2016-07-17 02:57:06 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 18:39:14 +00:00
|
|
|
#include "subd/subd_patch_table.h"
|
|
|
|
#include "kernel/kernel_types.h"
|
2016-07-17 02:57:06 +00:00
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 18:39:14 +00:00
|
|
|
#include "util/util_math.h"
|
2016-07-17 02:57:06 +00:00
|
|
|
|
|
|
|
#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)
|
|
|
|
{
|
2016-10-24 10:26:12 +00:00
|
|
|
for(int i = 0; i < 4; i++) {
|
2016-07-17 02:57:06 +00:00
|
|
|
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());
|
2016-08-17 21:49:55 +00:00
|
|
|
uint* data = table.data();
|
2016-07-17 02:57:06 +00:00
|
|
|
|
|
|
|
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);
|
2016-08-07 21:20:22 +00:00
|
|
|
#else
|
|
|
|
(void)patch_table;
|
|
|
|
(void)offset;
|
2016-07-17 02:57:06 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void PackedPatchTable::copy_adjusting_offsets(uint* dest, int doffset)
|
|
|
|
{
|
2016-08-17 21:49:55 +00:00
|
|
|
uint* src = table.data();
|
2016-07-17 02:57:06 +00:00
|
|
|
|
|
|
|
/* 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
|
|
|
|
|