diff --git a/examples/glutViewer/viewer.cpp b/examples/glutViewer/viewer.cpp index bcaf965e..3600bc6e 100644 --- a/examples/glutViewer/viewer.cpp +++ b/examples/glutViewer/viewer.cpp @@ -64,6 +64,10 @@ #endif #include + +#include +#include + #include #include #include diff --git a/examples/glutViewer/viewer_compat.cpp b/examples/glutViewer/viewer_compat.cpp index 2547f650..cd311292 100644 --- a/examples/glutViewer/viewer_compat.cpp +++ b/examples/glutViewer/viewer_compat.cpp @@ -65,6 +65,10 @@ #endif #include + +#include +#include + #include #include #include diff --git a/examples/mayaPtexViewer_siggraph2012/OpenSubdivPtexShader.cpp b/examples/mayaPtexViewer_siggraph2012/OpenSubdivPtexShader.cpp index 417ea1c7..18661591 100644 --- a/examples/mayaPtexViewer_siggraph2012/OpenSubdivPtexShader.cpp +++ b/examples/mayaPtexViewer_siggraph2012/OpenSubdivPtexShader.cpp @@ -87,6 +87,12 @@ #include #include + +#include +#include +#include +#include + #include #include #include diff --git a/examples/mayaPtexViewer_siggraph2012/hbrUtil.cpp b/examples/mayaPtexViewer_siggraph2012/hbrUtil.cpp index 2979c069..e7e44eac 100644 --- a/examples/mayaPtexViewer_siggraph2012/hbrUtil.cpp +++ b/examples/mayaPtexViewer_siggraph2012/hbrUtil.cpp @@ -55,12 +55,14 @@ // a particular purpose and non-infringement. // #include "hbrUtil.h" -#include + #include #include #include #include +#include + #define OSD_ERROR printf // XXXX OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices, diff --git a/examples/mayaPtexViewer_siggraph2012/hbrUtil.h b/examples/mayaPtexViewer_siggraph2012/hbrUtil.h index 0e49ea5b..69202c85 100644 --- a/examples/mayaPtexViewer_siggraph2012/hbrUtil.h +++ b/examples/mayaPtexViewer_siggraph2012/hbrUtil.h @@ -59,6 +59,9 @@ #include #include + +#include + #include extern "C" OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices, diff --git a/examples/mayaViewer/OpenSubdivShaderOverride.cpp b/examples/mayaViewer/OpenSubdivShaderOverride.cpp index 2997f128..ed1aec32 100644 --- a/examples/mayaViewer/OpenSubdivShaderOverride.cpp +++ b/examples/mayaViewer/OpenSubdivShaderOverride.cpp @@ -87,6 +87,12 @@ #include #include + +#include +#include +#include +#include + #include #include #include diff --git a/examples/mayaViewer/hbrUtil.cpp b/examples/mayaViewer/hbrUtil.cpp index a200dfcc..ca9574e3 100644 --- a/examples/mayaViewer/hbrUtil.cpp +++ b/examples/mayaViewer/hbrUtil.cpp @@ -55,12 +55,14 @@ // a particular purpose and non-infringement. // #include "hbrUtil.h" -#include + #include #include #include #include +#include + #define OSD_ERROR printf // XXXX OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices, diff --git a/examples/mayaViewer/hbrUtil.h b/examples/mayaViewer/hbrUtil.h index 0e49ea5b..69202c85 100644 --- a/examples/mayaViewer/hbrUtil.h +++ b/examples/mayaViewer/hbrUtil.h @@ -59,6 +59,9 @@ #include #include + +#include + #include extern "C" OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices, diff --git a/examples/ptexViewer/viewer.cpp b/examples/ptexViewer/viewer.cpp index b17e4506..8d127630 100644 --- a/examples/ptexViewer/viewer.cpp +++ b/examples/ptexViewer/viewer.cpp @@ -63,6 +63,12 @@ #endif #include + +#include +#include +#include +#include + #include #include #include diff --git a/opensubdiv/far/CMakeLists.txt b/opensubdiv/far/CMakeLists.txt index e4a9017a..59f948a5 100644 --- a/opensubdiv/far/CMakeLists.txt +++ b/opensubdiv/far/CMakeLists.txt @@ -57,14 +57,18 @@ set(PUBLIC_HEADER_FILES bilinearSubdivisionTables.h + bilinearSubdivisionTablesFactory.h catmarkSubdivisionTables.h + catmarkSubdivisionTablesFactory.h dispatcher.h loopSubdivisionTables.h + loopSubdivisionTablesFactory.h meshFactory.h mesh.h subdivisionTables.h table.h vertexEditTables.h + vertexEditTablesFactory.h ) install( FILES ${PUBLIC_HEADER_FILES} diff --git a/opensubdiv/far/bilinearSubdivisionTables.h b/opensubdiv/far/bilinearSubdivisionTables.h index 70c3862f..6f411098 100644 --- a/opensubdiv/far/bilinearSubdivisionTables.h +++ b/opensubdiv/far/bilinearSubdivisionTables.h @@ -57,13 +57,8 @@ #ifndef FAR_BILINEAR_SUBDIVISION_TABLES_H #define FAR_BILINEAR_SUBDIVISION_TABLES_H -#include "assert.h" - +#include #include -#include - -#include "../hbr/mesh.h" -#include "../hbr/bilinear.h" #include "../version.h" @@ -77,7 +72,7 @@ namespace OPENSUBDIV_VERSION { // structure. The advantage of this representation is its ability to be executed // in a massively parallel environment without data dependencies. // -template class FarBilinearSubdivisionTables : public FarSubdivisionTables { +template class FarBilinearSubdivisionTables : public FarSubdivisionTables { public: @@ -97,12 +92,10 @@ public: virtual int GetNumTables() const { return 7; } private: + template friend struct FarBilinearSubdivisionTablesFactory; + friend class FarDispatcher; - friend class FarMeshFactory; - friend class FarDispatcher; - - // Constructor : build level table at depth 'level' - FarBilinearSubdivisionTables( FarMeshFactory const & factory, FarMesh * mesh, int level ); + FarBilinearSubdivisionTables( FarMesh * mesh, int maxlevel ); // Compute-kernel applied to vertices resulting from the refinement of a face. void computeFacePoints(int offset, int level, int start, int end, void * clientdata) const; @@ -113,130 +106,34 @@ private: // Compute-kernel applied to vertices resulting from the refinement of a vertex void computeVertexPoints(int offset, int level, int start, int end, void * clientdata) const; - private: FarTable _F_ITa; FarTable _F_IT; }; -template int -FarBilinearSubdivisionTables::GetMemoryUsed() const { - return FarSubdivisionTables::GetMemoryUsed()+ +template +FarBilinearSubdivisionTables::FarBilinearSubdivisionTables( FarMesh * mesh, int maxlevel ) : + FarSubdivisionTables(mesh, maxlevel), + _F_ITa(maxlevel+1), + _F_IT(maxlevel+1) +{ } + +template int +FarBilinearSubdivisionTables::GetMemoryUsed() const { + return FarSubdivisionTables::GetMemoryUsed()+ _F_ITa.GetMemoryUsed()+ _F_IT.GetMemoryUsed(); } -// Constructor - generates indexing tables matching the bilinear subdivision scheme. -// -// tables codices detail : -// -// codices detail : -// -// _F_ITa[0] : offset into _F_IT array of vertices making up the face -// _F_ITa[1] : valence of the face -// -// _E_ITa[0] : index of the org / dest vertices of the parent edge -// _E_ITa[1] : -// -// _V_ITa[0] : index of the parent vertex -// -template -FarBilinearSubdivisionTables::FarBilinearSubdivisionTables( FarMeshFactory const & factory, FarMesh * mesh, int maxlevel ) : - FarSubdivisionTables(mesh, maxlevel), - _F_ITa(maxlevel+1), - _F_IT(maxlevel+1) -{ - std::vector const & remap = factory._remapTable; - - // Allocate memory for the indexing tables - _F_ITa.Resize(factory.GetNumFaceVerticesTotal(maxlevel)*2); - _F_IT.Resize(factory.GetNumFacesTotal(maxlevel) - factory.GetNumFacesTotal(0)); - - this->_E_IT.Resize(factory.GetNumEdgeVerticesTotal(maxlevel)*2); - - this->_V_ITa.Resize(factory.GetNumVertexVerticesTotal(maxlevel)); - - for (int level=1; level<=maxlevel; ++level) { - - // pointer to the first vertex corresponding to this level - this->_vertsOffsets[level] = factory._vertVertIdx[level-1] + - (int)factory._vertVertsList[level-1].size(); - - typename FarSubdivisionTables::VertexKernelBatch * batch = & (this->_batches[level-1]); - - // Face vertices - // "For each vertex, gather all the vertices from the parent face." - int offset = 0; - int * F_ITa = this->_F_ITa[level-1]; - unsigned int * F_IT = this->_F_IT[level-1]; - batch->kernelF = (int)factory._faceVertsList[level].size(); - for (int i=0; i < batch->kernelF; ++i) { - - HbrVertex * v = factory._faceVertsList[level][i]; - assert(v); - - HbrFace * f=v->GetParentFace(); - assert(f); - - int valence = f->GetNumVertices(); - - F_ITa[2*i+0] = offset; - F_ITa[2*i+1] = valence; - - for (int j=0; jGetVertex(j)->GetID()]; - } - _F_ITa.SetMarker(level, &F_ITa[2*batch->kernelF]); - _F_IT.SetMarker(level, &F_IT[offset]); - - // Edge vertices - - // "Average the end-points of the parent edge" - int * E_IT = this->_E_IT[level-1]; - batch->kernelE = (int)factory._edgeVertsList[level].size(); - for (int i=0; i < batch->kernelE; ++i) { - - HbrVertex * v = factory._edgeVertsList[level][i]; - assert(v); - HbrHalfedge * e = v->GetParentEdge(); - assert(e); - - // get the indices 2 vertices from the parent edge - E_IT[2*i+0] = remap[e->GetOrgVertex()->GetID()]; - E_IT[2*i+1] = remap[e->GetDestVertex()->GetID()]; - - } - this->_E_IT.SetMarker(level, &E_IT[2*batch->kernelE]); - - // Vertex vertices - - // "Pass down the parent vertex" - offset = 0; - int * V_ITa = this->_V_ITa[level-1]; - batch->kernelB.first = 0; - batch->kernelB.second = (int)factory._vertVertsList[level].size(); - for (int i=0; i < batch->kernelB.second; ++i) { - - HbrVertex * v = factory._vertVertsList[level][i], - * pv = v->GetParentVertex(); - assert(v and pv); - - V_ITa[i] = remap[pv->GetID()]; - - } - this->_V_ITa.SetMarker(level, &V_ITa[batch->kernelB.second]); - } -} - -template void -FarBilinearSubdivisionTables::Apply( int level, void * clientdata ) const { +template void +FarBilinearSubdivisionTables::Apply( int level, void * clientdata ) const { assert(this->_mesh and level>0); - typename FarSubdivisionTables::VertexKernelBatch const * batch = & (this->_batches[level-1]); + typename FarSubdivisionTables::VertexKernelBatch const * batch = & (this->_batches[level-1]); - FarDispatcher const * dispatch = this->_mesh->GetDispatcher(); + FarDispatcher const * dispatch = this->_mesh->GetDispatcher(); assert(dispatch); int offset = this->GetFirstVertexOffset(level); @@ -256,8 +153,8 @@ FarBilinearSubdivisionTables::Apply( int level, void * clientdata ) const { // Face-vertices compute Kernel - completely re-entrant // -template void -FarBilinearSubdivisionTables::computeFacePoints( int offset, int level, int start, int end, void * clientdata ) const { +template void +FarBilinearSubdivisionTables::computeFacePoints( int offset, int level, int start, int end, void * clientdata ) const { assert(this->_mesh); @@ -286,8 +183,8 @@ FarBilinearSubdivisionTables::computeFacePoints( int offset, int level, int // Edge-vertices compute Kernel - completely re-entrant // -template void -FarBilinearSubdivisionTables::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const { +template void +FarBilinearSubdivisionTables::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const { assert(this->_mesh); @@ -315,8 +212,8 @@ FarBilinearSubdivisionTables::computeEdgePoints( int offset, int level, in // Vertex-vertices compute Kernel - completely re-entrant // -template void -FarBilinearSubdivisionTables::computeVertexPoints( int offset, int level, int start, int end, void * clientdata ) const { +template void +FarBilinearSubdivisionTables::computeVertexPoints( int offset, int level, int start, int end, void * clientdata ) const { assert(this->_mesh); diff --git a/opensubdiv/far/bilinearSubdivisionTablesFactory.h b/opensubdiv/far/bilinearSubdivisionTablesFactory.h new file mode 100644 index 00000000..35cb0e19 --- /dev/null +++ b/opensubdiv/far/bilinearSubdivisionTablesFactory.h @@ -0,0 +1,175 @@ +// +// Copyright (C) Pixar. All rights reserved. +// +// This license governs use of the accompanying software. If you +// use the software, you accept this license. If you do not accept +// the license, do not use the software. +// +// 1. Definitions +// The terms "reproduce," "reproduction," "derivative works," and +// "distribution" have the same meaning here as under U.S. +// copyright law. A "contribution" is the original software, or +// any additions or changes to the software. +// A "contributor" is any person or entity that distributes its +// contribution under this license. +// "Licensed patents" are a contributor's patent claims that read +// directly on its contribution. +// +// 2. Grant of Rights +// (A) Copyright Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free copyright license to reproduce its contribution, +// prepare derivative works of its contribution, and distribute +// its contribution or any derivative works that you create. +// (B) Patent Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free license under its licensed patents to make, have +// made, use, sell, offer for sale, import, and/or otherwise +// dispose of its contribution in the software or derivative works +// of the contribution in the software. +// +// 3. Conditions and Limitations +// (A) No Trademark License- This license does not grant you +// rights to use any contributor's name, logo, or trademarks. +// (B) If you bring a patent claim against any contributor over +// patents that you claim are infringed by the software, your +// patent license from such contributor to the software ends +// automatically. +// (C) If you distribute any portion of the software, you must +// retain all copyright, patent, trademark, and attribution +// notices that are present in the software. +// (D) If you distribute any portion of the software in source +// code form, you may do so only under this license by including a +// complete copy of this license with your distribution. If you +// distribute any portion of the software in compiled or object +// code form, you may only do so under a license that complies +// with this license. +// (E) The software is licensed "as-is." You bear the risk of +// using it. The contributors give no express warranties, +// guarantees or conditions. You may have additional consumer +// rights under your local laws which this license cannot change. +// To the extent permitted under your local laws, the contributors +// exclude the implied warranties of merchantability, fitness for +// a particular purpose and non-infringement. +// +#ifndef FAR_BILINEAR_SUBDIVISION_TABLES_FACTORY_H +#define FAR_BILINEAR_SUBDIVISION_TABLES_FACTORY_H + +#include +#include + +#include "../version.h" + +#include "../far/bilinearSubdivisionTables.h" +#include "../far/meshFactory.h" + +namespace OpenSubdiv { +namespace OPENSUBDIV_VERSION { + +template class FarMeshFactory; + +// A specialized factory for FarBilinearSubdivisionTables +// Separating the factory allows us to isolate Far data structures from Hbr dependencies. +// +template struct FarBilinearSubdivisionTablesFactory { + static FarBilinearSubdivisionTables * Create( FarMeshFactory const * factory, FarMesh * mesh, int maxlevel ); +}; + +template FarBilinearSubdivisionTables * +FarBilinearSubdivisionTablesFactory::Create( FarMeshFactory const * factory, FarMesh * mesh, int maxlevel ) { + + assert( factory and mesh ); + + FarBilinearSubdivisionTables * result = new FarBilinearSubdivisionTables(mesh, maxlevel); + + std::vector const & remap = factory->_remapTable; + + // Allocate memory for the indexing tables + result->_F_ITa.Resize(factory->GetNumFaceVerticesTotal(maxlevel)*2); + result->_F_IT.Resize(factory->GetNumFacesTotal(maxlevel) - factory->GetNumFacesTotal(0)); + + result->_E_IT.Resize(factory->GetNumEdgeVerticesTotal(maxlevel)*2); + + result->_V_ITa.Resize(factory->GetNumVertexVerticesTotal(maxlevel)); + + for (int level=1; level<=maxlevel; ++level) { + + // pointer to the first vertex corresponding to this level + result->_vertsOffsets[level] = factory->_vertVertIdx[level-1] + + (int)factory->_vertVertsList[level-1].size(); + + typename FarSubdivisionTables::VertexKernelBatch * batch = & (result->_batches[level-1]); + + // Face vertices + // "For each vertex, gather all the vertices from the parent face." + int offset = 0; + int * F_ITa = result->_F_ITa[level-1]; + unsigned int * F_IT = result->_F_IT[level-1]; + batch->kernelF = (int)factory->_faceVertsList[level].size(); + for (int i=0; i < batch->kernelF; ++i) { + + HbrVertex * v = factory->_faceVertsList[level][i]; + assert(v); + + HbrFace * f=v->GetParentFace(); + assert(f); + + int valence = f->GetNumVertices(); + + F_ITa[2*i+0] = offset; + F_ITa[2*i+1] = valence; + + for (int j=0; jGetVertex(j)->GetID()]; + } + result->_F_ITa.SetMarker(level, &F_ITa[2*batch->kernelF]); + result->_F_IT.SetMarker(level, &F_IT[offset]); + + // Edge vertices + + // "Average the end-points of the parent edge" + int * E_IT = result->_E_IT[level-1]; + batch->kernelE = (int)factory->_edgeVertsList[level].size(); + for (int i=0; i < batch->kernelE; ++i) { + + HbrVertex * v = factory->_edgeVertsList[level][i]; + assert(v); + HbrHalfedge * e = v->GetParentEdge(); + assert(e); + + // get the indices 2 vertices from the parent edge + E_IT[2*i+0] = remap[e->GetOrgVertex()->GetID()]; + E_IT[2*i+1] = remap[e->GetDestVertex()->GetID()]; + + } + result->_E_IT.SetMarker(level, &E_IT[2*batch->kernelE]); + + // Vertex vertices + + // "Pass down the parent vertex" + offset = 0; + int * V_ITa = result->_V_ITa[level-1]; + batch->kernelB.first = 0; + batch->kernelB.second = (int)factory->_vertVertsList[level].size(); + for (int i=0; i < batch->kernelB.second; ++i) { + + HbrVertex * v = factory->_vertVertsList[level][i], + * pv = v->GetParentVertex(); + assert(v and pv); + + V_ITa[i] = remap[pv->GetID()]; + + } + result->_V_ITa.SetMarker(level, &V_ITa[batch->kernelB.second]); + } + return result; +} + +} // end namespace OPENSUBDIV_VERSION +using namespace OPENSUBDIV_VERSION; + +} // end namespace OpenSubdiv + +#endif /* FAR_BILINEAR_SUBDIVISION_TABLES_FACTORY_H */ diff --git a/opensubdiv/far/catmarkSubdivisionTables.h b/opensubdiv/far/catmarkSubdivisionTables.h index 8702dd13..9147b9c2 100644 --- a/opensubdiv/far/catmarkSubdivisionTables.h +++ b/opensubdiv/far/catmarkSubdivisionTables.h @@ -57,12 +57,8 @@ #ifndef FAR_CATMARK_SUBDIVISION_TABLES_H #define FAR_CATMARK_SUBDIVISION_TABLES_H -#include +#include #include -#include - -#include "../hbr/mesh.h" -#include "../hbr/catmark.h" #include "../version.h" @@ -76,8 +72,7 @@ namespace OPENSUBDIV_VERSION { // structure. The advantage of this representation is its ability to be executed // in a massively parallel environment without data dependencies. // - -template class FarCatmarkSubdivisionTables : public FarSubdivisionTables { +template class FarCatmarkSubdivisionTables : public FarSubdivisionTables { public: @@ -97,12 +92,11 @@ public: virtual int GetNumTables() const { return 7; } private: + template friend struct FarCatmarkSubdivisionTablesFactory; + friend class FarDispatcher; - friend class FarMeshFactory; - friend class FarDispatcher; - - // Constructor : build level table at depth 'level' - FarCatmarkSubdivisionTables( FarMeshFactory const & factory, FarMesh * mesh, int level ); + // Private constructor called by factory + FarCatmarkSubdivisionTables( FarMesh * mesh, int maxlevel ); // Compute-kernel applied to vertices resulting from the refinement of a face. void computeFacePoints(int offset, int level, int start, int end, void * clientdata) const; @@ -124,271 +118,28 @@ private: FarTable _F_IT; }; -template int -FarCatmarkSubdivisionTables::GetMemoryUsed() const { - return FarSubdivisionTables::GetMemoryUsed()+ +template +FarCatmarkSubdivisionTables::FarCatmarkSubdivisionTables( FarMesh * mesh, int maxlevel ) : + FarSubdivisionTables(mesh, maxlevel), + _F_ITa(maxlevel+1), + _F_IT(maxlevel+1) +{ } + +template int +FarCatmarkSubdivisionTables::GetMemoryUsed() const { + return FarSubdivisionTables::GetMemoryUsed()+ _F_ITa.GetMemoryUsed()+ _F_IT.GetMemoryUsed(); } -// Constructor - generates indexing tables matching the Catmull-Clark subdivision scheme. -// -// tables codices detail : -// -// _F_ITa[0] : offset into _F_IT array of vertices making up the face -// _F_ITa[1] : valence of the face -// -// _E_ITa[0] : index of the org / dest vertices of the parent edge -// _E_ITa[1] : -// _E_ITa[2] : index of vertices refined from the faces left / right -// _E_ITa[3] : of the parent edge -// -// _V_ITa[0] : offset to the corresponding adjacent vertices into _V0_IT -// _V_ITa[1] : number of adjacent indices -// _V_ITa[2] : index of the parent vertex -// _V_ITa[3] : index of adjacent edge 0 (k_Crease rule) -// _V_ITa[4] : index of adjacent edge 1 (k_Crease rule) -// -template -FarCatmarkSubdivisionTables::FarCatmarkSubdivisionTables( FarMeshFactory const & factory, FarMesh * mesh, int maxlevel ) : - FarSubdivisionTables(mesh, maxlevel), - _F_ITa(maxlevel+1), - _F_IT(maxlevel+1) -{ - std::vector const & remap = factory._remapTable; - - // Allocate memory for the indexing tables - _F_ITa.Resize(factory.GetNumFaceVerticesTotal(maxlevel)*2); - _F_IT.Resize(factory.GetNumFacesTotal(maxlevel) - factory.GetNumFacesTotal(0)); - - this->_E_IT.Resize(factory.GetNumEdgeVerticesTotal(maxlevel)*4); - this->_E_W.Resize(factory.GetNumEdgeVerticesTotal(maxlevel)*2); - - this->_V_ITa.Resize(factory.GetNumVertexVerticesTotal(maxlevel)*5); - this->_V_IT.Resize(factory.GetNumAdjacentVertVerticesTotal(maxlevel)*2); - this->_V_W.Resize(factory.GetNumVertexVerticesTotal(maxlevel)); - - for (int level=1; level<=maxlevel; ++level) { - - // pointer to the first vertex corresponding to this level - this->_vertsOffsets[level] = factory._vertVertIdx[level-1] + - (int)factory._vertVertsList[level-1].size(); - - typename FarSubdivisionTables::VertexKernelBatch * batch = & (this->_batches[level-1]); - - // Face vertices - // "For each vertex, gather all the vertices from the parent face." - int offset = 0; - int * F_ITa = this->_F_ITa[level-1]; - unsigned int * F_IT = this->_F_IT[level-1]; - batch->kernelF = (int)factory._faceVertsList[level].size(); - for (int i=0; i < batch->kernelF; ++i) { - - HbrVertex * v = factory._faceVertsList[level][i]; - assert(v); - - HbrFace * f=v->GetParentFace(); - assert(f); - - int valence = f->GetNumVertices(); - - F_ITa[2*i+0] = offset; - F_ITa[2*i+1] = valence; - - for (int j=0; jGetVertex(j)->GetID()]; - } - _F_ITa.SetMarker(level, &F_ITa[2*batch->kernelF]); - _F_IT.SetMarker(level, &F_IT[offset]); - - // Edge vertices - - // Triangular interpolation mode : - // see "smoothtriangle" tag introduced in prman 3.9 and HbrCatmarkSubdivision - typename HbrCatmarkSubdivision::TriangleSubdivision triangleMethod = - dynamic_cast *>(factory._hbrMesh->GetSubdivision())->GetTriangleSubdivisionMethod(); - - // "For each vertex, gather the 2 vertices from the parent edege and the - // 2 child vertices from the faces to the left and right of that edge. - // Adjust if edge has a crease or is on a boundary." - int * E_IT = this->_E_IT[level-1]; - float * E_W = this->_E_W[level-1]; - batch->kernelE = (int)factory._edgeVertsList[level].size(); - for (int i=0; i < batch->kernelE; ++i) { - - HbrVertex * v = factory._edgeVertsList[level][i]; - assert(v); - HbrHalfedge * e = v->GetParentEdge(); - assert(e); - - float esharp = e->GetSharpness(); - - // get the indices 2 vertices from the parent edge - E_IT[4*i+0] = remap[e->GetOrgVertex()->GetID()]; - E_IT[4*i+1] = remap[e->GetDestVertex()->GetID()]; - - float faceWeight=0.5f, vertWeight=0.5f; - - // in the case of a fractional sharpness, set the adjacent faces vertices - if (!e->IsBoundary() && esharp <= 1.0f) { - - float leftWeight, rightWeight; - HbrFace* rf = e->GetRightFace(); - HbrFace* lf = e->GetLeftFace(); - - leftWeight = ( triangleMethod == HbrCatmarkSubdivision::k_New && lf->GetNumVertices() == 3) ? HBR_SMOOTH_TRI_EDGE_WEIGHT : 0.25f; - rightWeight = ( triangleMethod == HbrCatmarkSubdivision::k_New && rf->GetNumVertices() == 3) ? HBR_SMOOTH_TRI_EDGE_WEIGHT : 0.25f; - - faceWeight = 0.5f * (leftWeight + rightWeight); - vertWeight = 0.5f * (1.0f - 2.0f * faceWeight); - - faceWeight *= (1.0f - esharp); - - vertWeight = 0.5f * esharp + (1.0f - esharp) * vertWeight; - - E_IT[4*i+2] = remap[lf->Subdivide()->GetID()]; - E_IT[4*i+3] = remap[rf->Subdivide()->GetID()]; - } else { - E_IT[4*i+2] = -1; - E_IT[4*i+3] = -1; - } - E_W[2*i+0] = vertWeight; - E_W[2*i+1] = faceWeight; - } - this->_E_IT.SetMarker(level, &E_IT[4*batch->kernelE]); - this->_E_W.SetMarker(level, &E_W[2*batch->kernelE]); - - // Vertex vertices - - batch->InitVertexKernels( (int)factory._vertVertsList[level].size(), 0 ); - - offset = 0; - int * V_ITa = this->_V_ITa[level-1]; - unsigned int * V_IT = this->_V_IT[level-1]; - float * V_W = this->_V_W[level-1]; - int nverts = (int)factory._vertVertsList[level].size(); - for (int i=0; i < nverts; ++i) { - - HbrVertex * v = factory._vertVertsList[level][i], - * pv = v->GetParentVertex(); - assert(v and pv); - - // Look at HbrCatmarkSubdivision::Subdivide for more details about - // the multi-pass interpolation - int masks[2], npasses; - float weights[2]; - masks[0] = pv->GetMask(false); - masks[1] = pv->GetMask(true); - - // If the masks are identical, only a single pass is necessary. If the - // vertex is transitioning to another rule, two passes are necessary, - // except when transitioning from k_Dart to k_Smooth : the same - // compute kernel is applied twice. Combining this special case allows - // to batch the compute kernels into fewer calls. - if (masks[0] != masks[1] and ( - not (masks[0]==HbrVertex::k_Smooth and - masks[1]==HbrVertex::k_Dart))) { - weights[1] = pv->GetFractionalMask(); - weights[0] = 1.0f - weights[1]; - npasses = 2; - } else { - weights[0] = 1.0f; - weights[1] = 0.0f; - npasses = 1; - } - - int rank = this->getMaskRanking(masks[0], masks[1]); - - V_ITa[5*i+0] = offset; - V_ITa[5*i+1] = 0; - V_ITa[5*i+2] = remap[ pv->GetID() ]; - V_ITa[5*i+3] = -1; - V_ITa[5*i+4] = -1; - - for (int p=0; p::k_Smooth : - case HbrVertex::k_Dart : { - HbrHalfedge *e = pv->GetIncidentEdge(), - *start = e; - while (e) { - V_ITa[5*i+1]++; - - V_IT[offset++] = remap[ e->GetDestVertex()->GetID() ]; - - V_IT[offset++] = remap[ e->GetLeftFace()->Subdivide()->GetID() ]; - - e = e->GetPrev()->GetOpposite(); - - if (e==start) break; - } - break; - } - case HbrVertex::k_Crease : { - - class GatherCreaseEdgesOperator : public HbrHalfedgeOperator { - public: - HbrVertex * vertex; int eidx[2]; int count; bool next; - - GatherCreaseEdgesOperator(HbrVertex * v, bool n) : vertex(v), count(0), next(n) { eidx[0]=-1; eidx[1]=-1; } - - virtual void operator() (HbrHalfedge &e) { - if (e.IsSharp(next) and count < 2) { - HbrVertex * a = e.GetDestVertex(); - if (a==vertex) - a = e.GetOrgVertex(); - eidx[count++]=a->GetID(); - } - } - }; - - GatherCreaseEdgesOperator op( pv, p==1 ); - pv->ApplyOperatorSurroundingEdges( op ); - - assert(V_ITa[5*i+3]==-1 and V_ITa[5*i+4]==-1); - assert(op.eidx[0]!=-1 and op.eidx[1]!=-1); - V_ITa[5*i+3] = remap[op.eidx[0]]; - V_ITa[5*i+4] = remap[op.eidx[1]]; - break; - } - case HbrVertex::k_Corner : - // in the case of a k_Crease / k_Corner pass combination, we - // need to set the valence to -1 to tell the "B" Kernel to - // switch to k_Corner rule (as edge indices won't be -1) - if (V_ITa[5*i+1]==0) - V_ITa[5*i+1] = -1; - - default : break; - } - - - if (rank>7) - // the k_Corner and k_Crease single-pass cases apply a weight of 1.0 - // but this value is inverted in the kernel - V_W[i] = 0.0; - else - V_W[i] = weights[0]; - - batch->AddVertex( i, rank ); - } - this->_V_ITa.SetMarker(level, &V_ITa[5*nverts]); - this->_V_IT.SetMarker(level, &V_IT[offset]); - this->_V_W.SetMarker(level, &V_W[nverts]); - - batch->kernelB.second++; - batch->kernelA1.second++; - batch->kernelA2.second++; - } -} - -template void -FarCatmarkSubdivisionTables::Apply( int level, void * clientdata ) const { +template void +FarCatmarkSubdivisionTables::Apply( int level, void * clientdata ) const { assert(this->_mesh and level>0); - typename FarSubdivisionTables::VertexKernelBatch const * batch = & (this->_batches[level-1]); + typename FarSubdivisionTables::VertexKernelBatch const * batch = & (this->_batches[level-1]); - FarDispatcher const * dispatch = this->_mesh->GetDispatcher(); + FarDispatcher const * dispatch = this->_mesh->GetDispatcher(); assert(dispatch); int offset = this->GetFirstVertexOffset(level); @@ -412,8 +163,8 @@ FarCatmarkSubdivisionTables::Apply( int level, void * clientdata ) const { // Face-vertices compute Kernel - completely re-entrant // -template void -FarCatmarkSubdivisionTables::computeFacePoints( int offset, int level, int start, int end, void * clientdata ) const { +template void +FarCatmarkSubdivisionTables::computeFacePoints( int offset, int level, int start, int end, void * clientdata ) const { assert(this->_mesh); @@ -442,8 +193,8 @@ FarCatmarkSubdivisionTables::computeFacePoints( int offset, int level, int // Edge-vertices compute Kernel - completely re-entrant // -template void -FarCatmarkSubdivisionTables::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const { +template void +FarCatmarkSubdivisionTables::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const { assert(this->_mesh); @@ -486,8 +237,8 @@ FarCatmarkSubdivisionTables::computeEdgePoints( int offset, int level, int // // multi-pass kernel handling k_Crease and k_Corner rules -template void -FarCatmarkSubdivisionTables::computeVertexPointsA( int offset, bool pass, int level, int start, int end, void * clientdata ) const { +template void +FarCatmarkSubdivisionTables::computeVertexPointsA( int offset, bool pass, int level, int start, int end, void * clientdata ) const { assert(this->_mesh); @@ -531,8 +282,8 @@ FarCatmarkSubdivisionTables::computeVertexPointsA( int offset, bool pass, i } // multi-pass kernel handling k_Dart and k_Smooth rules -template void -FarCatmarkSubdivisionTables::computeVertexPointsB( int offset, int level, int start, int end, void * clientdata ) const { +template void +FarCatmarkSubdivisionTables::computeVertexPointsB( int offset, int level, int start, int end, void * clientdata ) const { assert(this->_mesh); diff --git a/opensubdiv/far/catmarkSubdivisionTablesFactory.h b/opensubdiv/far/catmarkSubdivisionTablesFactory.h new file mode 100644 index 00000000..50abfe8b --- /dev/null +++ b/opensubdiv/far/catmarkSubdivisionTablesFactory.h @@ -0,0 +1,319 @@ +// +// Copyright (C) Pixar. All rights reserved. +// +// This license governs use of the accompanying software. If you +// use the software, you accept this license. If you do not accept +// the license, do not use the software. +// +// 1. Definitions +// The terms "reproduce," "reproduction," "derivative works," and +// "distribution" have the same meaning here as under U.S. +// copyright law. A "contribution" is the original software, or +// any additions or changes to the software. +// A "contributor" is any person or entity that distributes its +// contribution under this license. +// "Licensed patents" are a contributor's patent claims that read +// directly on its contribution. +// +// 2. Grant of Rights +// (A) Copyright Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free copyright license to reproduce its contribution, +// prepare derivative works of its contribution, and distribute +// its contribution or any derivative works that you create. +// (B) Patent Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free license under its licensed patents to make, have +// made, use, sell, offer for sale, import, and/or otherwise +// dispose of its contribution in the software or derivative works +// of the contribution in the software. +// +// 3. Conditions and Limitations +// (A) No Trademark License- This license does not grant you +// rights to use any contributor's name, logo, or trademarks. +// (B) If you bring a patent claim against any contributor over +// patents that you claim are infringed by the software, your +// patent license from such contributor to the software ends +// automatically. +// (C) If you distribute any portion of the software, you must +// retain all copyright, patent, trademark, and attribution +// notices that are present in the software. +// (D) If you distribute any portion of the software in source +// code form, you may do so only under this license by including a +// complete copy of this license with your distribution. If you +// distribute any portion of the software in compiled or object +// code form, you may only do so under a license that complies +// with this license. +// (E) The software is licensed "as-is." You bear the risk of +// using it. The contributors give no express warranties, +// guarantees or conditions. You may have additional consumer +// rights under your local laws which this license cannot change. +// To the extent permitted under your local laws, the contributors +// exclude the implied warranties of merchantability, fitness for +// a particular purpose and non-infringement. +// +#ifndef FAR_CATMARK_SUBDIVISION_TABLES_FACTORY_H +#define FAR_CATMARK_SUBDIVISION_TABLES_FACTORY_H + +#include +#include + +#include "../version.h" + +#include "../far/catmarkSubdivisionTables.h" +#include "../far/meshFactory.h" + +namespace OpenSubdiv { +namespace OPENSUBDIV_VERSION { + +template class FarMeshFactory; + +// A specialized factory for FarCatmarkSubdivisionTables +// Separating the factory allows us to isolate Far data structures from Hbr dependencies. +// +template struct FarCatmarkSubdivisionTablesFactory { + static FarCatmarkSubdivisionTables * Create( FarMeshFactory const * factory, FarMesh * mesh, int maxlevel ); +}; + +template FarCatmarkSubdivisionTables * +FarCatmarkSubdivisionTablesFactory::Create( FarMeshFactory const * factory, FarMesh * mesh, int maxlevel ) { + + assert( factory and mesh ); + + FarCatmarkSubdivisionTables * result = new FarCatmarkSubdivisionTables(mesh, maxlevel); + + std::vector const & remap = factory->_remapTable; + + // Allocate memory for the indexing tables + result->_F_ITa.Resize(factory->GetNumFaceVerticesTotal(maxlevel)*2); + result->_F_IT.Resize(factory->GetNumFacesTotal(maxlevel) - factory->GetNumFacesTotal(0)); + + result->_E_IT.Resize(factory->GetNumEdgeVerticesTotal(maxlevel)*4); + result->_E_W.Resize(factory->GetNumEdgeVerticesTotal(maxlevel)*2); + + result->_V_ITa.Resize(factory->GetNumVertexVerticesTotal(maxlevel)*5); + result->_V_IT.Resize(factory->GetNumAdjacentVertVerticesTotal(maxlevel)*2); + result->_V_W.Resize(factory->GetNumVertexVerticesTotal(maxlevel)); + + for (int level=1; level<=maxlevel; ++level) { + + // pointer to the first vertex corresponding to this level + result->_vertsOffsets[level] = factory->_vertVertIdx[level-1] + + (int)factory->_vertVertsList[level-1].size(); + + typename FarSubdivisionTables::VertexKernelBatch * batch = & (result->_batches[level-1]); + + // Face vertices + // "For each vertex, gather all the vertices from the parent face." + int offset = 0; + int * F_ITa = result->_F_ITa[level-1]; + unsigned int * F_IT = result->_F_IT[level-1]; + batch->kernelF = (int)factory->_faceVertsList[level].size(); + for (int i=0; i < batch->kernelF; ++i) { + + HbrVertex * v = factory->_faceVertsList[level][i]; + assert(v); + + HbrFace * f=v->GetParentFace(); + assert(f); + + int valence = f->GetNumVertices(); + + F_ITa[2*i+0] = offset; + F_ITa[2*i+1] = valence; + + for (int j=0; jGetVertex(j)->GetID()]; + } + result->_F_ITa.SetMarker(level, &F_ITa[2*batch->kernelF]); + result->_F_IT.SetMarker(level, &F_IT[offset]); + + // Edge vertices + + // Triangular interpolation mode : + // see "smoothtriangle" tag introduced in prman 3.9 and HbrCatmarkSubdivision + typename HbrCatmarkSubdivision::TriangleSubdivision triangleMethod = + dynamic_cast *>(factory->_hbrMesh->GetSubdivision())->GetTriangleSubdivisionMethod(); + + // "For each vertex, gather the 2 vertices from the parent edege and the + // 2 child vertices from the faces to the left and right of that edge. + // Adjust if edge has a crease or is on a boundary." + int * E_IT = result->_E_IT[level-1]; + float * E_W = result->_E_W[level-1]; + batch->kernelE = (int)factory->_edgeVertsList[level].size(); + for (int i=0; i < batch->kernelE; ++i) { + + HbrVertex * v = factory->_edgeVertsList[level][i]; + assert(v); + HbrHalfedge * e = v->GetParentEdge(); + assert(e); + + float esharp = e->GetSharpness(); + + // get the indices 2 vertices from the parent edge + E_IT[4*i+0] = remap[e->GetOrgVertex()->GetID()]; + E_IT[4*i+1] = remap[e->GetDestVertex()->GetID()]; + + float faceWeight=0.5f, vertWeight=0.5f; + + // in the case of a fractional sharpness, set the adjacent faces vertices + if (!e->IsBoundary() && esharp <= 1.0f) { + + float leftWeight, rightWeight; + HbrFace* rf = e->GetRightFace(); + HbrFace* lf = e->GetLeftFace(); + + leftWeight = ( triangleMethod == HbrCatmarkSubdivision::k_New && lf->GetNumVertices() == 3) ? HBR_SMOOTH_TRI_EDGE_WEIGHT : 0.25f; + rightWeight = ( triangleMethod == HbrCatmarkSubdivision::k_New && rf->GetNumVertices() == 3) ? HBR_SMOOTH_TRI_EDGE_WEIGHT : 0.25f; + + faceWeight = 0.5f * (leftWeight + rightWeight); + vertWeight = 0.5f * (1.0f - 2.0f * faceWeight); + + faceWeight *= (1.0f - esharp); + + vertWeight = 0.5f * esharp + (1.0f - esharp) * vertWeight; + + E_IT[4*i+2] = remap[lf->Subdivide()->GetID()]; + E_IT[4*i+3] = remap[rf->Subdivide()->GetID()]; + } else { + E_IT[4*i+2] = -1; + E_IT[4*i+3] = -1; + } + E_W[2*i+0] = vertWeight; + E_W[2*i+1] = faceWeight; + } + result->_E_IT.SetMarker(level, &E_IT[4*batch->kernelE]); + result->_E_W.SetMarker(level, &E_W[2*batch->kernelE]); + + // Vertex vertices + + batch->InitVertexKernels( (int)factory->_vertVertsList[level].size(), 0 ); + + offset = 0; + int * V_ITa = result->_V_ITa[level-1]; + unsigned int * V_IT = result->_V_IT[level-1]; + float * V_W = result->_V_W[level-1]; + int nverts = (int)factory->_vertVertsList[level].size(); + for (int i=0; i < nverts; ++i) { + + HbrVertex * v = factory->_vertVertsList[level][i], + * pv = v->GetParentVertex(); + assert(v and pv); + + // Look at HbrCatmarkSubdivision::Subdivide for more details about + // the multi-pass interpolation + int masks[2], npasses; + float weights[2]; + masks[0] = pv->GetMask(false); + masks[1] = pv->GetMask(true); + + // If the masks are identical, only a single pass is necessary. If the + // vertex is transitioning to another rule, two passes are necessary, + // except when transitioning from k_Dart to k_Smooth : the same + // compute kernel is applied twice. Combining this special case allows + // to batch the compute kernels into fewer calls. + if (masks[0] != masks[1] and ( + not (masks[0]==HbrVertex::k_Smooth and + masks[1]==HbrVertex::k_Dart))) { + weights[1] = pv->GetFractionalMask(); + weights[0] = 1.0f - weights[1]; + npasses = 2; + } else { + weights[0] = 1.0f; + weights[1] = 0.0f; + npasses = 1; + } + + int rank = result->getMaskRanking(masks[0], masks[1]); + + V_ITa[5*i+0] = offset; + V_ITa[5*i+1] = 0; + V_ITa[5*i+2] = remap[ pv->GetID() ]; + V_ITa[5*i+3] = -1; + V_ITa[5*i+4] = -1; + + for (int p=0; p::k_Smooth : + case HbrVertex::k_Dart : { + HbrHalfedge *e = pv->GetIncidentEdge(), + *start = e; + while (e) { + V_ITa[5*i+1]++; + + V_IT[offset++] = remap[ e->GetDestVertex()->GetID() ]; + + V_IT[offset++] = remap[ e->GetLeftFace()->Subdivide()->GetID() ]; + + e = e->GetPrev()->GetOpposite(); + + if (e==start) break; + } + break; + } + case HbrVertex::k_Crease : { + + class GatherCreaseEdgesOperator : public HbrHalfedgeOperator { + public: + HbrVertex * vertex; int eidx[2]; int count; bool next; + + GatherCreaseEdgesOperator(HbrVertex * v, bool n) : vertex(v), count(0), next(n) { eidx[0]=-1; eidx[1]=-1; } + + virtual void operator() (HbrHalfedge &e) { + if (e.IsSharp(next) and count < 2) { + HbrVertex * a = e.GetDestVertex(); + if (a==vertex) + a = e.GetOrgVertex(); + eidx[count++]=a->GetID(); + } + } + }; + + GatherCreaseEdgesOperator op( pv, p==1 ); + pv->ApplyOperatorSurroundingEdges( op ); + + assert(V_ITa[5*i+3]==-1 and V_ITa[5*i+4]==-1); + assert(op.eidx[0]!=-1 and op.eidx[1]!=-1); + V_ITa[5*i+3] = remap[op.eidx[0]]; + V_ITa[5*i+4] = remap[op.eidx[1]]; + break; + } + case HbrVertex::k_Corner : + // in the case of a k_Crease / k_Corner pass combination, we + // need to set the valence to -1 to tell the "B" Kernel to + // switch to k_Corner rule (as edge indices won't be -1) + if (V_ITa[5*i+1]==0) + V_ITa[5*i+1] = -1; + + default : break; + } + + + if (rank>7) + // the k_Corner and k_Crease single-pass cases apply a weight of 1.0 + // but this value is inverted in the kernel + V_W[i] = 0.0; + else + V_W[i] = weights[0]; + + batch->AddVertex( i, rank ); + } + result->_V_ITa.SetMarker(level, &V_ITa[5*nverts]); + result->_V_IT.SetMarker(level, &V_IT[offset]); + result->_V_W.SetMarker(level, &V_W[nverts]); + + batch->kernelB.second++; + batch->kernelA1.second++; + batch->kernelA2.second++; + } + return result; +} + +} // end namespace OPENSUBDIV_VERSION +using namespace OPENSUBDIV_VERSION; + +} // end namespace OpenSubdiv + +#endif /* FAR_CATMARK_SUBDIVISION_TABLES_FACTORY_H */ diff --git a/opensubdiv/far/dispatcher.h b/opensubdiv/far/dispatcher.h index 32b46a74..ab8cc637 100644 --- a/opensubdiv/far/dispatcher.h +++ b/opensubdiv/far/dispatcher.h @@ -60,7 +60,6 @@ #include "../version.h" #include "../far/mesh.h" -#include "../far/subdivisionTables.h" #include "../far/bilinearSubdivisionTables.h" #include "../far/catmarkSubdivisionTables.h" #include "../far/loopSubdivisionTables.h" @@ -81,60 +80,59 @@ namespace OPENSUBDIV_VERSION { // - call the FarMesh::Subdivide() to trigger computations // // Note : the caller is responsible for deleting a custom dispatcher -template class FarDispatcher { - +template class FarDispatcher { protected: - friend class FarBilinearSubdivisionTables; - friend class FarCatmarkSubdivisionTables; - friend class FarLoopSubdivisionTables; - friend class FarVertexEditTables; - friend class FarMesh; + template friend class FarMeshFactory; + friend class FarBilinearSubdivisionTables; + friend class FarCatmarkSubdivisionTables; + friend class FarLoopSubdivisionTables; + friend class FarVertexEditTables; + friend class FarMesh; - virtual void Refine(FarMesh * mesh, int maxlevel, void * clientdata=0) const; + virtual void Refine(FarMesh * mesh, int maxlevel, void * clientdata=0) const; - virtual void ApplyBilinearFaceVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; + virtual void ApplyBilinearFaceVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; - virtual void ApplyBilinearEdgeVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; + virtual void ApplyBilinearEdgeVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; - virtual void ApplyBilinearVertexVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; + virtual void ApplyBilinearVertexVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; - virtual void ApplyCatmarkFaceVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; + virtual void ApplyCatmarkFaceVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; - virtual void ApplyCatmarkEdgeVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; + virtual void ApplyCatmarkEdgeVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; - virtual void ApplyCatmarkVertexVerticesKernelB(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; + virtual void ApplyCatmarkVertexVerticesKernelB(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; - virtual void ApplyCatmarkVertexVerticesKernelA(FarMesh * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const; + virtual void ApplyCatmarkVertexVerticesKernelA(FarMesh * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const; - virtual void ApplyLoopEdgeVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; + virtual void ApplyLoopEdgeVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; - virtual void ApplyLoopVertexVerticesKernelB(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; + virtual void ApplyLoopVertexVerticesKernelB(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const; - virtual void ApplyLoopVertexVerticesKernelA(FarMesh * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const; + virtual void ApplyLoopVertexVerticesKernelA(FarMesh * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const; - virtual void ApplyVertexEdit(FarMesh *mesh, int offset, int level, void * clientdata) const; + + virtual void ApplyVertexEdits(FarMesh *mesh, int offset, int level, void * clientdata) const; private: - friend class FarMeshFactory; - static FarDispatcher _DefaultDispatcher; }; -template FarDispatcher FarDispatcher::_DefaultDispatcher; +template FarDispatcher FarDispatcher::_DefaultDispatcher; -template void -FarDispatcher::Refine( FarMesh * mesh, int maxlevel, void * data) const { +template void +FarDispatcher::Refine( FarMesh * mesh, int maxlevel, void * data) const { assert(mesh); - FarSubdivisionTables const * tables = mesh->GetSubdivision(); + FarSubdivisionTables const * tables = mesh->GetSubdivision(); - FarVertexEditTables const * edits = mesh->GetVertexEdit(); + FarVertexEditTables const * edits = mesh->GetVertexEdit(); if ( (maxlevel < 0) ) maxlevel=tables->GetMaxLevel(); @@ -142,98 +140,101 @@ FarDispatcher::Refine( FarMesh * mesh, int maxlevel, void * data) cons maxlevel = std::min(maxlevel, tables->GetMaxLevel()); for (int i=1; iApply(i, data); + + // apply hierarchical edits if (edits) edits->Apply(i, data); } } -template void -FarDispatcher::ApplyBilinearFaceVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { - FarBilinearSubdivisionTables const * subdivision = - dynamic_cast const *>(mesh->GetSubdivision()); +template void +FarDispatcher::ApplyBilinearFaceVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { + FarBilinearSubdivisionTables const * subdivision = + dynamic_cast const *>(mesh->GetSubdivision()); assert(subdivision); subdivision->computeFacePoints(offset, level, start, end, clientdata); } -template void -FarDispatcher::ApplyBilinearEdgeVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { - FarBilinearSubdivisionTables const * subdivision = - dynamic_cast const *>(mesh->GetSubdivision()); +template void +FarDispatcher::ApplyBilinearEdgeVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { + FarBilinearSubdivisionTables const * subdivision = + dynamic_cast const *>(mesh->GetSubdivision()); assert(subdivision); subdivision->computeEdgePoints(offset, level, start, end, clientdata); } -template void -FarDispatcher::ApplyBilinearVertexVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { - FarBilinearSubdivisionTables const * subdivision = - dynamic_cast const *>(mesh->GetSubdivision()); +template void +FarDispatcher::ApplyBilinearVertexVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { + FarBilinearSubdivisionTables const * subdivision = + dynamic_cast const *>(mesh->GetSubdivision()); assert(subdivision); subdivision->computeVertexPoints(offset, level, start, end, clientdata); } -template void -FarDispatcher::ApplyCatmarkFaceVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { - FarCatmarkSubdivisionTables const * subdivision = - dynamic_cast const *>(mesh->GetSubdivision()); +template void +FarDispatcher::ApplyCatmarkFaceVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { + FarCatmarkSubdivisionTables const * subdivision = + dynamic_cast const *>(mesh->GetSubdivision()); assert(subdivision); subdivision->computeFacePoints(offset, level, start, end, clientdata); } -template void -FarDispatcher::ApplyCatmarkEdgeVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { - FarCatmarkSubdivisionTables const * subdivision = - dynamic_cast const *>(mesh->GetSubdivision()); +template void +FarDispatcher::ApplyCatmarkEdgeVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { + FarCatmarkSubdivisionTables const * subdivision = + dynamic_cast const *>(mesh->GetSubdivision()); assert(subdivision); subdivision->computeEdgePoints(offset, level, start, end, clientdata); } -template void -FarDispatcher::ApplyCatmarkVertexVerticesKernelB(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { - FarCatmarkSubdivisionTables const * subdivision = - dynamic_cast const *>(mesh->GetSubdivision()); +template void +FarDispatcher::ApplyCatmarkVertexVerticesKernelB(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { + FarCatmarkSubdivisionTables const * subdivision = + dynamic_cast const *>(mesh->GetSubdivision()); assert(subdivision); subdivision->computeVertexPointsB(offset, level, start, end, clientdata); } -template void -FarDispatcher::ApplyCatmarkVertexVerticesKernelA(FarMesh * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const { - FarCatmarkSubdivisionTables const * subdivision = - dynamic_cast const *>(mesh->GetSubdivision()); +template void +FarDispatcher::ApplyCatmarkVertexVerticesKernelA(FarMesh * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const { + FarCatmarkSubdivisionTables const * subdivision = + dynamic_cast const *>(mesh->GetSubdivision()); assert(subdivision); subdivision->computeVertexPointsA(offset, pass, level, start, end, clientdata); } -template void -FarDispatcher::ApplyLoopEdgeVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { - FarLoopSubdivisionTables const * subdivision = - dynamic_cast const *>(mesh->GetSubdivision()); +template void +FarDispatcher::ApplyLoopEdgeVerticesKernel(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { + FarLoopSubdivisionTables const * subdivision = + dynamic_cast const *>(mesh->GetSubdivision()); assert(subdivision); subdivision->computeEdgePoints(offset, level, start, end, clientdata); } -template void -FarDispatcher::ApplyLoopVertexVerticesKernelB(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { - FarLoopSubdivisionTables const * subdivision = - dynamic_cast const *>(mesh->GetSubdivision()); +template void +FarDispatcher::ApplyLoopVertexVerticesKernelB(FarMesh * mesh, int offset, int level, int start, int end, void * clientdata) const { + FarLoopSubdivisionTables const * subdivision = + dynamic_cast const *>(mesh->GetSubdivision()); assert(subdivision); subdivision->computeVertexPointsB(offset, level, start, end, clientdata); } -template void -FarDispatcher::ApplyLoopVertexVerticesKernelA(FarMesh * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const { - FarLoopSubdivisionTables const * subdivision = - dynamic_cast const *>(mesh->GetSubdivision()); +template void +FarDispatcher::ApplyLoopVertexVerticesKernelA(FarMesh * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const { + FarLoopSubdivisionTables const * subdivision = + dynamic_cast const *>(mesh->GetSubdivision()); assert(subdivision); subdivision->computeVertexPointsA(offset, pass, level, start, end, clientdata); } -template void -FarDispatcher::ApplyVertexEdit(FarMesh * mesh, int offset, int level, void * clientdata) const { - - FarVertexEditTables const * vertexEdit = mesh->GetVertexEdit(); - if (vertexEdit) - vertexEdit->editVertex(level, clientdata); +template void +FarDispatcher::ApplyVertexEdits(FarMesh * mesh, int offset, int level, void * clientdata) const { + FarVertexEditTables const * vertEdit = mesh->GetVertexEdit(); + if (vertEdit) + vertEdit->computeVertexEdits(level, clientdata); } } // end namespace OPENSUBDIV_VERSION diff --git a/opensubdiv/far/loopSubdivisionTables.h b/opensubdiv/far/loopSubdivisionTables.h index 65b7909c..3dcc57f4 100644 --- a/opensubdiv/far/loopSubdivisionTables.h +++ b/opensubdiv/far/loopSubdivisionTables.h @@ -57,13 +57,10 @@ #ifndef FAR_LOOP_SUBDIVISION_TABLES_H #define FAR_LOOP_SUBDIVISION_TABLES_H -#include "assert.h" - +#include +#include #include -#include "../hbr/mesh.h" -#include "../hbr/loop.h" - #include "../version.h" #include "../far/subdivisionTables.h" @@ -77,7 +74,7 @@ namespace OPENSUBDIV_VERSION { // in a massively parallel environment without data dependencies. // -template class FarLoopSubdivisionTables : public FarSubdivisionTables { +template class FarLoopSubdivisionTables : public FarSubdivisionTables { public: @@ -86,13 +83,10 @@ public: private: + template friend struct FarLoopSubdivisionTablesFactory; + friend class FarDispatcher; - friend class FarMeshFactory; - friend class FarDispatcher; - - // Constructor : build level table at depth 'level' - FarLoopSubdivisionTables( FarMeshFactory const & factory, FarMesh * mesh, int level ); - + FarLoopSubdivisionTables( FarMesh * mesh, int maxlevel ); // Compute-kernel applied to vertices resulting from the refinement of an edge. void computeEdgePoints(int offset, int level, int start, int end, void * clientdata) const; @@ -104,212 +98,22 @@ private: // Compute-kernel applied to vertices resulting from the refinement of a vertex // Kernel "B" Handles the k_Crease and k_Corner rules void computeVertexPointsB(int offset,int level, int start, int end, void * clientdata) const; - }; -// Constructor - generates indexing tables matching the Loop subdivision scheme. -// -// tables codices detail : -// -// codices detail : -// -// _E_ITa[0] : index of the org / dest vertices of the parent edge -// _E_ITa[1] : -// _E_ITa[2] : index of vertices refined from the faces left / right -// _E_ITa[3] : of the parent edge -// -// _V_ITa[0] : offset to the corresponding adjacent vertices into _V0_IT -// _V_ITa[1] : number of adjacent indices -// _V_ITa[2] : index of the parent vertex -// _V_ITa[3] : index of adjacent edge 0 (k_Crease rule) -// _V_ITa[3] : index of adjacent edge 1 (k_Crease rule) -// -template -FarLoopSubdivisionTables::FarLoopSubdivisionTables( FarMeshFactory const & factory, FarMesh * mesh, int maxlevel ) - : FarSubdivisionTables(mesh, maxlevel) -{ - std::vector const & remap = factory._remapTable; +template +FarLoopSubdivisionTables::FarLoopSubdivisionTables( FarMesh * mesh, int maxlevel ) : + FarSubdivisionTables(mesh, maxlevel) +{ } - // Allocate memory for the indexing tables - this->_E_IT.Resize(factory.GetNumEdgeVerticesTotal(maxlevel)*4); - this->_E_W.Resize(factory.GetNumEdgeVerticesTotal(maxlevel)*2); - this->_V_ITa.Resize(factory.GetNumVertexVerticesTotal(maxlevel)*5); - this->_V_IT.Resize(factory.GetNumAdjacentVertVerticesTotal(maxlevel)); - this->_V_W.Resize(factory.GetNumVertexVerticesTotal(maxlevel)); - - for (int level=1; level<=maxlevel; ++level) { - - // pointer to the first vertex corresponding to this level - this->_vertsOffsets[level] = factory._vertVertIdx[level-1] + - (int)factory._vertVertsList[level-1].size(); - - typename FarSubdivisionTables::VertexKernelBatch * batch = & (this->_batches[level-1]); - - // Edge vertices - int * E_IT = this->_E_IT[level-1]; - float * E_W = this->_E_W[level-1]; - batch->kernelE = (int)factory._edgeVertsList[level].size(); - for (int i=0; i < batch->kernelE; ++i) { - - HbrVertex * v = factory._edgeVertsList[level][i]; - assert(v); - HbrHalfedge * e = v->GetParentEdge(); - assert(e); - - float esharp = e->GetSharpness(), - endPtWeight = 0.5f, - oppPtWeight = 0.5f; - - E_IT[4*i+0]= remap[e->GetOrgVertex()->GetID()]; - E_IT[4*i+1]= remap[e->GetDestVertex()->GetID()]; - - if (!e->IsBoundary() && esharp <= 1.0f) { - endPtWeight = 0.375f + esharp * (0.5f - 0.375f); - oppPtWeight = 0.125f * (1 - esharp); - - HbrHalfedge* ee = e->GetNext(); - E_IT[4*i+2]= remap[ee->GetDestVertex()->GetID()]; - ee = e->GetOpposite()->GetNext(); - E_IT[4*i+3]= remap[ee->GetDestVertex()->GetID()]; - } else { - E_IT[4*i+2]= -1; - E_IT[4*i+3]= -1; - } - E_W[2*i+0] = endPtWeight; - E_W[2*i+1] = oppPtWeight; - } - this->_E_IT.SetMarker(level, &E_IT[4*batch->kernelE]); - this->_E_W.SetMarker(level, &E_W[2*batch->kernelE]); - - // Vertex vertices - - batch->InitVertexKernels( (int)factory._vertVertsList[level].size(), 0 ); - - int offset = 0; - int * V_ITa = this->_V_ITa[level-1]; - unsigned int * V_IT = this->_V_IT[level-1]; - float * V_W = this->_V_W[level-1]; - int nverts = (int)factory._vertVertsList[level].size(); - for (int i=0; i < nverts; ++i) { - - HbrVertex * v = factory._vertVertsList[level][i], - * pv = v->GetParentVertex(); - assert(v and pv); - - // Look at HbrCatmarkSubdivision::Subdivide for more details about - // the multi-pass interpolation - int masks[2], npasses; - float weights[2]; - masks[0] = pv->GetMask(false); - masks[1] = pv->GetMask(true); - - // If the masks are identical, only a single pass is necessary. If the - // vertex is transitioning to another rule, two passes are necessary, - // except when transitioning from k_Dart to k_Smooth : the same - // compute kernel is applied twice. Combining this special case allows - // to batch the compute kernels into fewer calls. - if (masks[0] != masks[1] and ( - not (masks[0]==HbrVertex::k_Smooth and - masks[1]==HbrVertex::k_Dart))) { - weights[1] = pv->GetFractionalMask(); - weights[0] = 1.0f - weights[1]; - npasses = 2; - } else { - weights[0] = 1.0f; - weights[1] = 0.0f; - npasses = 1; - } - - int rank = this->getMaskRanking(masks[0], masks[1]); - - V_ITa[5*i+0] = offset; - V_ITa[5*i+1] = 0; - V_ITa[5*i+2] = remap[ pv->GetID() ]; - V_ITa[5*i+3] = -1; - V_ITa[5*i+4] = -1; - - for (int p=0; p::k_Smooth : - case HbrVertex::k_Dart : { - HbrHalfedge *e = pv->GetIncidentEdge(), - *start = e; - while (e) { - V_ITa[5*i+1]++; - - V_IT[offset++] = remap[ e->GetDestVertex()->GetID() ]; - - e = e->GetPrev()->GetOpposite(); - - if (e==start) break; - } - break; - } - case HbrVertex::k_Crease : { - - class GatherCreaseEdgesOperator : public HbrHalfedgeOperator { - public: - HbrVertex * vertex; int eidx[2]; int count; bool next; - - GatherCreaseEdgesOperator(HbrVertex * v, bool n) : vertex(v), count(0), next(n) { eidx[0]=-1; eidx[1]=-1; } - - virtual void operator() (HbrHalfedge &e) { - if (e.IsSharp(next) and count < 2) { - HbrVertex * a = e.GetDestVertex(); - if (a==vertex) - a = e.GetOrgVertex(); - eidx[count++]=a->GetID(); - } - } - }; - - GatherCreaseEdgesOperator op( pv, p==1 ); - pv->ApplyOperatorSurroundingEdges( op ); - - assert(V_ITa[5*i+3]==-1 and V_ITa[5*i+4]==-1); - assert(op.eidx[0]!=-1 and op.eidx[1]!=-1); - V_ITa[5*i+3] = remap[op.eidx[0]]; - V_ITa[5*i+4] = remap[op.eidx[1]]; - break; - } - case HbrVertex::k_Corner : - // in the case of a k_Crease / k_Corner pass combination, we - // need to set the valence to -1 to tell the "B" Kernel to - // switch to k_Corner rule (as edge indices won't be -1) - if (V_ITa[5*i+1]==0) - V_ITa[5*i+1] = -1; - - default : break; - } - - if (rank>7) - // the k_Corner and k_Crease single-pass cases apply a weight of 1.0 - // but this value is inverted in the kernel - V_W[i] = 0.0; - else - V_W[i] = weights[0]; - - batch->AddVertex( i, rank ); - } - this->_V_ITa.SetMarker(level, &V_ITa[5*nverts]); - this->_V_IT.SetMarker(level, &V_IT[offset]); - this->_V_W.SetMarker(level, &V_W[nverts]); - - batch->kernelB.second++; - batch->kernelA1.second++; - batch->kernelA2.second++; - } -} - -template void -FarLoopSubdivisionTables::Apply( int level, void * clientdata ) const +template void +FarLoopSubdivisionTables::Apply( int level, void * clientdata ) const { assert(this->_mesh and level>0); - typename FarSubdivisionTables::VertexKernelBatch const * batch = & (this->_batches[level-1]); + typename FarSubdivisionTables::VertexKernelBatch const * batch = & (this->_batches[level-1]); - FarDispatcher const * dispatch = this->_mesh->GetDispatcher(); + FarDispatcher const * dispatch = this->_mesh->GetDispatcher(); assert(dispatch); int offset = this->GetFirstVertexOffset(level); @@ -329,8 +133,8 @@ FarLoopSubdivisionTables::Apply( int level, void * clientdata ) const // Edge-vertices compute Kernel - completely re-entrant // -template void -FarLoopSubdivisionTables::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const { +template void +FarLoopSubdivisionTables::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const { assert(this->_mesh); @@ -373,8 +177,8 @@ FarLoopSubdivisionTables::computeEdgePoints( int offset, int level, int sta // // multi-pass kernel handling k_Crease and k_Corner rules -template void -FarLoopSubdivisionTables::computeVertexPointsA( int offset, bool pass, int level, int start, int end, void * clientdata ) const { +template void +FarLoopSubdivisionTables::computeVertexPointsA( int offset, bool pass, int level, int start, int end, void * clientdata ) const { assert(this->_mesh); @@ -418,8 +222,8 @@ FarLoopSubdivisionTables::computeVertexPointsA( int offset, bool pass, int } // multi-pass kernel handling k_Dart and k_Smooth rules -template void -FarLoopSubdivisionTables::computeVertexPointsB( int offset, int level, int start, int end, void * clientdata ) const { +template void +FarLoopSubdivisionTables::computeVertexPointsB( int offset, int level, int start, int end, void * clientdata ) const { assert(this->_mesh); diff --git a/opensubdiv/far/loopSubdivisionTablesFactory.h b/opensubdiv/far/loopSubdivisionTablesFactory.h new file mode 100644 index 00000000..245c9dfc --- /dev/null +++ b/opensubdiv/far/loopSubdivisionTablesFactory.h @@ -0,0 +1,267 @@ +// +// Copyright (C) Pixar. All rights reserved. +// +// This license governs use of the accompanying software. If you +// use the software, you accept this license. If you do not accept +// the license, do not use the software. +// +// 1. Definitions +// The terms "reproduce," "reproduction," "derivative works," and +// "distribution" have the same meaning here as under U.S. +// copyright law. A "contribution" is the original software, or +// any additions or changes to the software. +// A "contributor" is any person or entity that distributes its +// contribution under this license. +// "Licensed patents" are a contributor's patent claims that read +// directly on its contribution. +// +// 2. Grant of Rights +// (A) Copyright Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free copyright license to reproduce its contribution, +// prepare derivative works of its contribution, and distribute +// its contribution or any derivative works that you create. +// (B) Patent Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free license under its licensed patents to make, have +// made, use, sell, offer for sale, import, and/or otherwise +// dispose of its contribution in the software or derivative works +// of the contribution in the software. +// +// 3. Conditions and Limitations +// (A) No Trademark License- This license does not grant you +// rights to use any contributor's name, logo, or trademarks. +// (B) If you bring a patent claim against any contributor over +// patents that you claim are infringed by the software, your +// patent license from such contributor to the software ends +// automatically. +// (C) If you distribute any portion of the software, you must +// retain all copyright, patent, trademark, and attribution +// notices that are present in the software. +// (D) If you distribute any portion of the software in source +// code form, you may do so only under this license by including a +// complete copy of this license with your distribution. If you +// distribute any portion of the software in compiled or object +// code form, you may only do so under a license that complies +// with this license. +// (E) The software is licensed "as-is." You bear the risk of +// using it. The contributors give no express warranties, +// guarantees or conditions. You may have additional consumer +// rights under your local laws which this license cannot change. +// To the extent permitted under your local laws, the contributors +// exclude the implied warranties of merchantability, fitness for +// a particular purpose and non-infringement. +// +#ifndef FAR_LOOP_SUBDIVISION_TABLES_FACTORY_H +#define FAR_LOOP_SUBDIVISION_TABLES_FACTORY_H + +#include +#include + +#include "../version.h" + +#include "../far/loopSubdivisionTables.h" +#include "../far/meshFactory.h" + +namespace OpenSubdiv { +namespace OPENSUBDIV_VERSION { + +template class FarMeshFactory; + +// A specialized factory for FarLoopSubdivisionTables +// Separating the factory allows us to isolate Far data structures from Hbr dependencies. +// +template struct FarLoopSubdivisionTablesFactory { + static FarLoopSubdivisionTables * Create( FarMeshFactory const * factory, FarMesh * mesh, int maxlevel ); +}; + +template FarLoopSubdivisionTables * +FarLoopSubdivisionTablesFactory::Create( FarMeshFactory const * factory, FarMesh * mesh, int maxlevel ) { + + assert( factory and mesh ); + + FarLoopSubdivisionTables * result = new FarLoopSubdivisionTables(mesh, maxlevel); + + std::vector const & remap = factory->_remapTable; + + // Allocate memory for the indexing tables + result->_E_IT.Resize(factory->GetNumEdgeVerticesTotal(maxlevel)*4); + result->_E_W.Resize(factory->GetNumEdgeVerticesTotal(maxlevel)*2); + + result->_V_ITa.Resize(factory->GetNumVertexVerticesTotal(maxlevel)*5); + result->_V_IT.Resize(factory->GetNumAdjacentVertVerticesTotal(maxlevel)); + result->_V_W.Resize(factory->GetNumVertexVerticesTotal(maxlevel)); + + for (int level=1; level<=maxlevel; ++level) { + + // pointer to the first vertex corresponding to this level + result->_vertsOffsets[level] = factory->_vertVertIdx[level-1] + + (int)factory->_vertVertsList[level-1].size(); + + typename FarSubdivisionTables::VertexKernelBatch * batch = & (result->_batches[level-1]); + + // Edge vertices + int * E_IT = result->_E_IT[level-1]; + float * E_W = result->_E_W[level-1]; + batch->kernelE = (int)factory->_edgeVertsList[level].size(); + for (int i=0; i < batch->kernelE; ++i) { + + HbrVertex * v = factory->_edgeVertsList[level][i]; + assert(v); + HbrHalfedge * e = v->GetParentEdge(); + assert(e); + + float esharp = e->GetSharpness(), + endPtWeight = 0.5f, + oppPtWeight = 0.5f; + + E_IT[4*i+0]= remap[e->GetOrgVertex()->GetID()]; + E_IT[4*i+1]= remap[e->GetDestVertex()->GetID()]; + + if (!e->IsBoundary() && esharp <= 1.0f) { + endPtWeight = 0.375f + esharp * (0.5f - 0.375f); + oppPtWeight = 0.125f * (1 - esharp); + + HbrHalfedge* ee = e->GetNext(); + E_IT[4*i+2]= remap[ee->GetDestVertex()->GetID()]; + ee = e->GetOpposite()->GetNext(); + E_IT[4*i+3]= remap[ee->GetDestVertex()->GetID()]; + } else { + E_IT[4*i+2]= -1; + E_IT[4*i+3]= -1; + } + E_W[2*i+0] = endPtWeight; + E_W[2*i+1] = oppPtWeight; + } + result->_E_IT.SetMarker(level, &E_IT[4*batch->kernelE]); + result->_E_W.SetMarker(level, &E_W[2*batch->kernelE]); + + // Vertex vertices + + batch->InitVertexKernels( (int)factory->_vertVertsList[level].size(), 0 ); + + int offset = 0; + int * V_ITa = result->_V_ITa[level-1]; + unsigned int * V_IT = result->_V_IT[level-1]; + float * V_W = result->_V_W[level-1]; + int nverts = (int)factory->_vertVertsList[level].size(); + for (int i=0; i < nverts; ++i) { + + HbrVertex * v = factory->_vertVertsList[level][i], + * pv = v->GetParentVertex(); + assert(v and pv); + + // Look at HbrCatmarkSubdivision::Subdivide for more details about + // the multi-pass interpolation + int masks[2], npasses; + float weights[2]; + masks[0] = pv->GetMask(false); + masks[1] = pv->GetMask(true); + + // If the masks are identical, only a single pass is necessary. If the + // vertex is transitioning to another rule, two passes are necessary, + // except when transitioning from k_Dart to k_Smooth : the same + // compute kernel is applied twice. Combining this special case allows + // to batch the compute kernels into fewer calls. + if (masks[0] != masks[1] and ( + not (masks[0]==HbrVertex::k_Smooth and + masks[1]==HbrVertex::k_Dart))) { + weights[1] = pv->GetFractionalMask(); + weights[0] = 1.0f - weights[1]; + npasses = 2; + } else { + weights[0] = 1.0f; + weights[1] = 0.0f; + npasses = 1; + } + + int rank = result->getMaskRanking(masks[0], masks[1]); + + V_ITa[5*i+0] = offset; + V_ITa[5*i+1] = 0; + V_ITa[5*i+2] = remap[ pv->GetID() ]; + V_ITa[5*i+3] = -1; + V_ITa[5*i+4] = -1; + + for (int p=0; p::k_Smooth : + case HbrVertex::k_Dart : { + HbrHalfedge *e = pv->GetIncidentEdge(), + *start = e; + while (e) { + V_ITa[5*i+1]++; + + V_IT[offset++] = remap[ e->GetDestVertex()->GetID() ]; + + e = e->GetPrev()->GetOpposite(); + + if (e==start) break; + } + break; + } + case HbrVertex::k_Crease : { + + class GatherCreaseEdgesOperator : public HbrHalfedgeOperator { + public: + HbrVertex * vertex; int eidx[2]; int count; bool next; + + GatherCreaseEdgesOperator(HbrVertex * v, bool n) : vertex(v), count(0), next(n) { eidx[0]=-1; eidx[1]=-1; } + + virtual void operator() (HbrHalfedge &e) { + if (e.IsSharp(next) and count < 2) { + HbrVertex * a = e.GetDestVertex(); + if (a==vertex) + a = e.GetOrgVertex(); + eidx[count++]=a->GetID(); + } + } + }; + + GatherCreaseEdgesOperator op( pv, p==1 ); + pv->ApplyOperatorSurroundingEdges( op ); + + assert(V_ITa[5*i+3]==-1 and V_ITa[5*i+4]==-1); + assert(op.eidx[0]!=-1 and op.eidx[1]!=-1); + V_ITa[5*i+3] = remap[op.eidx[0]]; + V_ITa[5*i+4] = remap[op.eidx[1]]; + break; + } + case HbrVertex::k_Corner : + // in the case of a k_Crease / k_Corner pass combination, we + // need to set the valence to -1 to tell the "B" Kernel to + // switch to k_Corner rule (as edge indices won't be -1) + if (V_ITa[5*i+1]==0) + V_ITa[5*i+1] = -1; + + default : break; + } + + if (rank>7) + // the k_Corner and k_Crease single-pass cases apply a weight of 1.0 + // but this value is inverted in the kernel + V_W[i] = 0.0; + else + V_W[i] = weights[0]; + + batch->AddVertex( i, rank ); + } + result->_V_ITa.SetMarker(level, &V_ITa[5*nverts]); + result->_V_IT.SetMarker(level, &V_IT[offset]); + result->_V_W.SetMarker(level, &V_W[nverts]); + + batch->kernelB.second++; + batch->kernelA1.second++; + batch->kernelA2.second++; + } + return result; +} + +} // end namespace OPENSUBDIV_VERSION +using namespace OPENSUBDIV_VERSION; + +} // end namespace OpenSubdiv + +#endif /* FAR_LOOP_SUBDIVISION_TABLES_FACTORY_H */ diff --git a/opensubdiv/far/mesh.h b/opensubdiv/far/mesh.h index 8ab4a214..1755ac9f 100644 --- a/opensubdiv/far/mesh.h +++ b/opensubdiv/far/mesh.h @@ -61,14 +61,13 @@ #include #include "../version.h" +#include "../far/subdivisionTables.h" +#include "../far/vertexEditTables.h" namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { -template class FarMeshFactory; -template class FarSubdivisionTables; -template class FarDispatcher; -template class FarVertexEditTables; +template class FarDispatcher; // Core serialized subdivision mesh class. // @@ -78,16 +77,16 @@ template class FarVertexEditTables; // the actual positions of the vertices are irrelevant, so passing an "empty" // vertex class to Hbr is perfectly acceptable and saves some data-copy steps. -template class FarMesh { +template class FarMesh { public: ~FarMesh(); // returns the subdivision method - FarSubdivisionTables const * GetSubdivision() const { return _subdivision; } + FarSubdivisionTables const * GetSubdivision() const { return _subdivisionTables; } // returns the compute dispatcher - FarDispatcher const * GetDispatcher() const { return _dispatcher; } + FarDispatcher const * GetDispatcher() const { return _dispatcher; } enum PatchType { k_BilinearTriangles, @@ -111,7 +110,7 @@ public: std::vector const & GetPtexCoordinates(int level) const; // returns vertex edit tables - FarVertexEditTables const * GetVertexEdit() const { return _vertexEdit; } + FarVertexEditTables const * GetVertexEdit() const { return _vertexEditTables; } // returns the number of coarse vertices held at the beginning of the vertex // buffer. @@ -125,19 +124,24 @@ public: void Subdivide(int level=-1); private: - friend class FarMeshFactory; + // Note : the vertex classes are renamed so as not to shadow the + // declaration of the templated vertex class U. + template friend class FarMeshFactory; - FarMesh() : _subdivision(0), _dispatcher(0), _vertexEdit(0) { } + FarMesh() : _subdivisionTables(0), _dispatcher(0), _vertexEditTables(0) { } // non-copyable, so these are not implemented: - FarMesh(FarMesh const &); - FarMesh & operator = (FarMesh const &); + FarMesh(FarMesh const &); + FarMesh & operator = (FarMesh const &); // subdivision method used in this mesh - FarSubdivisionTables * _subdivision; + FarSubdivisionTables * _subdivisionTables; + + // hierarchical vertex edit tables + FarVertexEditTables * _vertexEditTables; // customizable compute dispatcher class - FarDispatcher * _dispatcher; + FarDispatcher * _dispatcher; // list of vertices (up to N levels of subdivision) std::vector _vertices; @@ -148,9 +152,6 @@ private: // ptex coordinates for each face std::vector< std::vector > _ptexcoordinates; - // hierarchical vertex edit tables - FarVertexEditTables * _vertexEdit; - // XXX stub for adaptive work PatchType _patchtype; @@ -158,47 +159,49 @@ private: int _numCoarseVertices; }; -template -FarMesh::~FarMesh() +template +FarMesh::~FarMesh() { - delete _subdivision; - delete _vertexEdit; + delete _subdivisionTables; + delete _vertexEditTables; } -template int -FarMesh::GetNumCoarseVertices() const { +template int +FarMesh::GetNumCoarseVertices() const { return _numCoarseVertices; } -template std::vector const & -FarMesh::GetFaceVertices(int level) const { +template std::vector const & +FarMesh::GetFaceVertices(int level) const { if ( (level>=0) and (level<(int)_faceverts.size()) ) return _faceverts[level]; return _faceverts[0]; } -template std::vector const & -FarMesh::GetPtexCoordinates(int level) const { +template std::vector const & +FarMesh::GetPtexCoordinates(int level) const { if ( (level>=0) and (level<(int)_faceverts.size()) ) return _ptexcoordinates[level]; return _ptexcoordinates[0]; } -template void -FarMesh::Subdivide(int maxlevel) { +template void +FarMesh::Subdivide(int maxlevel) { - assert(_subdivision); + assert(_subdivisionTables); if ( (maxlevel < 0) ) - maxlevel=_subdivision->GetMaxLevel(); + maxlevel=_subdivisionTables->GetMaxLevel(); else - maxlevel = std::min(maxlevel, _subdivision->GetMaxLevel()); + maxlevel = std::min(maxlevel, _subdivisionTables->GetMaxLevel()); for (int i=1; iApply(i); - if (_vertexEdit) - _vertexEdit->Apply(i); + + _subdivisionTables->Apply(i); + + if (_vertexEditTables) + _vertexEditTables->Apply(i); } } diff --git a/opensubdiv/far/meshFactory.h b/opensubdiv/far/meshFactory.h index 56430cf1..fe249a21 100644 --- a/opensubdiv/far/meshFactory.h +++ b/opensubdiv/far/meshFactory.h @@ -59,18 +59,19 @@ #include +#include "../version.h" + #include "../hbr/mesh.h" #include "../hbr/bilinear.h" #include "../hbr/catmark.h" #include "../hbr/loop.h" -#include "../version.h" - #include "../far/mesh.h" #include "../far/dispatcher.h" -#include "../far/bilinearSubdivisionTables.h" -#include "../far/catmarkSubdivisionTables.h" -#include "../far/loopSubdivisionTables.h" +#include "../far/bilinearSubdivisionTablesFactory.h" +#include "../far/catmarkSubdivisionTablesFactory.h" +#include "../far/loopSubdivisionTablesFactory.h" +#include "../far/vertexEditTablesFactory.h" namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { @@ -93,8 +94,7 @@ public: FarMeshFactory(HbrMesh * mesh, int maxlevel); // Create a table-based mesh representation - // XXXX : this creator will take the options for adaptive patch meshes - FarMesh * Create( FarDispatcher * dispatch=0 ); + FarMesh * Create( FarDispatcher * dispatch=0 ); // Maximum level of subidivision supported by this factory int GetMaxLevel() const { return _maxlevel; } @@ -129,10 +129,10 @@ public: std::vector const & GetRemappingTable( ) const { return _remapTable; } private: - friend class FarBilinearSubdivisionTables; - friend class FarCatmarkSubdivisionTables; - friend class FarLoopSubdivisionTables; - friend class FarVertexEditTables; + friend struct FarBilinearSubdivisionTablesFactory; + friend struct FarCatmarkSubdivisionTablesFactory; + friend struct FarLoopSubdivisionTablesFactory; + friend struct FarVertexEditTablesFactory; // Non-copyable, so these are not implemented: FarMeshFactory( FarMeshFactory const & ); @@ -144,18 +144,17 @@ private: static bool isLoop(HbrMesh * mesh); - void copyTopology( std::vector & vec, int level ); - void generatePtexCoordinates( std::vector & vec, int level ); - FarVertexEditTables * createVertexEdit(FarMesh * mesh); + void copyTopology( std::vector & vec, int level ); + + static bool compareVertices( HbrVertex const *x, HbrVertex const *y ); static void refine( HbrMesh * mesh, int maxlevel ); template static int sumList( std::vector > const & list, int level ); - static bool compareNSubfaces(HbrVertexEdit const *a, HbrVertexEdit const *b); - +private: HbrMesh * _hbrMesh; int _maxlevel, @@ -218,6 +217,27 @@ FarMeshFactory::refine( HbrMesh * mesh, int maxlevel ) { } +// Compare the weight masks of 2 vertices using the following ordering table. +// +// Assuming 2 computer kernels : +// - A handles the k_Crease and K_Corner rules +// - B handles the K_Smooth and K_Dart rules +// The vertices should be sorted so as to minimize the number execution calls of +// these kernels to match the 2 pass interpolation scheme used in Hbr. +template bool +FarMeshFactory::compareVertices( HbrVertex const * x, HbrVertex const * y ) { + + // Masks of the parent vertex decide for the current vertex. + HbrVertex * px=x->GetParentVertex(), + * py=y->GetParentVertex(); + + assert( (FarSubdivisionTables::getMaskRanking(px->GetMask(false), px->GetMask(true) )!=0xFF) and + (FarSubdivisionTables::getMaskRanking(py->GetMask(false), py->GetMask(true) )!=0xFF) ); + + return FarSubdivisionTables::getMaskRanking(px->GetMask(false), px->GetMask(true) ) < + FarSubdivisionTables::getMaskRanking(py->GetMask(false), py->GetMask(true) ); +} + // Assumption : the order of the vertices in the HbrMesh could be set in any // random order, so the builder runs 2 passes over the entire vertex list to // gather the counters needed to generate the indexing tables. @@ -328,11 +348,9 @@ FarMeshFactory::FarMeshFactory( HbrMesh * mesh, int maxlevel ) : // Sort the the vertices that are the child of a vertex based on their weight // mask. The masks combinations are ordered so as to minimize the compute - // kernel switching ( more information on this in the HbrVertex comparison - // function 'FarSubdivisionTables::compareVertices' ). + // kernel switching. for (size_t i=1; i<_vertVertsList.size(); ++i) - std::sort(_vertVertsList[i].begin(), _vertVertsList[i].end(), - FarSubdivisionTables::compareVertices); + std::sort(_vertVertsList[i].begin(), _vertVertsList[i].end(),compareVertices); // These vertices still need a remapped index for (int l=1; l<(maxlevel+1); ++l) @@ -403,6 +421,7 @@ FarMeshFactory::copyTopology( std::vector & vec, int level ) { vec[nv*i+j]=_remapTable[f->GetVertex(j)->GetID()]; } } + template void copyVertex( T & dest, U const & src ) { } @@ -412,7 +431,7 @@ copyVertex( T & dest, T const & src ) { dest = src; } -// XXX : this currently only supports Catmark / Bilinear schemes. +// XXXX : this currently only supports Catmark / Bilinear schemes. template void FarMeshFactory::generatePtexCoordinates( std::vector & vec, int level ) { @@ -462,162 +481,31 @@ FarMeshFactory::generatePtexCoordinates( std::vector & vec, int level } } -template bool -FarMeshFactory::compareNSubfaces(HbrVertexEdit const *a, HbrVertexEdit const *b) { - - return a->GetNSubfaces() < b->GetNSubfaces(); -} - -template FarVertexEditTables * -FarMeshFactory::createVertexEdit(FarMesh *mesh) { - - FarVertexEditTables * table = new FarVertexEditTables(mesh, _maxlevel); - - std::vector*> const & hEdits = _hbrMesh->GetHierarchicalEdits(); - - std::vector const *> vertexEdits; - vertexEdits.reserve(hEdits.size()); - - for (int i=0; i<(int)hEdits.size(); ++i) { - HbrVertexEdit *vedit = dynamic_cast *>(hEdits[i]); - if (vedit) { - int editlevel = vedit->GetNSubfaces(); - if (editlevel > _maxlevel) - continue; // far table doesn't contain such level - - vertexEdits.push_back(vedit); - } - } - - // sort vertex edits by level - std::sort(vertexEdits.begin(), vertexEdits.end(), compareNSubfaces); - - // uniquify edits with index and width - std::vector batchIndices; - std::vector batchSizes; - for(int i=0; i<(int)vertexEdits.size(); ++i) { - HbrVertexEdit const *vedit = vertexEdits[i]; - - // translate operation enum - typename FarVertexEditTables::Operation operation = (vedit->GetOperation() == HbrHierarchicalEdit::Set) ? - FarVertexEditTables::Set : FarVertexEditTables::Add; - - // determine which batch this edit belongs to (create it if necessary) - int batchIndex = -1; - for(int i = 0; i<(int)table->_batches.size(); ++i) { - if(table->_batches[i]._index == vedit->GetIndex() && - table->_batches[i]._width == vedit->GetWidth() && - table->_batches[i]._operation == operation) { - batchIndex = i; - break; - } - } - if (batchIndex == -1) { - // create new batch - batchIndex = (int)table->_batches.size(); - table->_batches.push_back(typename FarVertexEditTables::VertexEdit(vedit->GetIndex(), vedit->GetWidth(), operation)); - batchSizes.push_back(0); - } - batchSizes[batchIndex]++; - batchIndices.push_back(batchIndex); - } - - // allocate batches - int numBatches = table->GetNumBatches(); - for(int i=0; i_batches[i]._offsets.SetMaxLevel(_maxlevel+1); - table->_batches[i]._values.SetMaxLevel(_maxlevel+1); - table->_batches[i]._offsets.Resize(batchSizes[i]); - table->_batches[i]._values.Resize(batchSizes[i] * table->_batches[i]._width); - } - - // resolve vertexedits path to absolute offset and put them into corresponding batch - std::vector currentLevels(numBatches); - std::vector currentCounts(numBatches); - for(int i=0; i<(int)vertexEdits.size(); ++i){ - HbrVertexEdit const *vedit = vertexEdits[i]; - - HbrFace * f = _hbrMesh->GetFace(vedit->GetFaceID()); - - int level = vedit->GetNSubfaces(); - for (int j=0; jGetChild(vedit->GetSubface(j)); - - // remap vertex ID - int vertexID = f->GetVertex(vedit->GetVertexID())->GetID(); - vertexID = _remapTable[vertexID]; - - int batchIndex = batchIndices[i]; - int & batchLevel = currentLevels[batchIndex]; - int & batchCount = currentCounts[batchIndex]; - typename FarVertexEditTables::VertexEdit &batch = table->_batches[batchIndex]; - - // fill marker for skipped levels if exists - while(currentLevels[batchIndex] < level-1) { - batch._offsets.SetMarker(batchLevel+1, &batch._offsets[batchLevel][batchCount]); - batch._values.SetMarker(batchLevel+1, &batch._values[batchLevel][batchCount*batch._width]); - batchLevel++; - batchCount = 0; - } - - // set absolute vertex offset and edit values - const float *values = vedit->GetEdit(); - bool negate = (vedit->GetOperation() == HbrHierarchicalEdit::Subtract); - - batch._offsets[level-1][batchCount] = vertexID; - for(int i=0; i::VertexEdit &batch = table->_batches[i]; - int & batchLevel = currentLevels[i]; - int & batchCount = currentCounts[i]; - - // fill marker for rest levels if exists - while(batchLevel < _maxlevel) { - batch._offsets.SetMarker(batchLevel+1, &batch._offsets[batchLevel][batchCount]); - batch._values.SetMarker(batchLevel+1, &batch._values[batchLevel][batchCount*batch._width]); - batchLevel++; - batchCount = 0; - } - } - - return table; -} - -template FarMesh * -FarMeshFactory::Create( FarDispatcher * dispatch ) { +template FarMesh * +FarMeshFactory::Create( FarDispatcher * dispatch ) { assert( _hbrMesh ); if (_maxlevel<1) return 0; - FarMesh * result = new FarMesh(); + FarMesh * result = new FarMesh(); if (dispatch) result->_dispatcher = dispatch; else - result->_dispatcher = & FarDispatcher::_DefaultDispatcher; + result->_dispatcher = & FarDispatcher::_DefaultDispatcher; if ( isBilinear( _hbrMesh ) ) { - result->_subdivision = - new FarBilinearSubdivisionTables( *this, result, _maxlevel ); + result->_subdivisionTables = FarBilinearSubdivisionTablesFactory::Create( this, result, _maxlevel ); } else if ( isCatmark( _hbrMesh ) ) { - result->_subdivision = - new FarCatmarkSubdivisionTables( *this, result, _maxlevel ); + result->_subdivisionTables = FarCatmarkSubdivisionTablesFactory::Create( this, result, _maxlevel ); } else if ( isLoop(_hbrMesh) ) { - result->_subdivision = - new FarLoopSubdivisionTables( *this, result, _maxlevel ); + result->_subdivisionTables = FarLoopSubdivisionTablesFactory::Create( this, result, _maxlevel ); } else assert(0); - + assert(result->_subdivisionTables); + result->_numCoarseVertices = (int)_vertVertsList[0].size(); // Copy the data of the coarse vertices into the vertex buffer. @@ -629,7 +517,7 @@ FarMeshFactory::Create( FarDispatcher * dispatch ) { // Populate topology (face verts indices) // XXXX : only k_BilinearQuads support for now - adaptive bicubic patches to come - result->_patchtype = FarMesh::k_BilinearQuads; + result->_patchtype = FarMesh::k_BilinearQuads; // XXXX : we should let the client control what to copy, most of this may be irrelevant result->_faceverts.resize(_maxlevel+1); @@ -642,9 +530,10 @@ FarMeshFactory::Create( FarDispatcher * dispatch ) { // Create VertexEditTables if necessary if (_hbrMesh->HasVertexEdits()) { - result->_vertexEdit = createVertexEdit(result); + result->_vertexEditTables = FarVertexEditTablesFactory::Create( this, result, _maxlevel ); + assert(result->_vertexEditTables); } - + return result; } diff --git a/opensubdiv/far/subdivisionTables.h b/opensubdiv/far/subdivisionTables.h index 63f058b0..dfa79f26 100644 --- a/opensubdiv/far/subdivisionTables.h +++ b/opensubdiv/far/subdivisionTables.h @@ -57,23 +57,18 @@ #ifndef FAR_SUBDIVISION_TABLES_H #define FAR_SUBDIVISION_TABLES_H -#include +#include #include #include #include "../version.h" #include "../far/table.h" -template class HbrFace; -template class HbrHalfedge; -template class HbrVertex; -template class HbrMesh; - namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { -template class FarMesh; -template class FarMeshFactory; +template class FarMesh; +template class FarDispatcher; // Catmull-Clark tables store the indexing tables required in order to compute // the refined positions of a mesh without the help of a hierarchical data @@ -92,11 +87,11 @@ template class FarMeshFactory; // For more details see : "Feature Adaptive GPU Rendering of Catmull-Clark // Subdivision Surfaces" p.3 - par. 3.2 -template class FarSubdivisionTables { +template class FarSubdivisionTables { public: // Destructor - virtual ~FarSubdivisionTables() {} + virtual ~FarSubdivisionTables() {} // Return the highest level of subdivision possible with these tables int GetMaxLevel() const { return (int)(_vertsOffsets.size()); } @@ -108,7 +103,7 @@ public: virtual void Apply( int level, void * clientdata=0 ) const=0; // Pointer back to the mesh owning the table - FarMesh * GetMesh() { return _mesh; } + FarMesh * GetMesh() { return _mesh; } // The index of the first vertex that belongs to the level of subdivision // represented by this set of FarCatmarkSubdivisionTables @@ -148,16 +143,13 @@ public: virtual int GetNumTables() const { return 5; } protected: - friend class FarMeshFactory; + template friend class FarMeshFactory; - FarSubdivisionTables( FarMesh * mesh, int maxlevel ); + FarSubdivisionTables( FarMesh * mesh, int maxlevel ); // Returns an integer based on the order in which the kernels are applied static int getMaskRanking( unsigned char mask0, unsigned char mask1 ); - // Compares to vertices based on the ranking of their hbr masks combination - static bool compareVertices( HbrVertex const * x, HbrVertex const * y ); - struct VertexKernelBatch { int kernelF; // number of face vertices int kernelE; // number of edge vertices @@ -202,7 +194,7 @@ protected: protected: // mesh that owns this subdivisionTable - FarMesh * _mesh; + FarMesh * _mesh; FarTable _E_IT; // vertices from edge refinement FarTable _E_W; // weigths @@ -217,8 +209,8 @@ protected: private: }; -template -FarSubdivisionTables::FarSubdivisionTables( FarMesh * mesh, int maxlevel ) : +template +FarSubdivisionTables::FarSubdivisionTables( FarMesh * mesh, int maxlevel ) : _mesh(mesh), _E_IT(maxlevel+1), _E_W(maxlevel+1), @@ -251,8 +243,8 @@ FarSubdivisionTables::FarSubdivisionTables( FarMesh * mesh, int maxlev // with : // - A : compute kernel applying k_Crease / k_Corner rules // - B : compute kernel applying k_Smooth / k_Dart rules -template int -FarSubdivisionTables::getMaskRanking( unsigned char mask0, unsigned char mask1 ) { +template int +FarSubdivisionTables::getMaskRanking( unsigned char mask0, unsigned char mask1 ) { static short masks[4][4] = { { 0, 1, 6, 4 }, { 0xFF, 2, 5, 3 }, { 0xFF, 0xFF, 9, 7 }, @@ -260,47 +252,26 @@ FarSubdivisionTables::getMaskRanking( unsigned char mask0, unsigned char ma return masks[mask0][mask1]; } -// Compare the weight masks of 2 vertices using the following ordering table. -// -// Assuming 2 computer kernels : -// - A handles the k_Crease and K_Corner rules -// - B handles the K_Smooth and K_Dart rules -// The vertices should be sorted so as to minimize the number execution calls of -// these kernels to match the 2 pass interpolation scheme used in Hbr. -template bool -FarSubdivisionTables::compareVertices( HbrVertex const * x, HbrVertex const * y ) { - - // Masks of the parent vertex decide for the current vertex. - HbrVertex * px=x->GetParentVertex(), - * py=y->GetParentVertex(); - - assert( (getMaskRanking(px->GetMask(false), px->GetMask(true) )!=0xFF) and - (getMaskRanking(py->GetMask(false), py->GetMask(true) )!=0xFF) ); - - return getMaskRanking(px->GetMask(false), px->GetMask(true) ) < - getMaskRanking(py->GetMask(false), py->GetMask(true) ); -} - -template int -FarSubdivisionTables::GetFirstVertexOffset( int level ) const { +template int +FarSubdivisionTables::GetFirstVertexOffset( int level ) const { assert(level>=0 and level<=(int)_vertsOffsets.size()); return _vertsOffsets[level]; } -template int -FarSubdivisionTables::GetNumFaceVertices( int level ) const { +template int +FarSubdivisionTables::GetNumFaceVertices( int level ) const { assert(level>=0 and level<=(int)_batches.size()); return _batches[level-1].kernelF; } -template int -FarSubdivisionTables::GetNumEdgeVertices( int level ) const { +template int +FarSubdivisionTables::GetNumEdgeVertices( int level ) const { assert(level>=0 and level<=(int)_batches.size()); return _batches[level-1].kernelE; } -template int -FarSubdivisionTables::GetNumVertexVertices( int level ) const { +template int +FarSubdivisionTables::GetNumVertexVertices( int level ) const { assert(level>=0 and level<=(int)_batches.size()); if (level==0) return _mesh->GetNumCoarseVertices(); @@ -310,8 +281,8 @@ FarSubdivisionTables::GetNumVertexVertices( int level ) const { _batches[level-1].kernelA2.second)); } -template int -FarSubdivisionTables::GetNumVertices( int level ) const { +template int +FarSubdivisionTables::GetNumVertices( int level ) const { assert(level>=0 and level<=(int)_batches.size()); if (level==0) return GetNumVertexVertices(0); @@ -321,8 +292,8 @@ FarSubdivisionTables::GetNumVertices( int level ) const { GetNumVertexVertices(level); } -template int -FarSubdivisionTables::GetMemoryUsed() const { +template int +FarSubdivisionTables::GetMemoryUsed() const { return _E_IT.GetMemoryUsed()+ _E_W.GetMemoryUsed()+ _V_ITa.GetMemoryUsed()+ diff --git a/opensubdiv/far/vertexEditTables.h b/opensubdiv/far/vertexEditTables.h index b2098215..49966363 100644 --- a/opensubdiv/far/vertexEditTables.h +++ b/opensubdiv/far/vertexEditTables.h @@ -62,31 +62,57 @@ #include #include "../version.h" -#include "../far/table.h" -#include "../far/dispatcher.h" -#include "../hbr/vertexEdit.h" -template class HbrFace; -template class HbrHalfedge; -template class HbrVertex; -template class HbrMesh; +#include "../far/table.h" namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { -template class FarMesh; -template class FarMeshFactory; +template class FarMesh; +template class FarDispatcher; -template class FarVertexEditTables { +class FarVertexEdit { public: - FarVertexEditTables( FarMesh * mesh, int maxlevel); - - // type of edit operation. This enum matches to HbrHiearachicalEdit::Operation + // Type of edit operation - equivalent to HbrHiearachicalEdit::Operation enum Operation { Set, Add + // Note : subtract edits are converted to Add edits for better serialization }; + // Get the type of operation + Operation GetOperation() const { return _op; } + + // Return index of variable this edit applies to + int GetIndex() const { return _index; } + + // Return width of the variable + int GetWidth() const { return _width; } + + // Get the numerical value of the edit + const float* GetEdit() const { return _edit; } + +private: + template friend class FarVertexEditTables; + + FarVertexEdit(Operation op, int index, int width) : + _op(op), _edit(0), _index(index), _width(width) + { } + + void SetEdit(float const * edit) { _edit=edit; } + + Operation _op; + float const * _edit; + int _index, + _width; +}; + +template class FarVertexEditTables { +public: + FarVertexEditTables( FarMesh * mesh, int maxlevel); + + // Note : Subtract type edits are converted into Adds in order to save kernel calls. + // Compute the positions of edited vertices void Apply(int level, void * clientdata=0) const; @@ -94,117 +120,111 @@ public: return (int)_batches.size(); } - // this class holds a batch for vertex edit. each batch has unique index/width/operation - class VertexEdit { + // This class holds an array of edits. each batch has unique index/width/operation + class VertexEditBatch { public: - VertexEdit(int index, int width, Operation operation); + VertexEditBatch(int index, int width, FarVertexEdit::Operation operation); // copy vertex id and edit values into table void Append(int level, int vertexID, const float *values, bool negate); // Compute-kernel applied to vertices - void ApplyVertexEdit(U * vsrc, int level) const; + void ApplyVertexEdits(U * vsrc, int level) const; // Edit tables accessors // Returns the edit offset table - FarTable const & Get_Offsets() const { return _offsets; } + FarTable const & GetVertexIndices() const { return _vertIndices; } // Returns the edit values table - FarTable const & Get_Values() const { return _values; } + FarTable const & GetValues() const { return _edits; } - Operation GetOperation() const { return _operation; } + FarVertexEdit::Operation GetOperation() const { return _op; } - int GetPrimvarOffset() const { return _index; } + int GetPrimvarIndex() const { return _primvarIndex; } - int GetPrimvarWidth() const { return _width; } + int GetPrimvarWidth() const { return _primvarWidth; } private: - friend class FarMeshFactory; + template friend struct FarVertexEditTablesFactory; + friend class FarDispatcher; - FarTable _offsets; // absolute vertex index array for edits - FarTable _values; // edit values array + FarTable _vertIndices; // absolute vertex index array for edits + FarTable _edits; // edit values array - int _index; // primvar offset in vertex - int _width; // numElements per vertex in values - Operation _operation; // edit operation (Set, Add) + int _primvarIndex, // primvar offset in vertex + _primvarWidth; // numElements per vertex in values + FarVertexEdit::Operation _op; // edit operation (Set, Add) }; - VertexEdit const & GetBatch(int index) const { + VertexEditBatch const & GetBatch(int index) const { return _batches[index]; } -protected: - friend class FarMeshFactory; - friend class FarDispatcher; +private: + template friend struct FarVertexEditTablesFactory; + friend class FarDispatcher; - // Compute-kernel applied to vertices - void editVertex(int level, void *clientdata) const; + // Compute-kernel that applies the edits + void computeVertexEdits(int level, void *clientdata) const; // mesh that owns this vertexEditTable - FarMesh * _mesh; + FarMesh * _mesh; - std::vector _batches; + std::vector _batches; }; -template -FarVertexEditTables::VertexEdit::VertexEdit(int index, int width, Operation operation) : - _index(index), - _width(width), - _operation(operation) { +template +FarVertexEditTables::VertexEditBatch::VertexEditBatch(int index, int width, FarVertexEdit::Operation op) : + _primvarIndex(index), + _primvarWidth(width), + _op(op) { } -template +template void -FarVertexEditTables::VertexEdit::ApplyVertexEdit(U * vsrc, int level) const +FarVertexEditTables::VertexEditBatch::ApplyVertexEdits(U * vsrc, int level) const { - int n = _offsets.GetNumElements(level-1); - const unsigned int * offsets = _offsets[level-1]; - const float * values = _values[level-1]; + int n = _vertIndices.GetNumElements(level-1); + const unsigned int * offsets = _vertIndices[level-1]; + const float * values = _edits[level-1]; + + FarVertexEdit edit( GetOperation(), GetPrimvarIndex(), GetPrimvarWidth() ); for(int i=0; iApplyVertexEditAdd(const float *), vdst->ApplyVertexEditSet(const float *) - if (_operation == FarVertexEditTables::Set) { - HbrVertexEdit vedit(0, 0, 0, 0, 0, _width, false, HbrVertexEdit::Set, const_cast(&values[i*_width])); - vdst->ApplyVertexEdit(vedit); - } else { - HbrVertexEdit vedit(0, 0, 0, 0, 0, _width, false, HbrVertexEdit::Add, const_cast(&values[i*_width])); - vdst->ApplyVertexEdit(vedit); - } + edit.SetEdit( const_cast(&values[i*GetPrimvarWidth()]) ); + vdst->ApplyVertexEdit( edit ); } } -template -FarVertexEditTables::FarVertexEditTables( FarMesh * mesh, int maxlevel) : +template +FarVertexEditTables::FarVertexEditTables( FarMesh * mesh, int maxlevel) : _mesh(mesh) { } -template void -FarVertexEditTables::Apply( int level, void * clientdata ) const { +template void +FarVertexEditTables::Apply( int level, void * clientdata ) const { assert(this->_mesh and level>0); - FarDispatcher const * dispatch = this->_mesh->GetDispatcher(); + FarDispatcher const * dispatch = this->_mesh->GetDispatcher(); assert(dispatch); - dispatch->ApplyVertexEdit(this->_mesh, 0, level, clientdata); + dispatch->ApplyVertexEdits(this->_mesh, 0, level, clientdata); } -template void -FarVertexEditTables::editVertex(int level, void *clientdata) const { +template void +FarVertexEditTables::computeVertexEdits(int level, void *clientdata) const { assert(this->_mesh); U * vsrc = &this->_mesh->GetVertices().at(0); - for(int i=0; i<(int)_batches.size(); ++i) { - _batches[i].ApplyVertexEdit(vsrc, level); - } + for(int i=0; i<(int)_batches.size(); ++i) + _batches[i].ApplyVertexEdits(vsrc, level); } } // end namespace OPENSUBDIV_VERSION diff --git a/opensubdiv/far/vertexEditTablesFactory.h b/opensubdiv/far/vertexEditTablesFactory.h new file mode 100644 index 00000000..452c9241 --- /dev/null +++ b/opensubdiv/far/vertexEditTablesFactory.h @@ -0,0 +1,225 @@ +// +// Copyright (C) Pixar. All rights reserved. +// +// This license governs use of the accompanying software. If you +// use the software, you accept this license. If you do not accept +// the license, do not use the software. +// +// 1. Definitions +// The terms "reproduce," "reproduction," "derivative works," and +// "distribution" have the same meaning here as under U.S. +// copyright law. A "contribution" is the original software, or +// any additions or changes to the software. +// A "contributor" is any person or entity that distributes its +// contribution under this license. +// "Licensed patents" are a contributor's patent claims that read +// directly on its contribution. +// +// 2. Grant of Rights +// (A) Copyright Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free copyright license to reproduce its contribution, +// prepare derivative works of its contribution, and distribute +// its contribution or any derivative works that you create. +// (B) Patent Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free license under its licensed patents to make, have +// made, use, sell, offer for sale, import, and/or otherwise +// dispose of its contribution in the software or derivative works +// of the contribution in the software. +// +// 3. Conditions and Limitations +// (A) No Trademark License- This license does not grant you +// rights to use any contributor's name, logo, or trademarks. +// (B) If you bring a patent claim against any contributor over +// patents that you claim are infringed by the software, your +// patent license from such contributor to the software ends +// automatically. +// (C) If you distribute any portion of the software, you must +// retain all copyright, patent, trademark, and attribution +// notices that are present in the software. +// (D) If you distribute any portion of the software in source +// code form, you may do so only under this license by including a +// complete copy of this license with your distribution. If you +// distribute any portion of the software in compiled or object +// code form, you may only do so under a license that complies +// with this license. +// (E) The software is licensed "as-is." You bear the risk of +// using it. The contributors give no express warranties, +// guarantees or conditions. You may have additional consumer +// rights under your local laws which this license cannot change. +// To the extent permitted under your local laws, the contributors +// exclude the implied warranties of merchantability, fitness for +// a particular purpose and non-infringement. +// +#ifndef FAR_VERTEX_EDIT_TABLES_FACTORY_H +#define FAR_VERTEX_EDIT_TABLES_FACTORY_H + +#include +#include + +#include "../version.h" + +#include "../hbr/vertexEdit.h" + +#include "../far/vertexEditTables.h" + +namespace OpenSubdiv { +namespace OPENSUBDIV_VERSION { + +// A specialized factory for FarVertexEditTables +// Separating the factory allows us to isolate Far data structures from Hbr dependencies. +// +template struct FarVertexEditTablesFactory { + + static bool compareEdits(HbrVertexEdit const *a, HbrVertexEdit const *b); + + static FarVertexEditTables * Create( FarMeshFactory const * factory, FarMesh * mesh, int maxlevel ); +}; + +template bool +FarVertexEditTablesFactory::compareEdits(HbrVertexEdit const *a, HbrVertexEdit const *b) { + + return a->GetNSubfaces() < b->GetNSubfaces(); +} + + +template FarVertexEditTables * +FarVertexEditTablesFactory::Create( FarMeshFactory const * factory, FarMesh * mesh, int maxlevel ) { + + assert( factory and mesh ); + + FarVertexEditTables * result = new FarVertexEditTables(mesh, maxlevel); + + std::vector*> const & hEdits = factory->_hbrMesh->GetHierarchicalEdits(); + + std::vector const *> vertexEdits; + vertexEdits.reserve(hEdits.size()); + + for (int i=0; i<(int)hEdits.size(); ++i) { + HbrVertexEdit *vedit = dynamic_cast *>(hEdits[i]); + if (vedit) { + int editlevel = vedit->GetNSubfaces(); + if (editlevel > maxlevel) + continue; // far table doesn't contain such level + + vertexEdits.push_back(vedit); + } + } + + // sort vertex edits by level + std::sort(vertexEdits.begin(), vertexEdits.end(), compareEdits); + + // First pass : count batches based on operation and primvar being edited + std::vector batchIndices; + std::vector batchSizes; + for(int i=0; i<(int)vertexEdits.size(); ++i) { + HbrVertexEdit const *vedit = vertexEdits[i]; + + // translate operation enum + FarVertexEdit::Operation op = (vedit->GetOperation() == HbrHierarchicalEdit::Set) ? + FarVertexEdit::Set : FarVertexEdit::Add; + + // determine which batch this edit belongs to (create it if necessary) + // XXXX manuelk - if the number of edits becomes large, we may need to switch this + // to a map. + int batchIndex = -1; + for(int i = 0; i<(int)result->_batches.size(); ++i) { + if(result->_batches[i]._primvarIndex == vedit->GetIndex() && + result->_batches[i]._primvarWidth == vedit->GetWidth() && + result->_batches[i]._op == op) { + batchIndex = i; + break; + } + } + if (batchIndex == -1) { + // create new batch + batchIndex = (int)result->_batches.size(); + result->_batches.push_back(typename FarVertexEditTables::VertexEditBatch(vedit->GetIndex(), vedit->GetWidth(), op)); + batchSizes.push_back(0); + } + batchSizes[batchIndex]++; + batchIndices.push_back(batchIndex); + } + + // Second pass : populate the batches + int numBatches = result->GetNumBatches(); + for(int i=0; i_batches[i]._vertIndices.SetMaxLevel(maxlevel+1); + result->_batches[i]._edits.SetMaxLevel(maxlevel+1); + result->_batches[i]._vertIndices.Resize(batchSizes[i]); + result->_batches[i]._edits.Resize(batchSizes[i] * result->_batches[i].GetPrimvarWidth()); + } + + // Resolve vertexedits path to absolute offset and put them into corresponding batch + std::vector currentLevels(numBatches); + std::vector currentCounts(numBatches); + for(int i=0; i<(int)vertexEdits.size(); ++i){ + HbrVertexEdit const *vedit = vertexEdits[i]; + + HbrFace * f = factory->_hbrMesh->GetFace(vedit->GetFaceID()); + + int level = vedit->GetNSubfaces(); + for (int j=0; jGetChild(vedit->GetSubface(j)); + + int vertexID = f->GetVertex(vedit->GetVertexID())->GetID(); + + // Remap vertex ID + vertexID = factory->_remapTable[vertexID]; + + int batchIndex = batchIndices[i]; + int & batchLevel = currentLevels[batchIndex]; + int & batchCount = currentCounts[batchIndex]; + typename FarVertexEditTables::VertexEditBatch &batch = result->_batches[batchIndex]; + + // Fill marker for skipped levels if exists + while(currentLevels[batchIndex] < level-1) { + batch._vertIndices.SetMarker(batchLevel+1, &batch._vertIndices[batchLevel][batchCount]); + batch._edits.SetMarker(batchLevel+1, &batch._edits[batchLevel][batchCount*batch.GetPrimvarWidth()]); + batchLevel++; + batchCount = 0; + } + + // Set absolute vertex index + batch._vertIndices[level-1][batchCount] = vertexID; + + // Copy edit values : Subtract edits are optimized into Add edits (fewer batches) + const float *edit = vedit->GetEdit(); + + bool negate = (vedit->GetOperation() == HbrHierarchicalEdit::Subtract); + + for(int i=0; i::VertexEditBatch &batch = result->_batches[i]; + int & batchLevel = currentLevels[i]; + int & batchCount = currentCounts[i]; + + // fill marker for rest levels if exists + while(batchLevel < maxlevel) { + batch._vertIndices.SetMarker(batchLevel+1, &batch._vertIndices[batchLevel][batchCount]); + batch._edits.SetMarker(batchLevel+1, &batch._edits[batchLevel][batchCount*batch.GetPrimvarWidth()]); + batchLevel++; + batchCount = 0; + } + } + + return result; +} + +} // end namespace OPENSUBDIV_VERSION +using namespace OPENSUBDIV_VERSION; + +} // end namespace OpenSubdiv + +#endif /* FAR_VERTEX_EDIT_TABLES_FACTORY_H */ diff --git a/opensubdiv/osd/clDispatcher.cpp b/opensubdiv/osd/clDispatcher.cpp index e2e6e3ab..bfd03458 100644 --- a/opensubdiv/osd/clDispatcher.cpp +++ b/opensubdiv/osd/clDispatcher.cpp @@ -75,6 +75,7 @@ #include #include +#include #define CL_CHECK_ERROR(x, ...) { if(x != CL_SUCCESS) { printf("ERROR %d : ", x); printf(__VA_ARGS__);} } diff --git a/opensubdiv/osd/clDispatcher.h b/opensubdiv/osd/clDispatcher.h index 4189b285..a29377c9 100644 --- a/opensubdiv/osd/clDispatcher.h +++ b/opensubdiv/osd/clDispatcher.h @@ -115,7 +115,7 @@ public: virtual void ApplyLoopVertexVerticesKernelA(FarMesh * mesh, int offset, bool pass, int level, int start, int end, void * data) const; - virtual void ApplyVertexEdit(FarMesh *mesh, int offset, int level, void * clientdata) const {} + virtual void ApplyVertexEdits(FarMesh *mesh, int offset, int level, void * clientdata) const {} virtual void CopyTable(int tableIndex, size_t size, const void *ptr); diff --git a/opensubdiv/osd/cpuDispatcher.cpp b/opensubdiv/osd/cpuDispatcher.cpp index 0fe827a2..36a8360e 100644 --- a/opensubdiv/osd/cpuDispatcher.cpp +++ b/opensubdiv/osd/cpuDispatcher.cpp @@ -60,7 +60,6 @@ #include "../osd/cpuDispatcher.h" #include "../osd/cpuKernel.h" -#include #include #include @@ -292,19 +291,18 @@ OsdCpuKernelDispatcher::ApplyLoopVertexVerticesKernelA( FarMesh * mes } void -OsdCpuKernelDispatcher::ApplyVertexEdit(FarMesh *mesh, int offset, int level, void * clientdata) const { - +OsdCpuKernelDispatcher::ApplyVertexEdits(FarMesh *mesh, int offset, int level, void * clientdata) const { for (int i=0; i<(int)_edits.size(); ++i) { const VertexEditArrayInfo &info = _edits[i]; - if (info.operation == FarVertexEditTables::Add) { + if (info.operation == FarVertexEdit::Add) { editVertexAdd(_vdesc, GetVertexBuffer(), info.primVarOffset, info.primVarWidth, info.numEdits[level-1], (int*)_editTables[i*2+0].ptr + info.offsetOffsets[level-1], (float*)_editTables[i*2+1].ptr + info.valueOffsets[level-1]); - } else if (info.operation == FarVertexEditTables::Set) { -//XXX:TODO editVertexSet(_vdesc, GetVertexBuffer(), info.primVarOffset, info.primVarWidth, info.numEdits[level], -// (int*)_editTables[i*2+0].ptr + info.offsetOffsets[level], -// (float*)_editTables[i*2+1].ptr + info.valueOffsets[level]); + } else if (info.operation == FarVertexEdit::Set) { + editVertexSet(_vdesc, GetVertexBuffer(), info.primVarOffset, info.primVarWidth, info.numEdits[level], + (int*)_editTables[i*2+0].ptr + info.offsetOffsets[level], + (float*)_editTables[i*2+1].ptr + info.valueOffsets[level]); } } } diff --git a/opensubdiv/osd/cpuDispatcher.h b/opensubdiv/osd/cpuDispatcher.h index 49af2b4e..1ef1eb8e 100644 --- a/opensubdiv/osd/cpuDispatcher.h +++ b/opensubdiv/osd/cpuDispatcher.h @@ -95,7 +95,7 @@ public: virtual void ApplyLoopVertexVerticesKernelA(FarMesh * mesh, int offset, bool pass, int level, int start, int end, void * data) const; - virtual void ApplyVertexEdit(FarMesh *mesh, int offset, int level, void * clientdata) const; + virtual void ApplyVertexEdits(FarMesh *mesh, int offset, int level, void * clientdata) const; virtual void CopyTable(int tableIndex, size_t size, const void *ptr); diff --git a/opensubdiv/osd/cpuKernel.cpp b/opensubdiv/osd/cpuKernel.cpp index 56a80401..f52ccb9c 100644 --- a/opensubdiv/osd/cpuKernel.cpp +++ b/opensubdiv/osd/cpuKernel.cpp @@ -257,5 +257,15 @@ void editVertexAdd(const VertexDescriptor *vdesc, float *vertex, int primVarOffs } } +void editVertexSet(const VertexDescriptor *vdesc, float *vertex, int primVarOffset, int primVarWidth, int vertexCount, const int *editIndices, const float *editValues) { + +#ifdef _OPENMP +#pragma omp parallel for +#endif + for (int i = 0; i < vertexCount; i++) { + vdesc->ApplyVertexEditSet(vertex, primVarOffset, primVarWidth, editIndices[i], &editValues[i*primVarWidth]); + } +} + } // end namespace OPENSUBDIV_VERSION } // end namespace OpenSubdiv diff --git a/opensubdiv/osd/cpuKernel.h b/opensubdiv/osd/cpuKernel.h index 45913bba..592e43b0 100644 --- a/opensubdiv/osd/cpuKernel.h +++ b/opensubdiv/osd/cpuKernel.h @@ -58,8 +58,6 @@ #define OSD_CPU_KERNEL_H #include "../version.h" -#include - namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { @@ -99,6 +97,13 @@ struct VertexDescriptor { } } + void ApplyVertexEditSet(float *vertex, int primVarOffset, int primVarWidth, int editIndex, const float *editValues) const { + int d = editIndex * numVertexElements + primVarOffset; + for (int i = 0; i < primVarWidth; ++i) { + vertex[d++] = editValues[i]; + } + } + int numVertexElements; int numVaryingElements; }; diff --git a/opensubdiv/osd/cudaDispatcher.cpp b/opensubdiv/osd/cudaDispatcher.cpp index f1abd252..4f9c13e6 100644 --- a/opensubdiv/osd/cudaDispatcher.cpp +++ b/opensubdiv/osd/cudaDispatcher.cpp @@ -330,17 +330,17 @@ OsdCudaKernelDispatcher::ApplyLoopVertexVerticesKernelA(FarMesh * mes } void -OsdCudaKernelDispatcher::ApplyVertexEdit(FarMesh *mesh, int offset, int level, void * clientdata) const { +OsdCudaKernelDispatcher::ApplyVertexEdits(FarMesh *mesh, int offset, int level, void * clientdata) const { for (int i=0; i<(int)_edits.size(); ++i) { const VertexEditArrayInfo &info = _edits[i]; - if (info.operation == FarVertexEditTables::Add) { + if (info.operation == FarVertexEdit::Add) { OsdCudaEditVertexAdd(_deviceVertices, _numVertexElements-3, info.primVarOffset, info.primVarWidth, info.numEdits[level-1], (int*)_editTables[i*2+0].devicePtr + info.offsetOffsets[level-1], (float*)_editTables[i*2+1].devicePtr + info.valueOffsets[level-1]); - } else if (info.operation == FarVertexEditTables::Set) { - // XXX: + } else if (info.operation == FarVertexEdit::Set) { + // XXXX TODO } } } diff --git a/opensubdiv/osd/cudaDispatcher.h b/opensubdiv/osd/cudaDispatcher.h index cce912e6..8bc19027 100644 --- a/opensubdiv/osd/cudaDispatcher.h +++ b/opensubdiv/osd/cudaDispatcher.h @@ -115,7 +115,7 @@ public: virtual void ApplyLoopVertexVerticesKernelA(FarMesh * mesh, int offset, bool pass, int level, int start, int end, void * data) const; - virtual void ApplyVertexEdit(FarMesh *mesh, int offset, int level, void * clientdata) const; + virtual void ApplyVertexEdits(FarMesh *mesh, int offset, int level, void * clientdata) const; virtual void CopyTable(int tableIndex, size_t size, const void *ptr); diff --git a/opensubdiv/osd/glslDispatcher.h b/opensubdiv/osd/glslDispatcher.h index e958cd7b..7ac929f0 100644 --- a/opensubdiv/osd/glslDispatcher.h +++ b/opensubdiv/osd/glslDispatcher.h @@ -98,7 +98,7 @@ public: virtual void ApplyLoopVertexVerticesKernelA(FarMesh * mesh, int offset, bool pass, int level, int start, int end, void * data) const; - virtual void ApplyVertexEdit(FarMesh *mesh, int offset, int level, void * clientdata) const {} + virtual void ApplyVertexEdits(FarMesh *mesh, int offset, int level, void * clientdata) const {} virtual void CopyTable(int tableIndex, size_t size, const void *ptr); diff --git a/opensubdiv/osd/mesh.cpp b/opensubdiv/osd/mesh.cpp index 7335b9ae..3d6c55c9 100644 --- a/opensubdiv/osd/mesh.cpp +++ b/opensubdiv/osd/mesh.cpp @@ -125,9 +125,9 @@ OsdMesh::createEditTables( FarVertexEditTables const *editTables ) { _dispatcher->AllocateEditTables(numEditBatches); for (int i=0; i::VertexEdit & edit = editTables->GetBatch(i); - _dispatcher->UpdateEditTable(i, edit.Get_Offsets(), edit.Get_Values(), - edit.GetOperation(), edit.GetPrimvarOffset(), edit.GetPrimvarWidth()); + const FarVertexEditTables::VertexEditBatch & edit = editTables->GetBatch(i); + _dispatcher->UpdateEditTable(i, edit.GetVertexIndices(), edit.GetValues(), + edit.GetOperation(), edit.GetPrimvarIndex(), edit.GetPrimvarWidth()); } } diff --git a/opensubdiv/osd/mesh.h b/opensubdiv/osd/mesh.h index 3e8484de..1416ae75 100644 --- a/opensubdiv/osd/mesh.h +++ b/opensubdiv/osd/mesh.h @@ -77,7 +77,7 @@ typedef HbrVertex OsdHbrVertex; typedef HbrFace OsdHbrFace; typedef HbrHalfedge OsdHbrHalfedge; -template class FarMesh; +template class FarMesh; class OsdKernelDispatcher; class OsdElementArrayBuffer; diff --git a/opensubdiv/osd/vertex.h b/opensubdiv/osd/vertex.h index 4d3da386..95469646 100644 --- a/opensubdiv/osd/vertex.h +++ b/opensubdiv/osd/vertex.h @@ -65,18 +65,27 @@ namespace OPENSUBDIV_VERSION { template class HbrVertexEdit; template class HbrMovingVertexEdit; +class FarVertexEdit; class OsdVertex { public: OsdVertex() {} - OsdVertex(int index) {} - OsdVertex(const OsdVertex &src) {} - void AddWithWeight(const OsdVertex & i, float weight, void * = 0) {} + OsdVertex(int index) {} + + OsdVertex(OsdVertex const & src) {} + + void AddWithWeight(OsdVertex const & i, float weight, void * = 0) {} + void AddVaryingWithWeight(const OsdVertex & i, float weight, void * = 0) {} + void Clear(void * = 0) {} - void ApplyVertexEdit(const HbrVertexEdit &) { } - void ApplyMovingVertexEdit(const HbrMovingVertexEdit &) { } + + void ApplyVertexEdit(HbrVertexEdit const &) { } + + void ApplyVertexEdit(FarVertexEdit const &) { } + + void ApplyMovingVertexEdit(HbrMovingVertexEdit const &) { } }; } // end namespace OPENSUBDIV_VERSION diff --git a/regression/common/shape_utils.h b/regression/common/shape_utils.h index b9f8f888..3cd6e66f 100644 --- a/regression/common/shape_utils.h +++ b/regression/common/shape_utils.h @@ -57,6 +57,10 @@ #ifndef SHAPE_UTILS_H #define SHAPE_UTILS_H +#include +#include +#include +#include #include #include diff --git a/regression/far_regression/main.cpp b/regression/far_regression/main.cpp index 954423c0..d20366d4 100644 --- a/regression/far_regression/main.cpp +++ b/regression/far_regression/main.cpp @@ -96,40 +96,56 @@ struct xyzVV { ~xyzVV( ) { } - void AddWithWeight(const xyzVV& src, float weight, void * =0 ) { + void AddWithWeight(const xyzVV& src, float weight, void * =0 ) { _pos[0]+=weight*src._pos[0]; _pos[1]+=weight*src._pos[1]; _pos[2]+=weight*src._pos[2]; } - void AddVaryingWithWeight(const xyzVV& , float, void * =0 ) { } + void AddVaryingWithWeight(const xyzVV& , float, void * =0 ) { } - void Clear( void * =0 ) { _pos[0]=_pos[1]=_pos[2]=0.0f; } + void Clear( void * =0 ) { _pos[0]=_pos[1]=_pos[2]=0.0f; } - void SetPosition(float x, float y, float z) { _pos[0]=x; _pos[1]=y; _pos[2]=z; } + void SetPosition(float x, float y, float z) { _pos[0]=x; _pos[1]=y; _pos[2]=z; } - void ApplyVertexEdit(const OpenSubdiv::HbrVertexEdit & edit) { - const float *src = edit.GetEdit(); - switch(edit.GetOperation()) { - case OpenSubdiv::HbrHierarchicalEdit::Set: - _pos[0] = src[0]; - _pos[1] = src[1]; - _pos[2] = src[2]; - break; - case OpenSubdiv::HbrHierarchicalEdit::Add: - _pos[0] += src[0]; - _pos[1] += src[1]; - _pos[2] += src[2]; - break; - case OpenSubdiv::HbrHierarchicalEdit::Subtract: - _pos[0] -= src[0]; - _pos[1] -= src[1]; - _pos[2] -= src[2]; - break; - } - } + void ApplyVertexEdit(const OpenSubdiv::HbrVertexEdit & edit) { + const float *src = edit.GetEdit(); + switch(edit.GetOperation()) { + case OpenSubdiv::HbrHierarchicalEdit::Set: + _pos[0] = src[0]; + _pos[1] = src[1]; + _pos[2] = src[2]; + break; + case OpenSubdiv::HbrHierarchicalEdit::Add: + _pos[0] += src[0]; + _pos[1] += src[1]; + _pos[2] += src[2]; + break; + case OpenSubdiv::HbrHierarchicalEdit::Subtract: + _pos[0] -= src[0]; + _pos[1] -= src[1]; + _pos[2] -= src[2]; + break; + } + } - void ApplyMovingVertexEdit(const OpenSubdiv::HbrMovingVertexEdit &) { } + void ApplyVertexEdit(OpenSubdiv::FarVertexEdit const & edit) { + const float *src = edit.GetEdit(); + switch(edit.GetOperation()) { + case OpenSubdiv::FarVertexEdit::Set: + _pos[0] = src[0]; + _pos[1] = src[1]; + _pos[2] = src[2]; + break; + case OpenSubdiv::FarVertexEdit::Add: + _pos[0] += src[0]; + _pos[1] += src[1]; + _pos[2] += src[2]; + break; + } + } + + void ApplyMovingVertexEdit(const OpenSubdiv::HbrMovingVertexEdit &) { } const float * GetPos() const { return _pos; } diff --git a/regression/osd_regression/main.cpp b/regression/osd_regression/main.cpp index 8ac8cbbe..490ffd92 100644 --- a/regression/osd_regression/main.cpp +++ b/regression/osd_regression/main.cpp @@ -149,6 +149,22 @@ struct xyzVV { } } + void ApplyVertexEdit(OpenSubdiv::FarVertexEdit const & edit) { + const float *src = edit.GetEdit(); + switch(edit.GetOperation()) { + case OpenSubdiv::FarVertexEdit::Set: + _pos[0] = src[0]; + _pos[1] = src[1]; + _pos[2] = src[2]; + break; + case OpenSubdiv::FarVertexEdit::Add: + _pos[0] += src[0]; + _pos[1] += src[1]; + _pos[2] += src[2]; + break; + } + } + void ApplyMovingVertexEdit(const OpenSubdiv::HbrMovingVertexEdit &) { } const float * GetPos() const { return _pos; } @@ -356,6 +372,10 @@ int main(int argc, char ** argv) { #define test_catmark_tent #define test_catmark_tent_creases0 #define test_catmark_tent_creases1 +#define test_catmark_square_hedit0 +#define test_catmark_square_hedit1 +#define test_catmark_square_hedit2 +#define test_catmark_square_hedit3 #define test_loop_triangle_edgeonly #define test_loop_triangle_edgecorner @@ -458,6 +478,25 @@ int main(int argc, char ** argv) { total += checkMesh( "test_catmark_tent_creases1", catmark_tent_creases1, levels ); #endif +#ifdef test_catmark_square_hedit0 +#include "../shapes/catmark_square_hedit0.h" + total += checkMesh( "test_catmark_square_hedit0", catmark_square_hedit0, levels ); +#endif + +#ifdef test_catmark_square_hedit1 +#include "../shapes/catmark_square_hedit1.h" + total += checkMesh( "test_catmark_square_hedit1", catmark_square_hedit1, levels ); +#endif + +#ifdef test_catmark_square_hedit2 +#include "../shapes/catmark_square_hedit2.h" + total += checkMesh( "test_catmark_square_hedit2", catmark_square_hedit2, levels ); +#endif + +#ifdef test_catmark_square_hedit3 +#include "../shapes/catmark_square_hedit3.h" + total += checkMesh( "test_catmark_square_hedit3", catmark_square_hedit3, levels ); +#endif #ifdef test_loop_triangle_edgeonly