blender/intern/cycles/subd/patch_table.cpp
Brecht Van Lommel fd25e883e2 Cycles: remove prefix from source code file names
Remove prefix of filenames that is the same as the folder name. This used
to help when #includes were using individual files, but now they are always
relative to the cycles root directory and so the prefixes are redundant.

For patches and branches, git merge and rebase should be able to detect the
renames and move over code to the right file.
2021-10-26 15:37:04 +02:00

296 lines
8.1 KiB
C++

/*
* Based on code from OpenSubdiv released under this license:
*
* Copyright 2014 DreamWorks Animation LLC.
*
* Licensed under the Apache License, Version 2.0 (the "Apache License")
* with the following modification; you may not use this file except in
* compliance with the Apache License and the following modification to it:
* Section 6. Trademarks. is deleted and replaced with:
*
* 6. Trademarks. This License does not grant permission to use the trade
* names, trademarks, service marks, or product names of the Licensor
* and its affiliates, except as required to comply with Section 4(c) of
* the License and to reproduce the content of the NOTICE file.
*
* You may obtain a copy of the Apache License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Apache License with the above modification is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the Apache License for the specific
* language governing permissions and limitations under the Apache License.
*/
#include "subd/patch_table.h"
#include "kernel/types.h"
#include "util/math.h"
#ifdef WITH_OPENSUBDIV
# include <opensubdiv/far/patchTable.h>
#endif
CCL_NAMESPACE_BEGIN
#ifdef WITH_OPENSUBDIV
using namespace OpenSubdiv;
/* functions for building patch maps */
struct PatchMapQuadNode {
/* sets all the children to point to the patch of index */
void set_child(int index)
{
for (int i = 0; i < 4; i++) {
children[i] = index | PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF;
}
}
/* sets the child in quadrant to point to the node or patch of the given index */
void set_child(unsigned char quadrant, int index, bool is_leaf = true)
{
assert(quadrant < 4);
children[quadrant] = index | PATCH_MAP_NODE_IS_SET | (is_leaf ? PATCH_MAP_NODE_IS_LEAF : 0);
}
uint children[4];
};
template<class T> static int resolve_quadrant(T &median, T &u, T &v)
{
int quadrant = -1;
if (u < median) {
if (v < median) {
quadrant = 0;
}
else {
quadrant = 1;
v -= median;
}
}
else {
if (v < median) {
quadrant = 3;
}
else {
quadrant = 2;
v -= median;
}
u -= median;
}
return quadrant;
}
static void build_patch_map(PackedPatchTable &table,
OpenSubdiv::Far::PatchTable *patch_table,
int offset)
{
int num_faces = 0;
for (int array = 0; array < table.num_arrays; array++) {
Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
for (int j = 0; j < patch_table->GetNumPatches(array); j++) {
num_faces = max(num_faces, (int)params[j].GetFaceId());
}
}
num_faces++;
vector<PatchMapQuadNode> quadtree;
quadtree.reserve(num_faces + table.num_patches);
quadtree.resize(num_faces);
/* adjust offsets to make indices relative to the table */
int handle_index = -(table.num_patches * PATCH_HANDLE_SIZE);
offset += table.total_size();
/* populate the quadtree from the FarPatchArrays sub-patches */
for (int array = 0; array < table.num_arrays; array++) {
Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
for (int i = 0; i < patch_table->GetNumPatches(array);
i++, handle_index += PATCH_HANDLE_SIZE) {
const Far::PatchParam &param = params[i];
unsigned short depth = param.GetDepth();
PatchMapQuadNode *node = &quadtree[params[i].GetFaceId()];
if (depth == (param.NonQuadRoot() ? 1 : 0)) {
/* special case : regular BSpline face w/ no sub-patches */
node->set_child(handle_index + offset);
continue;
}
int u = param.GetU();
int v = param.GetV();
int pdepth = param.NonQuadRoot() ? depth - 2 : depth - 1;
int half = 1 << pdepth;
for (int j = 0; j < depth; j++) {
int delta = half >> 1;
int quadrant = resolve_quadrant(half, u, v);
assert(quadrant >= 0);
half = delta;
if (j == pdepth) {
/* we have reached the depth of the sub-patch : add a leaf */
assert(!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET));
node->set_child(quadrant, handle_index + offset, true);
break;
}
else {
/* travel down the child node of the corresponding quadrant */
if (!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET)) {
/* create a new branch in the quadrant */
quadtree.push_back(PatchMapQuadNode());
int idx = (int)quadtree.size() - 1;
node->set_child(quadrant, idx * 4 + offset, false);
node = &quadtree[idx];
}
else {
/* travel down an existing branch */
uint idx = node->children[quadrant] & PATCH_MAP_NODE_INDEX_MASK;
node = &(quadtree[(idx - offset) / 4]);
}
}
}
}
}
/* copy into table */
assert(table.table.size() == table.total_size());
uint map_offset = table.total_size();
table.num_nodes = quadtree.size() * 4;
table.table.resize(table.total_size());
uint *data = &table.table[map_offset];
for (int i = 0; i < quadtree.size(); i++) {
for (int j = 0; j < 4; j++) {
assert(quadtree[i].children[j] & PATCH_MAP_NODE_IS_SET);
*(data++) = quadtree[i].children[j];
}
}
}
#endif
/* packed patch table functions */
size_t PackedPatchTable::total_size()
{
return num_arrays * PATCH_ARRAY_SIZE + num_indices +
num_patches * (PATCH_PARAM_SIZE + PATCH_HANDLE_SIZE) + num_nodes * PATCH_NODE_SIZE;
}
void PackedPatchTable::pack(Far::PatchTable *patch_table, int offset)
{
num_arrays = 0;
num_patches = 0;
num_indices = 0;
num_nodes = 0;
#ifdef WITH_OPENSUBDIV
num_arrays = patch_table->GetNumPatchArrays();
for (int i = 0; i < num_arrays; i++) {
int patches = patch_table->GetNumPatches(i);
int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
num_patches += patches;
num_indices += patches * num_control;
}
table.resize(total_size());
uint *data = table.data();
uint *array = data;
uint *index = array + num_arrays * PATCH_ARRAY_SIZE;
uint *param = index + num_indices;
uint *handle = param + num_patches * PATCH_PARAM_SIZE;
uint current_param = 0;
for (int i = 0; i < num_arrays; i++) {
*(array++) = patch_table->GetPatchArrayDescriptor(i).GetType();
*(array++) = patch_table->GetNumPatches(i);
*(array++) = (index - data) + offset;
*(array++) = (param - data) + offset;
Far::ConstIndexArray indices = patch_table->GetPatchArrayVertices(i);
for (int j = 0; j < indices.size(); j++) {
*(index++) = indices[j];
}
const Far::PatchParamTable &param_table = patch_table->GetPatchParamTable();
int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
int patches = patch_table->GetNumPatches(i);
for (int j = 0; j < patches; j++, current_param++) {
*(param++) = param_table[current_param].field0;
*(param++) = param_table[current_param].field1;
*(handle++) = (array - data) - PATCH_ARRAY_SIZE + offset;
*(handle++) = (param - data) - PATCH_PARAM_SIZE + offset;
*(handle++) = j * num_control;
}
}
build_patch_map(*this, patch_table, offset);
#else
(void)patch_table;
(void)offset;
#endif
}
void PackedPatchTable::copy_adjusting_offsets(uint *dest, int doffset)
{
uint *src = table.data();
/* arrays */
for (int i = 0; i < num_arrays; i++) {
*(dest++) = *(src++);
*(dest++) = *(src++);
*(dest++) = *(src++) + doffset;
*(dest++) = *(src++) + doffset;
}
/* indices */
for (int i = 0; i < num_indices; i++) {
*(dest++) = *(src++);
}
/* params */
for (int i = 0; i < num_patches; i++) {
*(dest++) = *(src++);
*(dest++) = *(src++);
}
/* handles */
for (int i = 0; i < num_patches; i++) {
*(dest++) = *(src++) + doffset;
*(dest++) = *(src++) + doffset;
*(dest++) = *(src++);
}
/* nodes */
for (int i = 0; i < num_nodes; i++) {
*(dest++) = *(src++) + doffset;
}
}
CCL_NAMESPACE_END