From c18cf5bff2e819365a28fd14f16e83da8a4068b5 Mon Sep 17 00:00:00 2001 From: manuelk Date: Thu, 6 Jun 2013 18:07:46 -0700 Subject: [PATCH] first pass at face-varying interpolation for CpuEvalLimit - still a couple of kinks to be worked out... --- examples/limitEval/main.cpp | 59 ++++--- opensubdiv/osd/cpuEvalLimitContext.cpp | 27 +++- opensubdiv/osd/cpuEvalLimitContext.h | 184 ++++++++++++++-------- opensubdiv/osd/cpuEvalLimitController.cpp | 41 ++++- opensubdiv/osd/cpuEvalLimitKernel.cpp | 12 +- opensubdiv/osd/cpuEvalLimitKernel.h | 12 +- regression/common/shape_utils.h | 81 ++++++++-- 7 files changed, 295 insertions(+), 121 deletions(-) diff --git a/examples/limitEval/main.cpp b/examples/limitEval/main.cpp index 04072c85..168574c3 100644 --- a/examples/limitEval/main.cpp +++ b/examples/limitEval/main.cpp @@ -139,7 +139,8 @@ std::vector g_coarseEdgeSharpness; std::vector g_coarseVertexSharpness; enum DrawMode { kUV=0, - kVARYING=1 }; + kVARYING=1, + kFACEVARYING=2 }; int g_running = 1, g_width = 1024, @@ -387,7 +388,9 @@ OsdCpuEvalLimitController g_evalCtrl; OsdVertexBufferDescriptor g_idesc( /*offset*/ 0, /*legnth*/ 3, /*stride*/ 3 ), g_odesc( /*offset*/ 0, /*legnth*/ 3, /*stride*/ 6 ), - g_vdesc( /*offset*/ 3, /*legnth*/ 3, /*stride*/ 6 ); + g_vdesc( /*offset*/ 3, /*legnth*/ 3, /*stride*/ 6 ), + g_fvidesc( /*offset*/ 0, /*legnth*/ 2, /*stride*/ 2 ), + g_fvodesc( /*offset*/ 3, /*legnth*/ 2, /*stride*/ 6 ); std::vector g_coords; @@ -444,9 +447,15 @@ updateGeom() { // The varying data ends-up interleaved in the same g_Q output buffer because // g_Q has a stride of 6 and g_vdesc sets the offset to 3, while g_odesc sets // the offset to 0 - if (g_drawMode==kVARYING) { - g_evalCtx->BindVaryingBuffers( g_idesc, g_varyingData, g_vdesc, g_Q ); - } + switch (g_drawMode) { + case kVARYING : g_evalCtx->BindVaryingBuffers( g_idesc, g_varyingData, g_vdesc, g_Q ); break; + + case kFACEVARYING : g_evalCtx->BindFaceVaryingBuffers( g_fvidesc, g_fvodesc, g_Q ); + + case kUV : + + default : g_evalCtx->UnbindVaryingBuffers(); break; + } #define USE_OPENMP #if defined(OPENSUBDIV_HAS_OPENMP) and defined(USE_OPENMP) @@ -457,16 +466,19 @@ updateGeom() { int n = g_evalCtrl.EvalLimitSample( g_coords[i], g_evalCtx, i ); if (n) { + // point colors + switch (g_drawMode) { + case kUV : { float * color = g_Q->BindCpuBuffer() + i * 6 + 3; + color[0] = g_coords[i].u; + color[1] = 0.0f; + color[2] = g_coords[i].v; } break; - // point colors - switch (g_drawMode) { - case kUV : { float * color = g_Q->BindCpuBuffer() + i * 6 + 3; - color[0] = g_coords[i].u; - color[1] = 0.0f; - color[2] = g_coords[i].v; } break; - case kVARYING : - default : break; - } + case kVARYING : break; + + case kFACEVARYING : { g_Q->BindCpuBuffer()[i*6 + 5] = 0.1f; + } break; + default : break; + } #if defined(OPENSUBDIV_HAS_OPENMP) and defined(USE_OPENMP) #pragma omp atomic #endif @@ -488,7 +500,7 @@ static void createOsdMesh( const std::string &shape, int level, Scheme scheme=kCatmark ) { // Create HBR mesh - OsdHbrMesh * hmesh = simpleHbr(shape.c_str(), scheme, g_orgPositions); + OsdHbrMesh * hmesh = simpleHbr(shape.c_str(), scheme, g_orgPositions, true); g_positions.resize(g_orgPositions.size(),0.0f); @@ -504,7 +516,7 @@ createOsdMesh( const std::string &shape, int level, Scheme scheme=kCatmark ) { OsdFarMeshFactory factory( hmesh, level, /*adaptive*/ true); delete g_fmesh; - g_fmesh = factory.Create(/*fvar*/ false); + g_fmesh = factory.Create(/*fvar*/ true); int nverts = g_fmesh->GetNumVertices(); @@ -514,17 +526,13 @@ createOsdMesh( const std::string &shape, int level, Scheme scheme=kCatmark ) { delete g_vertexData; g_vertexData = OsdCpuVertexBuffer::Create(3, nverts); - // Create v-buffer & populate w/ colors - delete g_varyingData; - + // Create primvar v-buffer & populate w/ colors or (u,v) data + delete g_varyingData; g_varyingData = 0; if (g_drawMode==kVARYING) { g_varyingData = OsdCpuVertexBuffer::Create(3, nverts); - g_varyingData->UpdateData( &g_varyingColors[0], 0, nverts); - } else { - g_varyingData = 0; } - + // Create a Compute context, used to "pose" the vertices delete g_computeCtx; g_computeCtx = OsdCpuComputeContext::Create(g_fmesh); @@ -535,7 +543,7 @@ createOsdMesh( const std::string &shape, int level, Scheme scheme=kCatmark ) { // Create eval context & data buffers delete g_evalCtx; - g_evalCtx = OsdCpuEvalLimitContext::Create(g_fmesh); + g_evalCtx = OsdCpuEvalLimitContext::Create(g_fmesh, /*requireFVarData*/ true); delete g_Q; g_Q = OsdCpuGLVertexBuffer::Create(6,nsamples); @@ -780,7 +788,7 @@ drawSamples() { glBindVertexArray(g_samplesVAO); glPointSize(1.0f); - glDrawArrays( GL_POINTS, 0, (int)g_coords.size() ); + glDrawArrays( GL_POINTS, 0, g_nsamplesFound); glPointSize(1.0f); glBindVertexArray(0); @@ -1044,6 +1052,7 @@ initHUD() g_hud.AddRadioButton(0, "(u,v)", true, 200, 10, callbackDisplayVaryingColors, kUV, 'k'); g_hud.AddRadioButton(0, "varying", false, 200, 30, callbackDisplayVaryingColors, kVARYING, 'k'); + g_hud.AddRadioButton(0, "face-varying", false, 200, 50, callbackDisplayVaryingColors, kFACEVARYING, 'k'); for (int i = 1; i < 11; ++i) { char level[16]; diff --git a/opensubdiv/osd/cpuEvalLimitContext.cpp b/opensubdiv/osd/cpuEvalLimitContext.cpp index 010fc011..bd5822bb 100644 --- a/opensubdiv/osd/cpuEvalLimitContext.cpp +++ b/opensubdiv/osd/cpuEvalLimitContext.cpp @@ -67,7 +67,7 @@ namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { OsdCpuEvalLimitContext * -OsdCpuEvalLimitContext::Create(FarMesh const * farmesh) { +OsdCpuEvalLimitContext::Create(FarMesh const * farmesh, bool requireFVarData) { assert(farmesh); @@ -75,7 +75,7 @@ OsdCpuEvalLimitContext::Create(FarMesh const * farmesh) { if (not farmesh->GetPatchTables()) return NULL; - return new OsdCpuEvalLimitContext(farmesh); + return new OsdCpuEvalLimitContext(farmesh, requireFVarData); } void @@ -85,7 +85,15 @@ OsdCpuEvalLimitContext::EvalData::Unbind() { _inQ=0; _outDesc.Reset(); - _outQ = _outdQu = _outdQv = 0; + _outQ = 0; +} + +void +OsdCpuEvalLimitContext::EvalVertexData::Unbind() { + + EvalData::Unbind(); + + _outdQu = _outdQv = 0; } void @@ -98,7 +106,12 @@ OsdCpuEvalLimitContext::UnbindVaryingBuffers() { _varyingData.Unbind(); } -OsdCpuEvalLimitContext::OsdCpuEvalLimitContext(FarMesh const * farmesh) : +void +OsdCpuEvalLimitContext::UnbindFaceVaryingBuffers() { + _faceVaryingData.Unbind(); +} + +OsdCpuEvalLimitContext::OsdCpuEvalLimitContext(FarMesh const * farmesh, bool requireFVarData) : OsdEvalLimitContext(farmesh) { FarPatchTables const * patchTables = farmesh->GetPatchTables(); @@ -137,6 +150,12 @@ OsdCpuEvalLimitContext::OsdCpuEvalLimitContext(FarMesh const * farmes } } + if (requireFVarData) { + _fvarwidth = farmesh->GetTotalFVarWidth(); + if (_fvarwidth>0) { + _fvarData = patchTables->GetFVarDataTable(); + } + } _patchMap = new FarPatchTables::PatchMap( *patchTables ); } diff --git a/opensubdiv/osd/cpuEvalLimitContext.h b/opensubdiv/osd/cpuEvalLimitContext.h index 45e029ce..c71eff00 100644 --- a/opensubdiv/osd/cpuEvalLimitContext.h +++ b/opensubdiv/osd/cpuEvalLimitContext.h @@ -71,11 +71,18 @@ namespace OPENSUBDIV_VERSION { class OsdCpuEvalLimitContext : public OsdEvalLimitContext { public: + /// \brief Factory /// Returns an EvalLimitContext from the given farmesh. /// Note : the farmesh is expected to be feature-adaptive and have ptex /// coordinates tables. - static OsdCpuEvalLimitContext * Create(FarMesh const * farmesh); + /// + /// @param farmesh a pointer to an initialized farmesh + /// + /// @param requireFVarData flag for generating face-varying data + /// + static OsdCpuEvalLimitContext * Create(FarMesh const * farmesh, + bool requireFVarData=false); /// Destructor virtual ~OsdCpuEvalLimitContext(); @@ -99,12 +106,14 @@ public: return _outQ + index * _outDesc.stride; } - float const * GetOutputDU(int index=0) const { - return _outdQu + index * _outDesc.stride; + template + void BindInputData( BUFFER * inQ ) { + _inQ = inQ ? inQ->BindCpuBuffer() : 0; } - float const * GetOutputDV(int index=0) const { - return _outdQv + index * _outDesc.stride; + template + void BindOutputData( BUFFER * outQ ) { + _outQ = outQ ? outQ->BindCpuBuffer() : 0; } bool IsBound() const { @@ -114,46 +123,47 @@ public: private: friend class OsdCpuEvalLimitContext; + EvalData() : _inQ(0), _outQ(0) { } + OsdVertexBufferDescriptor _inDesc; // input data float * _inQ; OsdVertexBufferDescriptor _outDesc; // output data - float * _outQ, - * _outdQu, // U derivative of output data - * _outdQv; // V derivative of output data - - /// Binds the data buffers. - /// - /// @param inDesc vertex / varying data descriptor shared by all input data buffers - /// - /// @param inQ input subidivision data - /// - /// @param outDesc vertex buffer data descriptor shared by all output data buffers - /// - /// @param outQ output vertex data - /// - /// @param outdQu optional output derivative along "u" of the vertex data - /// - /// @param outdQv optional output derivative along "v" of the vertex data - /// - template - void Bind( OsdVertexBufferDescriptor const & inDesc, INPUT_BUFFER *inQ, - OsdVertexBufferDescriptor const & outDesc, OUTPUT_BUFFER *outQ, - OUTPUT_BUFFER *outdQu=0, - OUTPUT_BUFFER *outdQv=0); - + float * _outQ; + /// Resets the descriptors & pointers void Unbind(); }; - EvalData const & GetVertexData() const { - return _vertexData; - } + /// Limit evaluation data descriptor with derivatives + class EvalVertexData : public EvalData { + public: + float const * GetOutputDU(int index=0) const { + return _outdQu + index * _outDesc.stride; + } - EvalData const & GetVaryingData() const { - return _varyingData; - } + float const * GetOutputDV(int index=0) const { + return _outdQv + index * _outDesc.stride; + } + template + void BindOutputDerivData( BUFFER * outdQu, BUFFER * outdQv ) { + _outdQu = outdQu ? outdQu->BindCpuBuffer() : 0; + _outdQv = outdQv ? outdQv->BindCpuBuffer() : 0; + } + + private: + friend class OsdCpuEvalLimitContext; + + EvalVertexData() : _outdQu(0), _outdQv(0) { } + + /// Resets the descriptors & pointers + void Unbind(); + + float * _outdQu, // U derivative of output data + * _outdQv; // V derivative of output data + }; + /// Binds the vertex-interpolated data buffers. /// @@ -174,12 +184,24 @@ public: OsdVertexBufferDescriptor const & outDesc, OUTPUT_BUFFER *outQ, OUTPUT_BUFFER *outdQu=0, OUTPUT_BUFFER *outdQv=0) { - _vertexData.Bind( inDesc, inQ, outDesc, outQ, outdQu, outdQv ); + _vertexData._inDesc = inDesc; + _vertexData.BindInputData( inQ ); + _vertexData._outDesc = outDesc; + _vertexData.BindOutputData( outQ ); + _vertexData.BindOutputDerivData( outdQu, outdQv ); } /// Unbind the vertex data buffers void UnbindVertexBuffers(); + /// Returns an Eval data descriptor of the vertex-interpolated data currently + /// bound to this EvalLimitContext. + EvalVertexData const & GetVertexData() const { + return _vertexData; + } + + + /// Binds the varying-interpolated data buffers. /// /// @param inDesc varying buffer data descriptor shared by all input data buffers @@ -190,19 +212,59 @@ public: /// /// @param outQ output varying data /// - /// @param outdQu optional output derivative along "u" of the varying data - /// - /// @param outdQv optional output derivative along "v" of the varying data - /// template void BindVaryingBuffers( OsdVertexBufferDescriptor const & inDesc, VARYING_BUFFER *inQ, OsdVertexBufferDescriptor const & outDesc, OUTPUT_BUFFER *outQ) { - _varyingData.Bind( inDesc, inQ, outDesc, outQ ); + _varyingData._inDesc = inDesc; + _varyingData.BindInputData( inQ ); + _varyingData._outDesc = outDesc; + _varyingData.BindOutputData( outQ ); } /// Unbind the varying data buffers void UnbindVaryingBuffers(); + /// Returns an Eval data descriptor of the varying-interpolated data currently + /// bound to this EvalLimitContext. + EvalData const & GetVaryingData() const { + return _varyingData; + } + + + + /// Binds the face-varying-interpolated data buffers. + /// + /// Note : currently we only support bilinear boundary interpolation rules + /// for face-varying data. Although Hbr supports 3 addition smooth rule sets, + /// the feature-adaptive patch interpolation code currently does not support + /// them, and neither does this EvalContext + /// + /// @param inDesc varying buffer data descriptor shared by all input data buffers + /// + /// @param inQ input varying data + /// + /// @param outDesc varying buffer data descriptor shared by all output data buffers + /// + /// @param outQ output varying data + /// + template + void BindFaceVaryingBuffers( OsdVertexBufferDescriptor const & inDesc, + OsdVertexBufferDescriptor const & outDesc, OUTPUT_BUFFER *outQ) { + _faceVaryingData._inDesc = inDesc; + _faceVaryingData._outDesc = outDesc; + _faceVaryingData.BindOutputData( outQ ); + } + + /// Unbind the varying data buffers + void UnbindFaceVaryingBuffers(); + + /// Returns an Eval data descriptor of the face-varying-interpolated data + /// currently bound to this EvalLimitContext. + EvalData const & GetFaceVaryingData() const { + return _faceVaryingData; + } + + /// Returns the vector of patch arrays const FarPatchTables::PatchArrayVector & GetPatchArrayVector() const { @@ -228,6 +290,16 @@ public: const unsigned int *GetQuadOffsetBuffer() const { return &_quadOffsetBuffer[0]; } + + /// Returns the face-varying data patch table + FarPatchTables::FVarDataTable const & GetFVarData() const { + return _fvarData; + } + + /// Returns the number of floats in a datum of the face-varying data table + int GetFVarWidth() const { + return _fvarwidth; + } /// Returns a map object that can connect a faceId to a list of children patches const FarPatchTables::PatchMap * GetPatchesMap() const { @@ -240,7 +312,7 @@ public: } protected: - explicit OsdCpuEvalLimitContext(FarMesh const * farmesh); + explicit OsdCpuEvalLimitContext(FarMesh const * farmesh, bool requireFVarData); private: @@ -252,32 +324,18 @@ private: FarPatchTables::VertexValenceTable _vertexValenceBuffer; // extra Gregory patch data buffers FarPatchTables::QuadOffsetTable _quadOffsetBuffer; + FarPatchTables::FVarDataTable _fvarData; + FarPatchTables::PatchMap * _patchMap; // map of the sub-patches given a face index - EvalData _vertexData, - _varyingData; + EvalVertexData _vertexData; // vertex-interpolated data descriptor + EvalData _varyingData, // varying-interpolated data descriptor + _faceVaryingData; // face-varying-interpolated data descriptor - int _maxValence; + int _maxValence, + _fvarwidth; }; -template void -OsdCpuEvalLimitContext::EvalData::Bind( OsdVertexBufferDescriptor const & inDesc, - INPUT_BUFFER *inQ, - OsdVertexBufferDescriptor const & outDesc, - OUTPUT_BUFFER *outQ, - OUTPUT_BUFFER *outdQu, - OUTPUT_BUFFER *outdQv) { - _inDesc = inDesc; - _inQ = inQ ? inQ->BindCpuBuffer() : 0; - - _outDesc = outDesc; - _outQ = outQ ? outQ->BindCpuBuffer() : 0 ; - _outdQu = outdQu ? outdQu->BindCpuBuffer() : 0 ; - _outdQv = outdQv ? outdQv->BindCpuBuffer() : 0 ; -} - - - } // end namespace OPENSUBDIV_VERSION using namespace OPENSUBDIV_VERSION; diff --git a/opensubdiv/osd/cpuEvalLimitController.cpp b/opensubdiv/osd/cpuEvalLimitController.cpp index 8a3f310f..900d5207 100644 --- a/opensubdiv/osd/cpuEvalLimitController.cpp +++ b/opensubdiv/osd/cpuEvalLimitController.cpp @@ -104,9 +104,8 @@ OsdCpuEvalLimitController::_EvalLimitSample( OpenSubdiv::OsdEvalCoords const & c unsigned int const * cvs = &context->GetControlVertices()[ parray.GetVertIndex() + handle.vertexOffset ]; - OsdCpuEvalLimitContext::EvalData const & vertexData = context->GetVertexData(), - & varyingData = context->GetVaryingData(); - + OsdCpuEvalLimitContext::EvalVertexData const & vertexData = context->GetVertexData(); + // Position lookup pointers at the indexed vertex float const * inQ = vertexData.GetInputData(); float * outQ = const_cast(vertexData.GetOutputData(index)); @@ -167,6 +166,8 @@ OsdCpuEvalLimitController::_EvalLimitSample( OpenSubdiv::OsdEvalCoords const & c default: assert(0); } + + OsdCpuEvalLimitContext::EvalData const & varyingData = context->GetVaryingData(); if (varyingData.IsBound()) { static int indices[5][4] = { {5, 6,10, 9}, // regular @@ -182,13 +183,37 @@ OsdCpuEvalLimitController::_EvalLimitSample( OpenSubdiv::OsdEvalCoords const & c cvs[indices[type][2]], cvs[indices[type][3]] }; - evalVarying( v, u, zeroRing, - varyingData.GetInputDesc(), - varyingData.GetInputData(), - varyingData.GetOutputDesc(), - const_cast(varyingData.GetOutputData(index)) ); + evalBilinear( v, u, zeroRing, + varyingData.GetInputDesc(), + varyingData.GetInputData(), + varyingData.GetOutputDesc(), + const_cast(varyingData.GetOutputData(index)) ); } + + // Note : currently we only support bilinear boundary interpolation rules + // for face-varying data. Although Hbr supports 3 addition smooth rule sets, + // the feature-adaptive patch interpolation code currently does not support + // them, and neither does this EvalContext + OsdCpuEvalLimitContext::EvalData const & faceVaryingData = context->GetFaceVaryingData(); + if (faceVaryingData.GetOutputData()) { + + FarPatchTables::FVarDataTable const & fvarData = context->GetFVarData(); + + if (not fvarData.empty()) { + + float const * fvar = &fvarData[ handle.serialIndex * 4 * context->GetFVarWidth() ]; + + static unsigned int zeroRing[4] = {0,1,2,3}; + + evalBilinear( v, u, zeroRing, + faceVaryingData.GetInputDesc(), + fvar, + faceVaryingData.GetOutputDesc(), + const_cast(faceVaryingData.GetOutputData(index)) ); + } + } + return 1; } diff --git a/opensubdiv/osd/cpuEvalLimitKernel.cpp b/opensubdiv/osd/cpuEvalLimitKernel.cpp index 9587e730..e1c7f7db 100644 --- a/opensubdiv/osd/cpuEvalLimitKernel.cpp +++ b/opensubdiv/osd/cpuEvalLimitKernel.cpp @@ -69,12 +69,12 @@ namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { void -evalVarying(float u, float v, - unsigned int const * vertexIndices, - OsdVertexBufferDescriptor const & inDesc, - float const * inQ, - OsdVertexBufferDescriptor const & outDesc, - float * outQ) { +evalBilinear(float u, float v, + unsigned int const * vertexIndices, + OsdVertexBufferDescriptor const & inDesc, + float const * inQ, + OsdVertexBufferDescriptor const & outDesc, + float * outQ) { assert( inDesc.length <= (outDesc.stride-outDesc.offset) ); diff --git a/opensubdiv/osd/cpuEvalLimitKernel.h b/opensubdiv/osd/cpuEvalLimitKernel.h index 07b08faf..29015ca0 100644 --- a/opensubdiv/osd/cpuEvalLimitKernel.h +++ b/opensubdiv/osd/cpuEvalLimitKernel.h @@ -65,12 +65,12 @@ namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { void -evalVarying(float u, float v, - unsigned int const * vertexIndices, - OsdVertexBufferDescriptor const & inDesc, - float const * inQ, - OsdVertexBufferDescriptor const & outDesc, - float * outQ); +evalBilinear(float u, float v, + unsigned int const * vertexIndices, + OsdVertexBufferDescriptor const & inDesc, + float const * inQ, + OsdVertexBufferDescriptor const & outDesc, + float * outQ); void evalBSpline(float u, float v, diff --git a/regression/common/shape_utils.h b/regression/common/shape_utils.h index 46691946..a9207231 100644 --- a/regression/common/shape_utils.h +++ b/regression/common/shape_utils.h @@ -703,7 +703,7 @@ hbrToObj( OpenSubdiv::HbrMesh * mesh ) { //------------------------------------------------------------------------------ template OpenSubdiv::HbrMesh * -createMesh( Scheme scheme=kCatmark) { +createMesh( Scheme scheme=kCatmark, int fvarwidth=0) { OpenSubdiv::HbrMesh * mesh = 0; @@ -711,10 +711,32 @@ createMesh( Scheme scheme=kCatmark) { static OpenSubdiv::HbrLoopSubdivision _loop; static OpenSubdiv::HbrCatmarkSubdivision _catmark; + static int indices[1] = { 0 }, + widths[1] = { 2 }; + + int const fvarcount = fvarwidth > 0 ? 1 : 0, + * fvarindices = fvarwidth > 0 ? indices : NULL, + * fvarwidths = fvarwidth > 0 ? widths : NULL; + + switch (scheme) { - case kBilinear : mesh = new OpenSubdiv::HbrMesh( &_bilinear ); break; - case kLoop : mesh = new OpenSubdiv::HbrMesh( &_loop ); break; - case kCatmark : mesh = new OpenSubdiv::HbrMesh( &_catmark ); break; + case kBilinear : mesh = new OpenSubdiv::HbrMesh( &_bilinear, + fvarcount, + fvarindices, + fvarwidths, + fvarwidth ); break; + + case kLoop : mesh = new OpenSubdiv::HbrMesh( &_loop, + fvarcount, + fvarindices, + fvarwidths, + fvarwidth ); break; + + case kCatmark : mesh = new OpenSubdiv::HbrMesh( &_catmark, + fvarcount, + fvarindices, + fvarwidths, + fvarwidth ); break; } return mesh; @@ -840,19 +862,55 @@ createTopology( shape const * sh, OpenSubdiv::HbrMesh * mesh, Scheme scheme) mesh->Finish(); } +//------------------------------------------------------------------------------ +template void +createFaceVaryingUV( shape const * sh, OpenSubdiv::HbrMesh * mesh) { + + if (sh->uvs.empty() or sh->faceuvs.empty()) + return; + + for (int i=0, idx=0; igetNfaces(); ++i ) { + + OpenSubdiv::HbrFace * f = mesh->GetFace(i); + + int nv = sh->nvertsPerFace[i]; + + OpenSubdiv::HbrHalfedge * e = f->GetFirstEdge(); + + for (int j=0; jGetNext()) { + + OpenSubdiv::HbrFVarData & fvt = e->GetOrgVertex()->GetFVarData(f); + + float const * fvdata = &sh->uvs[ sh->faceuvs[idx++] ]; + + if (not fvt.IsInitialized()) { + fvt.SetAllData(2, fvdata); + } else if (not fvt.CompareAll(2, fvdata)) { + OpenSubdiv::HbrFVarData & nfvt = e->GetOrgVertex()->NewFVarData(f); + nfvt.SetAllData(2, fvdata); + } + } + } +} + //------------------------------------------------------------------------------ template OpenSubdiv::HbrMesh * -simpleHbr(char const * shapestr, Scheme scheme, std::vector * verts=0) { +simpleHbr(char const * shapestr, Scheme scheme, std::vector * verts=0, bool fvar=false) { shape * sh = shape::parseShape( shapestr ); - OpenSubdiv::HbrMesh * mesh = createMesh(scheme); + int fvarwidth = fvar ? 2 : 0; + + OpenSubdiv::HbrMesh * mesh = createMesh(scheme, fvarwidth); createVertices(sh, mesh, verts); createTopology(sh, mesh, scheme); + + if (fvar) + createFaceVaryingUV(sh, mesh); - if(verts) + if (verts) copyVertexPositions(sh,mesh,*verts); delete sh; @@ -862,16 +920,21 @@ simpleHbr(char const * shapestr, Scheme scheme, std::vector * verts=0) { //------------------------------------------------------------------------------ template OpenSubdiv::HbrMesh * -simpleHbr(char const * shapestr, Scheme scheme, std::vector & verts) { +simpleHbr(char const * shapestr, Scheme scheme, std::vector & verts, bool fvar=false) { shape * sh = shape::parseShape( shapestr ); - OpenSubdiv::HbrMesh * mesh = createMesh(scheme); + int fvarwidth = fvar ? 2 : 0; + + OpenSubdiv::HbrMesh * mesh = createMesh(scheme, fvarwidth); createVertices(sh, mesh, verts); createTopology(sh, mesh, scheme); + if (fvar) + createFaceVaryingUV(sh, mesh); + copyVertexPositions(sh,mesh,verts); delete sh;