Blender V4.3
evaluator_impl.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2018 Blender Foundation
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later
4 *
5 * Author: Sergey Sharybin. */
6
8
9#include <cassert>
10#include <cstdio>
11
12#ifdef _MSC_VER
13# include <iso646.h>
14#endif
15
16#include <opensubdiv/far/patchMap.h>
17#include <opensubdiv/far/patchTable.h>
18#include <opensubdiv/far/patchTableFactory.h>
19#include <opensubdiv/osd/mesh.h>
20#include <opensubdiv/osd/types.h>
21#include <opensubdiv/version.h>
22
23#include "MEM_guardedalloc.h"
24
32
33using OpenSubdiv::Far::PatchTable;
34using OpenSubdiv::Far::PatchTableFactory;
35using OpenSubdiv::Far::StencilTable;
36using OpenSubdiv::Far::StencilTableFactory;
37using OpenSubdiv::Far::TopologyRefiner;
38using OpenSubdiv::Osd::PatchArray;
39using OpenSubdiv::Osd::PatchCoord;
40
41namespace blender::opensubdiv {
42
43// Array implementation which stores small data on stack (or, rather, in the class itself).
44template<typename T, int kNumMaxElementsOnStack> class StackOrHeapArray {
45 public:
50
51 explicit StackOrHeapArray(int size) : StackOrHeapArray()
52 {
53 resize(size);
54 }
55
57 {
58 delete[] heap_elements_;
59 }
60
61 int size() const
62 {
63 return num_elements_;
64 };
65
66 T *data()
67 {
69 }
70
71 void resize(int num_elements)
72 {
73 const int old_num_elements = num_elements_;
74 num_elements_ = num_elements;
75 // Early output if allcoation size did not change, or allocation size is smaller.
76 // We never re-allocate, sacrificing some memory over performance.
77 if (old_num_elements >= num_elements) {
78 return;
79 }
80 // Simple case: no previously allocated buffer, can simply do one allocation.
82 effective_elements_ = allocate(num_elements);
83 return;
84 }
85 // Make new allocation, and copy elements if needed.
86 T *old_buffer = effective_elements_;
87 effective_elements_ = allocate(num_elements);
88 if (old_buffer != effective_elements_) {
89 memcpy(
90 effective_elements_, old_buffer, sizeof(T) * std::min(old_num_elements, num_elements));
91 }
92 if (old_buffer != stack_elements_) {
93 delete[] old_buffer;
94 }
95 }
96
97 protected:
98 T *allocate(int num_elements)
99 {
100 if (num_elements < kNumMaxElementsOnStack) {
101 return stack_elements_;
102 }
103 heap_elements_ = new T[num_elements];
104 return heap_elements_;
105 }
106
107 // Number of elements in the buffer.
109
110 // Elements which are allocated on a stack (or, rather, in the same allocation as the buffer
111 // itself).
112 // Is used as long as buffer is smaller than kNumMaxElementsOnStack.
113 T stack_elements_[kNumMaxElementsOnStack];
114
115 // Heap storage for buffer larger than kNumMaxElementsOnStack.
118
119 // Depending on the current buffer size points to rither stack_elements_ or heap_elements_.
121};
122
123// 32 is a number of inner vertices along the patch size at subdivision level 6.
125
126static void convertPatchCoordsToArray(const OpenSubdiv_PatchCoord *patch_coords,
127 const int num_patch_coords,
128 const PatchMap *patch_map,
130{
131 array->resize(num_patch_coords);
132 for (int i = 0; i < num_patch_coords; ++i) {
133 const PatchTable::PatchHandle *handle = patch_map->FindPatch(
134 patch_coords[i].ptex_face, patch_coords[i].u, patch_coords[i].v);
135 (array->data())[i] = PatchCoord(*handle, patch_coords[i].u, patch_coords[i].v);
136 }
137}
138
140// Evaluator wrapper for anonymous API.
141
143 : patch_map_(patch_map), implementation_(implementation)
144{
145}
146
151
156
157void EvalOutputAPI::setCoarsePositions(const float *positions,
158 const int start_vertex_index,
159 const int num_vertices)
160{
161 // TODO(sergey): Add sanity check on indices.
162 implementation_->updateData(positions, start_vertex_index, num_vertices);
163}
164
165void EvalOutputAPI::setVaryingData(const float *varying_data,
166 const int start_vertex_index,
167 const int num_vertices)
168{
169 // TODO(sergey): Add sanity check on indices.
170 implementation_->updateVaryingData(varying_data, start_vertex_index, num_vertices);
171}
172
173void EvalOutputAPI::setVertexData(const float *vertex_data,
174 const int start_vertex_index,
175 const int num_vertices)
176{
177 // TODO(sergey): Add sanity check on indices.
178 implementation_->updateVertexData(vertex_data, start_vertex_index, num_vertices);
179}
180
181void EvalOutputAPI::setFaceVaryingData(const int face_varying_channel,
182 const float *face_varying_data,
183 const int start_vertex_index,
184 const int num_vertices)
185{
186 // TODO(sergey): Add sanity check on indices.
188 face_varying_channel, face_varying_data, start_vertex_index, num_vertices);
189}
190
192 const int start_offset,
193 const int stride,
194 const int start_vertex_index,
195 const int num_vertices)
196{
197 // TODO(sergey): Add sanity check on indices.
198 const unsigned char *current_buffer = (unsigned char *)buffer;
199 current_buffer += start_offset;
200 for (int i = 0; i < num_vertices; ++i) {
201 const int current_vertex_index = start_vertex_index + i;
203 reinterpret_cast<const float *>(current_buffer), current_vertex_index, 1);
204 current_buffer += stride;
205 }
206}
207
209 const int start_offset,
210 const int stride,
211 const int start_vertex_index,
212 const int num_vertices)
213{
214 // TODO(sergey): Add sanity check on indices.
215 const unsigned char *current_buffer = (unsigned char *)buffer;
216 current_buffer += start_offset;
217 for (int i = 0; i < num_vertices; ++i) {
218 const int current_vertex_index = start_vertex_index + i;
220 reinterpret_cast<const float *>(current_buffer), current_vertex_index, 1);
221 current_buffer += stride;
222 }
223}
224
225void EvalOutputAPI::setFaceVaryingDataFromBuffer(const int face_varying_channel,
226 const void *buffer,
227 const int start_offset,
228 const int stride,
229 const int start_vertex_index,
230 const int num_vertices)
231{
232 // TODO(sergey): Add sanity check on indices.
233 const unsigned char *current_buffer = (unsigned char *)buffer;
234 current_buffer += start_offset;
235 for (int i = 0; i < num_vertices; ++i) {
236 const int current_vertex_index = start_vertex_index + i;
237 implementation_->updateFaceVaryingData(face_varying_channel,
238 reinterpret_cast<const float *>(current_buffer),
239 current_vertex_index,
240 1);
241 current_buffer += stride;
242 }
243}
244
249
250void EvalOutputAPI::evaluateLimit(const int ptex_face_index,
251 float face_u,
252 float face_v,
253 float P[3],
254 float dPdu[3],
255 float dPdv[3])
256{
257 assert(face_u >= 0.0f);
258 assert(face_u <= 1.0f);
259 assert(face_v >= 0.0f);
260 assert(face_v <= 1.0f);
261 const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
262 PatchCoord patch_coord(*handle, face_u, face_v);
263 if (dPdu != NULL || dPdv != NULL) {
264 implementation_->evalPatchesWithDerivatives(&patch_coord, 1, P, dPdu, dPdv);
265 }
266 else {
267 implementation_->evalPatches(&patch_coord, 1, P);
268 }
269}
270
271void EvalOutputAPI::evaluateVarying(const int ptex_face_index,
272 float face_u,
273 float face_v,
274 float varying[3])
275{
276 assert(face_u >= 0.0f);
277 assert(face_u <= 1.0f);
278 assert(face_v >= 0.0f);
279 assert(face_v <= 1.0f);
280 const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
281 PatchCoord patch_coord(*handle, face_u, face_v);
282 implementation_->evalPatchesVarying(&patch_coord, 1, varying);
283}
284
285void EvalOutputAPI::evaluateVertexData(const int ptex_face_index,
286 float face_u,
287 float face_v,
288 float vertex_data[])
289{
290 assert(face_u >= 0.0f);
291 assert(face_u <= 1.0f);
292 assert(face_v >= 0.0f);
293 assert(face_v <= 1.0f);
294 const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
295 PatchCoord patch_coord(*handle, face_u, face_v);
296 implementation_->evalPatchesVertexData(&patch_coord, 1, vertex_data);
297}
298
299void EvalOutputAPI::evaluateFaceVarying(const int face_varying_channel,
300 const int ptex_face_index,
301 float face_u,
302 float face_v,
303 float face_varying[2])
304{
305 assert(face_u >= 0.0f);
306 assert(face_u <= 1.0f);
307 assert(face_v >= 0.0f);
308 assert(face_v <= 1.0f);
309 const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
310 PatchCoord patch_coord(*handle, face_u, face_v);
311 implementation_->evalPatchesFaceVarying(face_varying_channel, &patch_coord, 1, face_varying);
312}
313
315 const int num_patch_coords,
316 float *P,
317 float *dPdu,
318 float *dPdv)
319{
320 StackOrHeapPatchCoordArray patch_coords_array;
321 convertPatchCoordsToArray(patch_coords, num_patch_coords, patch_map_, &patch_coords_array);
322 if (dPdu != NULL || dPdv != NULL) {
324 patch_coords_array.data(), num_patch_coords, P, dPdu, dPdv);
325 }
326 else {
327 implementation_->evalPatches(patch_coords_array.data(), num_patch_coords, P);
328 }
329}
330
332 OpenSubdiv_Buffer *patch_map_quadtree,
333 int *min_patch_face,
334 int *max_patch_face,
335 int *max_depth,
336 int *patches_are_triangular)
337{
338 *min_patch_face = patch_map_->getMinPatchFace();
339 *max_patch_face = patch_map_->getMaxPatchFace();
340 *max_depth = patch_map_->getMaxDepth();
341 *patches_are_triangular = patch_map_->getPatchesAreTriangular();
342
343 const std::vector<PatchTable::PatchHandle> &handles = patch_map_->getHandles();
344 PatchTable::PatchHandle *buffer_handles = static_cast<PatchTable::PatchHandle *>(
345 patch_map_handles->alloc(patch_map_handles, handles.size()));
346 memcpy(buffer_handles, &handles[0], sizeof(PatchTable::PatchHandle) * handles.size());
347
348 const std::vector<PatchMap::QuadNode> &quadtree = patch_map_->nodes();
349 PatchMap::QuadNode *buffer_nodes = static_cast<PatchMap::QuadNode *>(
350 patch_map_quadtree->alloc(patch_map_quadtree, quadtree.size()));
351 memcpy(buffer_nodes, &quadtree[0], sizeof(PatchMap::QuadNode) * quadtree.size());
352}
353
355{
356 implementation_->fillPatchArraysBuffer(patch_arrays_buffer);
357}
358
360{
361 implementation_->wrapPatchIndexBuffer(patch_index_buffer);
362}
363
365{
366 implementation_->wrapPatchParamBuffer(patch_param_buffer);
367}
368
373
378
379void EvalOutputAPI::fillFVarPatchArraysBuffer(const int face_varying_channel,
380 OpenSubdiv_Buffer *patch_arrays_buffer)
381{
382 implementation_->fillFVarPatchArraysBuffer(face_varying_channel, patch_arrays_buffer);
383}
384
385void EvalOutputAPI::wrapFVarPatchIndexBuffer(const int face_varying_channel,
386 OpenSubdiv_Buffer *patch_index_buffer)
387{
388 implementation_->wrapFVarPatchIndexBuffer(face_varying_channel, patch_index_buffer);
389}
390
391void EvalOutputAPI::wrapFVarPatchParamBuffer(const int face_varying_channel,
392 OpenSubdiv_Buffer *patch_param_buffer)
393{
394 implementation_->wrapFVarPatchParamBuffer(face_varying_channel, patch_param_buffer);
395}
396
397void EvalOutputAPI::wrapFVarSrcBuffer(const int face_varying_channel,
398 OpenSubdiv_Buffer *src_buffer)
399{
400 implementation_->wrapFVarSrcBuffer(face_varying_channel, src_buffer);
401}
402
404{
406}
407
408} // namespace blender::opensubdiv
409
411 : eval_output(NULL), patch_map(NULL), patch_table(NULL)
412{
413}
414
421
424 eOpenSubdivEvaluator evaluator_type,
425 OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr)
426{
427 TopologyRefiner *refiner = topology_refiner->topology_refiner;
428 if (refiner == NULL) {
429 // Happens on bad topology.
430 return NULL;
431 }
432 // TODO(sergey): Base this on actual topology.
433 const bool has_varying_data = false;
434 const int num_face_varying_channels = refiner->GetNumFVarChannels();
435 const bool has_face_varying_data = (num_face_varying_channels != 0);
436 const int level = topology_refiner->settings.level;
437 const bool is_adaptive = topology_refiner->settings.is_adaptive;
438 // Common settings for stencils and patches.
439 const bool stencil_generate_intermediate_levels = is_adaptive;
440 const bool stencil_generate_offsets = true;
441 const bool use_inf_sharp_patch = true;
442 // Refine the topology with given settings.
443 // TODO(sergey): What if topology is already refined?
444 if (is_adaptive) {
445 TopologyRefiner::AdaptiveOptions options(level);
446 options.considerFVarChannels = has_face_varying_data;
447 options.useInfSharpPatch = use_inf_sharp_patch;
448 refiner->RefineAdaptive(options);
449 }
450 else {
451 TopologyRefiner::UniformOptions options(level);
452 refiner->RefineUniform(options);
453 }
454 // Generate stencil table to update the bi-cubic patches control vertices
455 // after they have been re-posed (both for vertex & varying interpolation).
456 //
457 // Vertex stencils.
458 StencilTableFactory::Options vertex_stencil_options;
459 vertex_stencil_options.generateOffsets = stencil_generate_offsets;
460 vertex_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels;
461 const StencilTable *vertex_stencils = StencilTableFactory::Create(*refiner,
462 vertex_stencil_options);
463 // Varying stencils.
464 //
465 // TODO(sergey): Seems currently varying stencils are always required in
466 // OpenSubdiv itself.
467 const StencilTable *varying_stencils = NULL;
468 if (has_varying_data) {
469 StencilTableFactory::Options varying_stencil_options;
470 varying_stencil_options.generateOffsets = stencil_generate_offsets;
471 varying_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels;
472 varying_stencil_options.interpolationMode = StencilTableFactory::INTERPOLATE_VARYING;
473 varying_stencils = StencilTableFactory::Create(*refiner, varying_stencil_options);
474 }
475 // Face warying stencil.
476 std::vector<const StencilTable *> all_face_varying_stencils;
477 all_face_varying_stencils.reserve(num_face_varying_channels);
478 for (int face_varying_channel = 0; face_varying_channel < num_face_varying_channels;
479 ++face_varying_channel)
480 {
481 StencilTableFactory::Options face_varying_stencil_options;
482 face_varying_stencil_options.generateOffsets = stencil_generate_offsets;
483 face_varying_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels;
484 face_varying_stencil_options.interpolationMode = StencilTableFactory::INTERPOLATE_FACE_VARYING;
485 face_varying_stencil_options.fvarChannel = face_varying_channel;
486 all_face_varying_stencils.push_back(
487 StencilTableFactory::Create(*refiner, face_varying_stencil_options));
488 }
489 // Generate bi-cubic patch table for the limit surface.
490 PatchTableFactory::Options patch_options(level);
491 patch_options.SetEndCapType(PatchTableFactory::Options::ENDCAP_GREGORY_BASIS);
492 patch_options.useInfSharpPatch = use_inf_sharp_patch;
493 patch_options.generateFVarTables = has_face_varying_data;
494 patch_options.generateFVarLegacyLinearPatches = false;
495 const PatchTable *patch_table = PatchTableFactory::Create(*refiner, patch_options);
496 // Append local points stencils.
497 // Point stencils.
498 const StencilTable *local_point_stencil_table = patch_table->GetLocalPointStencilTable();
499 if (local_point_stencil_table != NULL) {
500 const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTable(
501 *refiner, vertex_stencils, local_point_stencil_table);
502 delete vertex_stencils;
503 vertex_stencils = table;
504 }
505 // Varying stencils.
506 if (has_varying_data) {
507 const StencilTable *local_point_varying_stencil_table =
508 patch_table->GetLocalPointVaryingStencilTable();
509 if (local_point_varying_stencil_table != NULL) {
510 const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTable(
511 *refiner, varying_stencils, local_point_varying_stencil_table);
512 delete varying_stencils;
513 varying_stencils = table;
514 }
515 }
516 for (int face_varying_channel = 0; face_varying_channel < num_face_varying_channels;
517 ++face_varying_channel)
518 {
519 const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTableFaceVarying(
520 *refiner,
521 all_face_varying_stencils[face_varying_channel],
522 patch_table->GetLocalPointFaceVaryingStencilTable(face_varying_channel),
523 face_varying_channel);
524 if (table != NULL) {
525 delete all_face_varying_stencils[face_varying_channel];
526 all_face_varying_stencils[face_varying_channel] = table;
527 }
528 }
529 // Create OpenSubdiv's CPU side evaluator.
531
532 const bool use_gpu_evaluator = evaluator_type == OPENSUBDIV_EVALUATOR_GPU;
533 if (use_gpu_evaluator) {
535 if (evaluator_cache_descr) {
536 evaluator_cache = static_cast<blender::opensubdiv::GpuEvalOutput::EvaluatorCache *>(
537 evaluator_cache_descr->eval_cache);
538 }
539
540 eval_output = new blender::opensubdiv::GpuEvalOutput(vertex_stencils,
541 varying_stencils,
542 all_face_varying_stencils,
543 2,
544 patch_table,
545 evaluator_cache);
546 }
547 else {
548 eval_output = new blender::opensubdiv::CpuEvalOutput(
549 vertex_stencils, varying_stencils, all_face_varying_stencils, 2, patch_table);
550 }
551
553 // Wrap everything we need into an object which we control from our side.
554 OpenSubdiv_EvaluatorImpl *evaluator_descr;
555 evaluator_descr = new OpenSubdiv_EvaluatorImpl();
556
557 evaluator_descr->eval_output = new blender::opensubdiv::EvalOutputAPI(eval_output, patch_map);
558 evaluator_descr->patch_map = patch_map;
559 evaluator_descr->patch_table = patch_table;
560 // TODO(sergey): Look into whether we've got duplicated stencils arrays.
561 delete vertex_stencils;
562 delete varying_stencils;
563 for (const StencilTable *table : all_face_varying_stencils) {
564 delete table;
565 }
566 return evaluator_descr;
567}
568
570{
571 delete evaluator;
572}
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v
T * resize(size_t newsize)
virtual void wrapPatchIndexBuffer(OpenSubdiv_Buffer *)
Definition eval_output.h:82
virtual void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *P)=0
virtual void fillFVarPatchArraysBuffer(const int, OpenSubdiv_Buffer *)
Definition eval_output.h:90
virtual void evalPatchesVertexData(const PatchCoord *patch_coord, const int num_patch_coords, float *vertex_data)=0
virtual void evalPatchesWithDerivatives(const PatchCoord *patch_coord, const int num_patch_coords, float *P, float *dPdu, float *dPdv)=0
virtual void wrapPatchParamBuffer(OpenSubdiv_Buffer *)
Definition eval_output.h:84
virtual void wrapFVarPatchParamBuffer(const int, OpenSubdiv_Buffer *)
virtual void wrapFVarPatchIndexBuffer(const int, OpenSubdiv_Buffer *)
Definition eval_output.h:95
virtual void wrapSrcVertexDataBuffer(OpenSubdiv_Buffer *)
Definition eval_output.h:88
virtual void updateVertexData(const float *src, int start_vertex, int num_vertices)=0
virtual void fillPatchArraysBuffer(OpenSubdiv_Buffer *)
Definition eval_output.h:80
virtual void updateData(const float *src, int start_vertex, int num_vertices)=0
virtual void evalPatchesVarying(const PatchCoord *patch_coord, const int num_patch_coords, float *varying)=0
virtual void updateSettings(const OpenSubdiv_EvaluatorSettings *settings)=0
virtual void updateFaceVaryingData(const int face_varying_channel, const float *src, int start_vertex, int num_vertices)=0
virtual void evalPatchesFaceVarying(const int face_varying_channel, const PatchCoord *patch_coord, const int num_patch_coords, float face_varying[2])=0
virtual void wrapFVarSrcBuffer(const int, OpenSubdiv_Buffer *)
virtual void wrapSrcBuffer(OpenSubdiv_Buffer *)
Definition eval_output.h:86
virtual void updateVaryingData(const float *src, int start_vertex, int num_vertices)=0
void setVaryingData(const float *varying_data, const int start_vertex_index, const int num_vertices)
void wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer)
void wrapFVarSrcBuffer(const int face_varying_channel, OpenSubdiv_Buffer *src_buffer)
void evaluatePatchesLimit(const OpenSubdiv_PatchCoord *patch_coords, const int num_patch_coords, float *P, float *dPdu, float *dPdv)
void wrapPatchIndexBuffer(OpenSubdiv_Buffer *patch_index_buffer)
void fillPatchArraysBuffer(OpenSubdiv_Buffer *patch_arrays_buffer)
void setSettings(const OpenSubdiv_EvaluatorSettings *settings)
void wrapPatchParamBuffer(OpenSubdiv_Buffer *patch_param_buffer)
void evaluateLimit(const int ptex_face_index, float face_u, float face_v, float P[3], float dPdu[3], float dPdv[3])
void evaluateFaceVarying(const int face_varying_channel, const int ptes_face_index, float face_u, float face_v, float face_varying[2])
void setFaceVaryingData(const int face_varying_channel, const float *varying_data, const int start_vertex_index, const int num_vertices)
void getPatchMap(OpenSubdiv_Buffer *patch_map_handles, OpenSubdiv_Buffer *patch_map_quadtree, int *min_patch_face, int *max_patch_face, int *max_depth, int *patches_are_triangular)
void wrapFVarPatchIndexBuffer(const int face_varying_channel, OpenSubdiv_Buffer *patch_index_buffer)
void fillFVarPatchArraysBuffer(const int face_varying_channel, OpenSubdiv_Buffer *patch_arrays_buffer)
void wrapSrcVertexDataBuffer(OpenSubdiv_Buffer *src_buffer)
void evaluateVertexData(const int ptes_face_index, float face_u, float face_v, float data[])
void setCoarsePositionsFromBuffer(const void *buffer, const int start_offset, const int stride, const int start_vertex_index, const int num_vertices)
void wrapFVarPatchParamBuffer(const int face_varying_channel, OpenSubdiv_Buffer *patch_param_buffer)
void setVaryingDataFromBuffer(const void *buffer, const int start_offset, const int stride, const int start_vertex_index, const int num_vertices)
EvalOutputAPI(EvalOutput *implementation, PatchMap *patch_map)
void evaluateVarying(const int ptes_face_index, float face_u, float face_v, float varying[3])
void setFaceVaryingDataFromBuffer(const int face_varying_channel, const void *buffer, const int start_offset, const int stride, const int start_vertex_index, const int num_vertices)
void setVertexData(const float *data, const int start_vertex_index, const int num_vertices)
void setCoarsePositions(const float *positions, const int start_vertex_index, const int num_vertices)
An quadtree-based map connecting coarse faces to their sub-patches.
Definition patch_map.h:25
const std::vector< QuadNode > & nodes()
Definition patch_map.h:98
bool getPatchesAreTriangular() const
Definition patch_map.h:88
const std::vector< Handle > & getHandles()
Definition patch_map.h:93
Handle const * FindPatch(int patchFaceId, double u, double v) const
Returns a handle to the sub-patch of the face at the given (u,v). Note that the patch face ID corresp...
Definition patch_map.h:203
T stack_elements_[kNumMaxElementsOnStack]
OpenSubdiv::Far::TopologyRefiner * topology_refiner
OpenSubdiv_TopologyRefinerSettings settings
CCL_NAMESPACE_BEGIN struct Options options
#define NULL
void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorImpl *evaluator)
OpenSubdiv_EvaluatorImpl * openSubdiv_createEvaluatorInternal(blender::opensubdiv::TopologyRefinerImpl *topology_refiner, eOpenSubdivEvaluator evaluator_type, OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr)
StackOrHeapArray< PatchCoord, 32 *32 > StackOrHeapPatchCoordArray
static void convertPatchCoordsToArray(const OpenSubdiv_PatchCoord *patch_coords, const int num_patch_coords, const PatchMap *patch_map, StackOrHeapPatchCoordArray *array)
eOpenSubdivEvaluator
@ OPENSUBDIV_EVALUATOR_GPU
void *(* alloc)(const OpenSubdiv_Buffer *buffer, const unsigned int size)
const blender::opensubdiv::PatchMap * patch_map
blender::opensubdiv::EvalOutputAPI * eval_output
const OpenSubdiv::Far::PatchTable * patch_table