This commit is contained in:
jcowles 2012-10-08 16:05:08 -07:00
commit a287869e9c
44 changed files with 3563 additions and 1197 deletions

View File

@ -311,3 +311,5 @@ add_subdirectory(opensubdiv)
add_subdirectory(regression)
add_subdirectory(examples)
add_subdirectory(documentation)

View File

@ -0,0 +1,76 @@
#
# 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.
#
find_package(Doxygen)
if (DOXYGEN_FOUND)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/OpenSubdiv.doxy ${CMAKE_CURRENT_BINARY_DIR}/OpenSubdiv.doxy @ONLY)
add_custom_target(doc
${DOXYGEN_EXECUTABLE}
${CMAKE_CURRENT_BINARY_DIR}/OpenSubdiv.doxy
WORKING_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen" VERBATIM
)
else()
message(WARNING
"Doxyen was not found : support for Doxygen automated API documentation is disabled.")
endif()

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

View File

@ -64,6 +64,10 @@
#endif
#include <osd/mutex.h>
#include <hbr/mesh.h>
#include <hbr/face.h>
#include <osd/vertex.h>
#include <osd/mesh.h>
#include <osd/elementArrayBuffer.h>
@ -618,6 +622,8 @@ createOsdMesh( const char * shape, int level, int kernel, Scheme scheme=kCatmark
if (g_elementArrayBuffer) delete g_elementArrayBuffer;
g_elementArrayBuffer = g_osdmesh->CreateElementArrayBuffer(level);
g_scheme = scheme;
// compute model bounding
float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX};
float max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};

View File

@ -65,6 +65,10 @@
#endif
#include <osd/mutex.h>
#include <hbr/mesh.h>
#include <hbr/face.h>
#include <osd/vertex.h>
#include <osd/mesh.h>
#include <osd/cpuDispatcher.h>

View File

@ -87,6 +87,12 @@
#include <maya/MStateManager.h>
#include <osd/mutex.h>
#include <hbr/mesh.h>
#include <hbr/bilinear.h>
#include <hbr/catmark.h>
#include <hbr/loop.h>
#include <osd/mesh.h>
#include <osd/pTexture.h>
#include <osd/cpuDispatcher.h>

View File

@ -55,12 +55,14 @@
// a particular purpose and non-infringement.
//
#include "hbrUtil.h"
#include <far/mesh.h>
#include <hbr/mesh.h>
#include <hbr/bilinear.h>
#include <hbr/loop.h>
#include <hbr/catmark.h>
#include <far/mesh.h>
#define OSD_ERROR printf // XXXX
OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices,

View File

@ -59,6 +59,9 @@
#include <vector>
#include <osd/mutex.h>
#include <hbr/mesh.h>
#include <osd/mesh.h>
extern "C" OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices,

View File

@ -87,6 +87,12 @@
#include <maya/MStateManager.h>
#include <osd/mutex.h>
#include <hbr/mesh.h>
#include <hbr/bilinear.h>
#include <hbr/catmark.h>
#include <hbr/loop.h>
#include <osd/mesh.h>
#include <osd/cpuDispatcher.h>
#include <osd/clDispatcher.h>

View File

@ -55,12 +55,14 @@
// a particular purpose and non-infringement.
//
#include "hbrUtil.h"
#include <far/mesh.h>
#include <hbr/mesh.h>
#include <hbr/bilinear.h>
#include <hbr/loop.h>
#include <hbr/catmark.h>
#include <far/mesh.h>
#define OSD_ERROR printf // XXXX
OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices,

View File

@ -59,6 +59,9 @@
#include <vector>
#include <osd/mutex.h>
#include <hbr/mesh.h>
#include <osd/mesh.h>
extern "C" OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices,

View File

@ -63,6 +63,12 @@
#endif
#include <osd/mutex.h>
#include <hbr/mesh.h>
#include <hbr/bilinear.h>
#include <hbr/catmark.h>
#include <hbr/face.h>
#include <osd/vertex.h>
#include <osd/mesh.h>
#include <osd/cpuDispatcher.h>

View File

@ -55,18 +55,22 @@
# a particular purpose and non-infringement.
#
set(H_FILES
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 ${H_FILES}
install( FILES ${PUBLIC_HEADER_FILES}
DESTINATION include/far
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ )

View File

@ -57,13 +57,8 @@
#ifndef FAR_BILINEAR_SUBDIVISION_TABLES_H
#define FAR_BILINEAR_SUBDIVISION_TABLES_H
#include "assert.h"
#include <cassert>
#include <vector>
#include <utility>
#include "../hbr/mesh.h"
#include "../hbr/bilinear.h"
#include "../version.h"
@ -72,37 +67,38 @@
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
// Bilinear tables store the indexing tables required in order to compute
// the refined positions of a mesh without the help of a hierarchical data
// structure. The advantage of this representation is its ability to be executed
// in a massively parallel environment without data dependencies.
//
template <class T, class U=T> class FarBilinearSubdivisionTables : public FarSubdivisionTables<T,U> {
/// \brief Bilinear subdivision scheme tables.
///
/// Bilinear tables store the indexing tables required in order to compute
/// the refined positions of a mesh without the help of a hierarchical data
/// structure. The advantage of this representation is its ability to be executed
/// in a massively parallel environment without data dependencies.
///
template <class U> class FarBilinearSubdivisionTables : public FarSubdivisionTables<U> {
public:
// Memory required to store the indexing tables
/// Memory required to store the indexing tables
virtual int GetMemoryUsed() const;
// Compute the positions of refined vertices using the specified kernels
/// Compute the positions of refined vertices using the specified kernels
virtual void Apply( int level, void * data=0 ) const;
// Table accessors
/// Face-vertices indexing table accessor
FarTable<unsigned int> const & Get_F_IT( ) const { return _F_IT; }
/// Face-vertices indexing table accessor
FarTable<int> const & Get_F_ITa( ) const { return _F_ITa; }
// Returns the number of indexing tables needed to represent this particular
// subdivision scheme.
/// Returns the number of indexing tables needed to represent this particular
/// subdivision scheme.
virtual int GetNumTables() const { return 7; }
private:
template <class X, class Y> friend struct FarBilinearSubdivisionTablesFactory;
friend class FarDispatcher<U>;
friend class FarMeshFactory<T,U>;
friend class FarDispatcher<T,U>;
// Constructor : build level table at depth 'level'
FarBilinearSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int level );
FarBilinearSubdivisionTables( FarMesh<U> * 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 +109,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<int> _F_ITa;
FarTable<unsigned int> _F_IT;
};
template <class T, class U> int
FarBilinearSubdivisionTables<T,U>::GetMemoryUsed() const {
return FarSubdivisionTables<T,U>::GetMemoryUsed()+
template <class U>
FarBilinearSubdivisionTables<U>::FarBilinearSubdivisionTables( FarMesh<U> * mesh, int maxlevel ) :
FarSubdivisionTables<U>(mesh, maxlevel),
_F_ITa(maxlevel+1),
_F_IT(maxlevel+1)
{ }
template <class U> int
FarBilinearSubdivisionTables<U>::GetMemoryUsed() const {
return FarSubdivisionTables<U>::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 <class T, class U>
FarBilinearSubdivisionTables<T,U>::FarBilinearSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int maxlevel ) :
FarSubdivisionTables<T,U>(mesh, maxlevel),
_F_ITa(maxlevel+1),
_F_IT(maxlevel+1)
{
std::vector<int> 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<T,U>::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<T> * v = factory._faceVertsList[level][i];
assert(v);
HbrFace<T> * 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; j<valence; ++j)
F_IT[offset++] = remap[f->GetVertex(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<T> * v = factory._edgeVertsList[level][i];
assert(v);
HbrHalfedge<T> * 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<T> * 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 <class T, class U> void
FarBilinearSubdivisionTables<T,U>::Apply( int level, void * clientdata ) const {
template <class U> void
FarBilinearSubdivisionTables<U>::Apply( int level, void * clientdata ) const {
assert(this->_mesh and level>0);
typename FarSubdivisionTables<T,U>::VertexKernelBatch const * batch = & (this->_batches[level-1]);
typename FarSubdivisionTables<U>::VertexKernelBatch const * batch = & (this->_batches[level-1]);
FarDispatcher<T,U> const * dispatch = this->_mesh->GetDispatcher();
FarDispatcher<U> const * dispatch = this->_mesh->GetDispatcher();
assert(dispatch);
int offset = this->GetFirstVertexOffset(level);
@ -256,8 +156,8 @@ FarBilinearSubdivisionTables<T,U>::Apply( int level, void * clientdata ) const {
// Face-vertices compute Kernel - completely re-entrant
//
template <class T, class U> void
FarBilinearSubdivisionTables<T,U>::computeFacePoints( int offset, int level, int start, int end, void * clientdata ) const {
template <class U> void
FarBilinearSubdivisionTables<U>::computeFacePoints( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh);
@ -286,8 +186,8 @@ FarBilinearSubdivisionTables<T,U>::computeFacePoints( int offset, int level, int
// Edge-vertices compute Kernel - completely re-entrant
//
template <class T, class U> void
FarBilinearSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const {
template <class U> void
FarBilinearSubdivisionTables<U>::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh);
@ -315,8 +215,8 @@ FarBilinearSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, in
// Vertex-vertices compute Kernel - completely re-entrant
//
template <class T, class U> void
FarBilinearSubdivisionTables<T,U>::computeVertexPoints( int offset, int level, int start, int end, void * clientdata ) const {
template <class U> void
FarBilinearSubdivisionTables<U>::computeVertexPoints( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh);

View File

@ -0,0 +1,178 @@
//
// 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 <cassert>
#include <vector>
#include "../version.h"
#include "../far/bilinearSubdivisionTables.h"
#include "../far/meshFactory.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
template <class T, class U> class FarMeshFactory;
/// \brief A specialized factory for FarBilinearSubdivisionTables
///
/// Separating the factory allows us to isolate Far data structures from Hbr dependencies.
///
template <class T, class U> struct FarBilinearSubdivisionTablesFactory {
/// Creates a FarBilinearSubdivisiontables instance.
static FarBilinearSubdivisionTables<U> * Create( FarMeshFactory<T,U> const * factory, FarMesh<U> * mesh, int maxlevel );
};
template <class T, class U> FarBilinearSubdivisionTables<U> *
FarBilinearSubdivisionTablesFactory<T,U>::Create( FarMeshFactory<T,U> const * factory, FarMesh<U> * mesh, int maxlevel ) {
assert( factory and mesh );
FarBilinearSubdivisionTables<U> * result = new FarBilinearSubdivisionTables<U>(mesh, maxlevel);
std::vector<int> 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<U>::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<T> * v = factory->_faceVertsList[level][i];
assert(v);
HbrFace<T> * 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; j<valence; ++j)
F_IT[offset++] = remap[f->GetVertex(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<T> * v = factory->_edgeVertsList[level][i];
assert(v);
HbrHalfedge<T> * 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<T> * 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 */

View File

@ -57,12 +57,8 @@
#ifndef FAR_CATMARK_SUBDIVISION_TABLES_H
#define FAR_CATMARK_SUBDIVISION_TABLES_H
#include <assert.h>
#include <cassert>
#include <vector>
#include <utility>
#include "../hbr/mesh.h"
#include "../hbr/catmark.h"
#include "../version.h"
@ -71,38 +67,39 @@
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
// 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
// structure. The advantage of this representation is its ability to be executed
// in a massively parallel environment without data dependencies.
//
template <class T, class U=T> class FarCatmarkSubdivisionTables : public FarSubdivisionTables<T,U> {
/// \brief Catmark subdivision scheme tables.
///
/// 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
/// structure. The advantage of this representation is its ability to be executed
/// in a massively parallel environment without data dependencies.
///
template <class U> class FarCatmarkSubdivisionTables : public FarSubdivisionTables<U> {
public:
// Memory required to store the indexing tables
/// Memory required to store the indexing tables
virtual int GetMemoryUsed() const;
// Compute the positions of refined vertices using the specified kernels
/// Compute the positions of refined vertices using the specified kernels
virtual void Apply( int level, void * data=0 ) const;
// Table accessors
/// Face-vertices indexing table accessor
FarTable<unsigned int> const & Get_F_IT( ) const { return _F_IT; }
/// Face-vertices indexing table accessor
FarTable<int> const & Get_F_ITa( ) const { return _F_ITa; }
// Returns the number of indexing tables needed to represent this particular
// subdivision scheme.
/// Returns the number of indexing tables needed to represent this particular
/// subdivision scheme.
virtual int GetNumTables() const { return 7; }
private:
template <class X, class Y> friend struct FarCatmarkSubdivisionTablesFactory;
friend class FarDispatcher<U>;
friend class FarMeshFactory<T,U>;
friend class FarDispatcher<T,U>;
// Constructor : build level table at depth 'level'
FarCatmarkSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int level );
// Private constructor called by factory
FarCatmarkSubdivisionTables( FarMesh<U> * 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 +121,28 @@ private:
FarTable<unsigned int> _F_IT;
};
template <class T, class U> int
FarCatmarkSubdivisionTables<T,U>::GetMemoryUsed() const {
return FarSubdivisionTables<T,U>::GetMemoryUsed()+
template <class U>
FarCatmarkSubdivisionTables<U>::FarCatmarkSubdivisionTables( FarMesh<U> * mesh, int maxlevel ) :
FarSubdivisionTables<U>(mesh, maxlevel),
_F_ITa(maxlevel+1),
_F_IT(maxlevel+1)
{ }
template <class U> int
FarCatmarkSubdivisionTables<U>::GetMemoryUsed() const {
return FarSubdivisionTables<U>::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 <class T, class U>
FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int maxlevel ) :
FarSubdivisionTables<T,U>(mesh, maxlevel),
_F_ITa(maxlevel+1),
_F_IT(maxlevel+1)
{
std::vector<int> 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<T,U>::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<T> * v = factory._faceVertsList[level][i];
assert(v);
HbrFace<T> * 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; j<valence; ++j)
F_IT[offset++] = remap[f->GetVertex(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<T>
typename HbrCatmarkSubdivision<T>::TriangleSubdivision triangleMethod =
dynamic_cast<HbrCatmarkSubdivision<T> *>(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<T> * v = factory._edgeVertsList[level][i];
assert(v);
HbrHalfedge<T> * 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<T>* rf = e->GetRightFace();
HbrFace<T>* lf = e->GetLeftFace();
leftWeight = ( triangleMethod == HbrCatmarkSubdivision<T>::k_New && lf->GetNumVertices() == 3) ? HBR_SMOOTH_TRI_EDGE_WEIGHT : 0.25f;
rightWeight = ( triangleMethod == HbrCatmarkSubdivision<T>::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<T> * v = factory._vertVertsList[level][i],
* pv = v->GetParentVertex();
assert(v and pv);
// Look at HbrCatmarkSubdivision<T>::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<T>::k_Smooth and
masks[1]==HbrVertex<T>::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<npasses; ++p)
switch (masks[p]) {
case HbrVertex<T>::k_Smooth :
case HbrVertex<T>::k_Dart : {
HbrHalfedge<T> *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<T>::k_Crease : {
class GatherCreaseEdgesOperator : public HbrHalfedgeOperator<T> {
public:
HbrVertex<T> * vertex; int eidx[2]; int count; bool next;
GatherCreaseEdgesOperator(HbrVertex<T> * v, bool n) : vertex(v), count(0), next(n) { eidx[0]=-1; eidx[1]=-1; }
virtual void operator() (HbrHalfedge<T> &e) {
if (e.IsSharp(next) and count < 2) {
HbrVertex<T> * 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<T>::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 <class T, class U> void
FarCatmarkSubdivisionTables<T,U>::Apply( int level, void * clientdata ) const {
template <class U> void
FarCatmarkSubdivisionTables<U>::Apply( int level, void * clientdata ) const {
assert(this->_mesh and level>0);
typename FarSubdivisionTables<T,U>::VertexKernelBatch const * batch = & (this->_batches[level-1]);
typename FarSubdivisionTables<U>::VertexKernelBatch const * batch = & (this->_batches[level-1]);
FarDispatcher<T,U> const * dispatch = this->_mesh->GetDispatcher();
FarDispatcher<U> const * dispatch = this->_mesh->GetDispatcher();
assert(dispatch);
int offset = this->GetFirstVertexOffset(level);
@ -412,8 +166,8 @@ FarCatmarkSubdivisionTables<T,U>::Apply( int level, void * clientdata ) const {
// Face-vertices compute Kernel - completely re-entrant
//
template <class T, class U> void
FarCatmarkSubdivisionTables<T,U>::computeFacePoints( int offset, int level, int start, int end, void * clientdata ) const {
template <class U> void
FarCatmarkSubdivisionTables<U>::computeFacePoints( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh);
@ -442,8 +196,8 @@ FarCatmarkSubdivisionTables<T,U>::computeFacePoints( int offset, int level, int
// Edge-vertices compute Kernel - completely re-entrant
//
template <class T, class U> void
FarCatmarkSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const {
template <class U> void
FarCatmarkSubdivisionTables<U>::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh);
@ -486,8 +240,8 @@ FarCatmarkSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int
//
// multi-pass kernel handling k_Crease and k_Corner rules
template <class T, class U> void
FarCatmarkSubdivisionTables<T,U>::computeVertexPointsA( int offset, bool pass, int level, int start, int end, void * clientdata ) const {
template <class U> void
FarCatmarkSubdivisionTables<U>::computeVertexPointsA( int offset, bool pass, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh);
@ -531,8 +285,8 @@ FarCatmarkSubdivisionTables<T,U>::computeVertexPointsA( int offset, bool pass, i
}
// multi-pass kernel handling k_Dart and k_Smooth rules
template <class T, class U> void
FarCatmarkSubdivisionTables<T,U>::computeVertexPointsB( int offset, int level, int start, int end, void * clientdata ) const {
template <class U> void
FarCatmarkSubdivisionTables<U>::computeVertexPointsB( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh);

View File

@ -0,0 +1,322 @@
//
// 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 <cassert>
#include <vector>
#include "../version.h"
#include "../far/catmarkSubdivisionTables.h"
#include "../far/meshFactory.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
template <class T, class U> class FarMeshFactory;
/// \brief A specialized factory for FarCatmarkSubdivisionTables
///
/// Separating the factory allows us to isolate Far data structures from Hbr dependencies.
///
template <class T, class U> struct FarCatmarkSubdivisionTablesFactory {
/// Creates a FarCatmarkSubdivisiontables instance.
static FarCatmarkSubdivisionTables<U> * Create( FarMeshFactory<T,U> const * factory, FarMesh<U> * mesh, int maxlevel );
};
template <class T, class U> FarCatmarkSubdivisionTables<U> *
FarCatmarkSubdivisionTablesFactory<T,U>::Create( FarMeshFactory<T,U> const * factory, FarMesh<U> * mesh, int maxlevel ) {
assert( factory and mesh );
FarCatmarkSubdivisionTables<U> * result = new FarCatmarkSubdivisionTables<U>(mesh, maxlevel);
std::vector<int> 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<U>::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<T> * v = factory->_faceVertsList[level][i];
assert(v);
HbrFace<T> * 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; j<valence; ++j)
F_IT[offset++] = remap[f->GetVertex(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<T>
typename HbrCatmarkSubdivision<T>::TriangleSubdivision triangleMethod =
dynamic_cast<HbrCatmarkSubdivision<T> *>(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<T> * v = factory->_edgeVertsList[level][i];
assert(v);
HbrHalfedge<T> * 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<T>* rf = e->GetRightFace();
HbrFace<T>* lf = e->GetLeftFace();
leftWeight = ( triangleMethod == HbrCatmarkSubdivision<T>::k_New && lf->GetNumVertices() == 3) ? HBR_SMOOTH_TRI_EDGE_WEIGHT : 0.25f;
rightWeight = ( triangleMethod == HbrCatmarkSubdivision<T>::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<T> * v = factory->_vertVertsList[level][i],
* pv = v->GetParentVertex();
assert(v and pv);
// Look at HbrCatmarkSubdivision<T>::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<T>::k_Smooth and
masks[1]==HbrVertex<T>::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<npasses; ++p)
switch (masks[p]) {
case HbrVertex<T>::k_Smooth :
case HbrVertex<T>::k_Dart : {
HbrHalfedge<T> *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<T>::k_Crease : {
class GatherCreaseEdgesOperator : public HbrHalfedgeOperator<T> {
public:
HbrVertex<T> * vertex; int eidx[2]; int count; bool next;
GatherCreaseEdgesOperator(HbrVertex<T> * v, bool n) : vertex(v), count(0), next(n) { eidx[0]=-1; eidx[1]=-1; }
virtual void operator() (HbrHalfedge<T> &e) {
if (e.IsSharp(next) and count < 2) {
HbrVertex<T> * 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<T>::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 */

View File

@ -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"
@ -69,72 +68,74 @@
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
// Compute dispatcher : allows client code to customize parts or the entire
// computation process. This pattern aims at hiding the logic specific to
// the subdivision algorithms and expose a simplified access to minimalistic
// compute kernels. By default, meshes revert to a default dispatcher that
// implements single-threaded CPU kernels.
//
// - derive a dispatcher class from this one
// - override the virtual functions
// - pass the derived dispatcher to the factory (one instance can be shared by many meshes)
// - call the FarMesh::Subdivide() to trigger computations
//
// Note : the caller is responsible for deleting a custom dispatcher
template <class T, class U=T> class FarDispatcher {
/// \brief Subdivision process encapsulation layer.
///
/// The Compute dispatcher allows client code to customize parts or the entire
/// computation process. This pattern aims at hiding the logic specific to
/// the subdivision algorithms and expose a simplified access to minimalistic
/// compute kernels. By default, meshes revert to a default dispatcher that
/// implements single-threaded CPU kernels.
///
/// - derive a dispatcher class from this one
/// - override the virtual functions
/// - pass the derived dispatcher to the factory (one instance can be shared by many meshes)
/// - call the FarMesh::Subdivide() to trigger computations
///
/// Note : the caller is responsible for deleting a custom dispatcher
///
template <class U> class FarDispatcher {
protected:
friend class FarBilinearSubdivisionTables<T,U>;
friend class FarCatmarkSubdivisionTables<T,U>;
friend class FarLoopSubdivisionTables<T,U>;
friend class FarVertexEditTables<T,U>;
friend class FarMesh<T,U>;
template <class X, class Y> friend class FarMeshFactory;
friend class FarBilinearSubdivisionTables<U>;
friend class FarCatmarkSubdivisionTables<U>;
friend class FarLoopSubdivisionTables<U>;
friend class FarVertexEditTables<U>;
friend class FarMesh<U>;
virtual void Refine(FarMesh<T,U> * mesh, int maxlevel, void * clientdata=0) const;
virtual void Refine(FarMesh<U> * mesh, int maxlevel, void * clientdata=0) const;
virtual void ApplyBilinearFaceVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyBilinearFaceVerticesKernel(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyBilinearEdgeVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyBilinearEdgeVerticesKernel(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyBilinearVertexVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyBilinearVertexVerticesKernel(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyCatmarkFaceVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyCatmarkFaceVerticesKernel(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyCatmarkEdgeVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyCatmarkEdgeVerticesKernel(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyCatmarkVertexVerticesKernelB(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyCatmarkVertexVerticesKernelB(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyCatmarkVertexVerticesKernelA(FarMesh<T,U> * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const;
virtual void ApplyCatmarkVertexVerticesKernelA(FarMesh<U> * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const;
virtual void ApplyLoopEdgeVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyLoopEdgeVerticesKernel(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyLoopVertexVerticesKernelB(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyLoopVertexVerticesKernelB(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<T,U> * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const;
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<U> * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const;
virtual void ApplyVertexEdit(FarMesh<T,U> *mesh, int offset, int level, void * clientdata) const;
virtual void ApplyVertexEdits(FarMesh<U> *mesh, int offset, int level, void * clientdata) const;
private:
friend class FarMeshFactory<T,U>;
static FarDispatcher _DefaultDispatcher;
};
template<class T, class U> FarDispatcher<T,U> FarDispatcher<T,U>::_DefaultDispatcher;
template<class U> FarDispatcher<U> FarDispatcher<U>::_DefaultDispatcher;
template <class T,class U> void
FarDispatcher<T,U>::Refine( FarMesh<T,U> * mesh, int maxlevel, void * data) const {
template <class U> void
FarDispatcher<U>::Refine( FarMesh<U> * mesh, int maxlevel, void * data) const {
assert(mesh);
FarSubdivisionTables<T,U> const * tables = mesh->GetSubdivision();
FarSubdivisionTables<U> const * tables = mesh->GetSubdivision();
FarVertexEditTables<T,U> const * edits = mesh->GetVertexEdit();
FarVertexEditTables<U> const * edits = mesh->GetVertexEdit();
if ( (maxlevel < 0) )
maxlevel=tables->GetMaxLevel();
@ -142,98 +143,101 @@ FarDispatcher<T,U>::Refine( FarMesh<T,U> * mesh, int maxlevel, void * data) cons
maxlevel = std::min(maxlevel, tables->GetMaxLevel());
for (int i=1; i<maxlevel; ++i) {
// compute vertex & varying interpolation on all vertices
tables->Apply(i, data);
// apply hierarchical edits
if (edits)
edits->Apply(i, data);
}
}
template <class T, class U> void
FarDispatcher<T,U>::ApplyBilinearFaceVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarBilinearSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarBilinearSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
template <class U> void
FarDispatcher<U>::ApplyBilinearFaceVerticesKernel(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarBilinearSubdivisionTables<U> const * subdivision =
dynamic_cast<FarBilinearSubdivisionTables<U> const *>(mesh->GetSubdivision());
assert(subdivision);
subdivision->computeFacePoints(offset, level, start, end, clientdata);
}
template <class T, class U> void
FarDispatcher<T,U>::ApplyBilinearEdgeVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarBilinearSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarBilinearSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
template <class U> void
FarDispatcher<U>::ApplyBilinearEdgeVerticesKernel(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarBilinearSubdivisionTables<U> const * subdivision =
dynamic_cast<FarBilinearSubdivisionTables<U> const *>(mesh->GetSubdivision());
assert(subdivision);
subdivision->computeEdgePoints(offset, level, start, end, clientdata);
}
template <class T, class U> void
FarDispatcher<T,U>::ApplyBilinearVertexVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarBilinearSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarBilinearSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
template <class U> void
FarDispatcher<U>::ApplyBilinearVertexVerticesKernel(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarBilinearSubdivisionTables<U> const * subdivision =
dynamic_cast<FarBilinearSubdivisionTables<U> const *>(mesh->GetSubdivision());
assert(subdivision);
subdivision->computeVertexPoints(offset, level, start, end, clientdata);
}
template <class T, class U> void
FarDispatcher<T,U>::ApplyCatmarkFaceVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarCatmarkSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarCatmarkSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
template <class U> void
FarDispatcher<U>::ApplyCatmarkFaceVerticesKernel(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarCatmarkSubdivisionTables<U> const * subdivision =
dynamic_cast<FarCatmarkSubdivisionTables<U> const *>(mesh->GetSubdivision());
assert(subdivision);
subdivision->computeFacePoints(offset, level, start, end, clientdata);
}
template <class T, class U> void
FarDispatcher<T,U>::ApplyCatmarkEdgeVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarCatmarkSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarCatmarkSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
template <class U> void
FarDispatcher<U>::ApplyCatmarkEdgeVerticesKernel(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarCatmarkSubdivisionTables<U> const * subdivision =
dynamic_cast<FarCatmarkSubdivisionTables<U> const *>(mesh->GetSubdivision());
assert(subdivision);
subdivision->computeEdgePoints(offset, level, start, end, clientdata);
}
template <class T, class U> void
FarDispatcher<T,U>::ApplyCatmarkVertexVerticesKernelB(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarCatmarkSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarCatmarkSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
template <class U> void
FarDispatcher<U>::ApplyCatmarkVertexVerticesKernelB(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarCatmarkSubdivisionTables<U> const * subdivision =
dynamic_cast<FarCatmarkSubdivisionTables<U> const *>(mesh->GetSubdivision());
assert(subdivision);
subdivision->computeVertexPointsB(offset, level, start, end, clientdata);
}
template <class T, class U> void
FarDispatcher<T,U>::ApplyCatmarkVertexVerticesKernelA(FarMesh<T,U> * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const {
FarCatmarkSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarCatmarkSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
template <class U> void
FarDispatcher<U>::ApplyCatmarkVertexVerticesKernelA(FarMesh<U> * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const {
FarCatmarkSubdivisionTables<U> const * subdivision =
dynamic_cast<FarCatmarkSubdivisionTables<U> const *>(mesh->GetSubdivision());
assert(subdivision);
subdivision->computeVertexPointsA(offset, pass, level, start, end, clientdata);
}
template <class T, class U> void
FarDispatcher<T,U>::ApplyLoopEdgeVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarLoopSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarLoopSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
template <class U> void
FarDispatcher<U>::ApplyLoopEdgeVerticesKernel(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarLoopSubdivisionTables<U> const * subdivision =
dynamic_cast<FarLoopSubdivisionTables<U> const *>(mesh->GetSubdivision());
assert(subdivision);
subdivision->computeEdgePoints(offset, level, start, end, clientdata);
}
template <class T, class U> void
FarDispatcher<T,U>::ApplyLoopVertexVerticesKernelB(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarLoopSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarLoopSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
template <class U> void
FarDispatcher<U>::ApplyLoopVertexVerticesKernelB(FarMesh<U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarLoopSubdivisionTables<U> const * subdivision =
dynamic_cast<FarLoopSubdivisionTables<U> const *>(mesh->GetSubdivision());
assert(subdivision);
subdivision->computeVertexPointsB(offset, level, start, end, clientdata);
}
template <class T, class U> void
FarDispatcher<T,U>::ApplyLoopVertexVerticesKernelA(FarMesh<T,U> * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const {
FarLoopSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarLoopSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
template <class U> void
FarDispatcher<U>::ApplyLoopVertexVerticesKernelA(FarMesh<U> * mesh, int offset, bool pass, int level, int start, int end, void * clientdata) const {
FarLoopSubdivisionTables<U> const * subdivision =
dynamic_cast<FarLoopSubdivisionTables<U> const *>(mesh->GetSubdivision());
assert(subdivision);
subdivision->computeVertexPointsA(offset, pass, level, start, end, clientdata);
}
template <class T, class U> void
FarDispatcher<T,U>::ApplyVertexEdit(FarMesh<T,U> * mesh, int offset, int level, void * clientdata) const {
FarVertexEditTables<T,U> const * vertexEdit = mesh->GetVertexEdit();
if (vertexEdit)
vertexEdit->editVertex(level, clientdata);
template <class U> void
FarDispatcher<U>::ApplyVertexEdits(FarMesh<U> * mesh, int offset, int level, void * clientdata) const {
FarVertexEditTables<U> const * vertEdit = mesh->GetVertexEdit();
if (vertEdit)
vertEdit->computeVertexEdits(level, clientdata);
}
} // end namespace OPENSUBDIV_VERSION

View File

@ -57,13 +57,10 @@
#ifndef FAR_LOOP_SUBDIVISION_TABLES_H
#define FAR_LOOP_SUBDIVISION_TABLES_H
#include "assert.h"
#include <cassert>
#include <cmath>
#include <vector>
#include "../hbr/mesh.h"
#include "../hbr/loop.h"
#include "../version.h"
#include "../far/subdivisionTables.h"
@ -71,28 +68,27 @@
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
// Loop tables store the indexing tables required in order to compute
// the refined positions of a mesh without the help of a hierarchical data
// structure. The advantage of this representation is its ability to be executed
// in a massively parallel environment without data dependencies.
//
/// \brief Loop subdivision scheme tables.
///
/// Loop tables store the indexing tables required in order to compute
/// the refined positions of a mesh without the help of a hierarchical data
/// structure. The advantage of this representation is its ability to be executed
/// in a massively parallel environment without data dependencies.
///
template <class T, class U=T> class FarLoopSubdivisionTables : public FarSubdivisionTables<T,U> {
template <class U> class FarLoopSubdivisionTables : public FarSubdivisionTables<U> {
public:
// Compute the positions of refined vertices using the specified kernels
/// Compute the positions of refined vertices using the specified kernels
virtual void Apply( int level, void * data=0 ) const;
private:
template <class X, class Y> friend struct FarLoopSubdivisionTablesFactory;
friend class FarDispatcher<U>;
friend class FarMeshFactory<T,U>;
friend class FarDispatcher<T,U>;
// Constructor : build level table at depth 'level'
FarLoopSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int level );
FarLoopSubdivisionTables( FarMesh<U> * 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 +100,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 <class T, class U>
FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int maxlevel )
: FarSubdivisionTables<T,U>(mesh, maxlevel)
{
std::vector<int> const & remap = factory._remapTable;
template <class U>
FarLoopSubdivisionTables<U>::FarLoopSubdivisionTables( FarMesh<U> * mesh, int maxlevel ) :
FarSubdivisionTables<U>(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<T,U>::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<T> * v = factory._edgeVertsList[level][i];
assert(v);
HbrHalfedge<T> * 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<T>* 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<T> * v = factory._vertVertsList[level][i],
* pv = v->GetParentVertex();
assert(v and pv);
// Look at HbrCatmarkSubdivision<T>::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<T>::k_Smooth and
masks[1]==HbrVertex<T>::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<npasses; ++p)
switch (masks[p]) {
case HbrVertex<T>::k_Smooth :
case HbrVertex<T>::k_Dart : {
HbrHalfedge<T> *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<T>::k_Crease : {
class GatherCreaseEdgesOperator : public HbrHalfedgeOperator<T> {
public:
HbrVertex<T> * vertex; int eidx[2]; int count; bool next;
GatherCreaseEdgesOperator(HbrVertex<T> * v, bool n) : vertex(v), count(0), next(n) { eidx[0]=-1; eidx[1]=-1; }
virtual void operator() (HbrHalfedge<T> &e) {
if (e.IsSharp(next) and count < 2) {
HbrVertex<T> * 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<T>::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 <class T, class U> void
FarLoopSubdivisionTables<T,U>::Apply( int level, void * clientdata ) const
template <class U> void
FarLoopSubdivisionTables<U>::Apply( int level, void * clientdata ) const
{
assert(this->_mesh and level>0);
typename FarSubdivisionTables<T,U>::VertexKernelBatch const * batch = & (this->_batches[level-1]);
typename FarSubdivisionTables<U>::VertexKernelBatch const * batch = & (this->_batches[level-1]);
FarDispatcher<T,U> const * dispatch = this->_mesh->GetDispatcher();
FarDispatcher<U> const * dispatch = this->_mesh->GetDispatcher();
assert(dispatch);
int offset = this->GetFirstVertexOffset(level);
@ -329,8 +135,8 @@ FarLoopSubdivisionTables<T,U>::Apply( int level, void * clientdata ) const
// Edge-vertices compute Kernel - completely re-entrant
//
template <class T, class U> void
FarLoopSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const {
template <class U> void
FarLoopSubdivisionTables<U>::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh);
@ -373,8 +179,8 @@ FarLoopSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int sta
//
// multi-pass kernel handling k_Crease and k_Corner rules
template <class T, class U> void
FarLoopSubdivisionTables<T,U>::computeVertexPointsA( int offset, bool pass, int level, int start, int end, void * clientdata ) const {
template <class U> void
FarLoopSubdivisionTables<U>::computeVertexPointsA( int offset, bool pass, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh);
@ -418,8 +224,8 @@ FarLoopSubdivisionTables<T,U>::computeVertexPointsA( int offset, bool pass, int
}
// multi-pass kernel handling k_Dart and k_Smooth rules
template <class T, class U> void
FarLoopSubdivisionTables<T,U>::computeVertexPointsB( int offset, int level, int start, int end, void * clientdata ) const {
template <class U> void
FarLoopSubdivisionTables<U>::computeVertexPointsB( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh);

View File

@ -0,0 +1,270 @@
//
// 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 <cassert>
#include <vector>
#include "../version.h"
#include "../far/loopSubdivisionTables.h"
#include "../far/meshFactory.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
template <class T, class U> class FarMeshFactory;
/// \brief A specialized factory for FarLoopSubdivisionTables
///
/// Separating the factory allows us to isolate Far data structures from Hbr dependencies.
///
template <class T, class U> struct FarLoopSubdivisionTablesFactory {
/// Creates a FarLoopSubdivisiontables instance.
static FarLoopSubdivisionTables<U> * Create( FarMeshFactory<T,U> const * factory, FarMesh<U> * mesh, int maxlevel );
};
template <class T, class U> FarLoopSubdivisionTables<U> *
FarLoopSubdivisionTablesFactory<T,U>::Create( FarMeshFactory<T,U> const * factory, FarMesh<U> * mesh, int maxlevel ) {
assert( factory and mesh );
FarLoopSubdivisionTables<U> * result = new FarLoopSubdivisionTables<U>(mesh, maxlevel);
std::vector<int> 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<U>::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<T> * v = factory->_edgeVertsList[level][i];
assert(v);
HbrHalfedge<T> * 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<T>* 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<T> * v = factory->_vertVertsList[level][i],
* pv = v->GetParentVertex();
assert(v and pv);
// Look at HbrCatmarkSubdivision<T>::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<T>::k_Smooth and
masks[1]==HbrVertex<T>::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<npasses; ++p)
switch (masks[p]) {
case HbrVertex<T>::k_Smooth :
case HbrVertex<T>::k_Dart : {
HbrHalfedge<T> *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<T>::k_Crease : {
class GatherCreaseEdgesOperator : public HbrHalfedgeOperator<T> {
public:
HbrVertex<T> * vertex; int eidx[2]; int count; bool next;
GatherCreaseEdgesOperator(HbrVertex<T> * v, bool n) : vertex(v), count(0), next(n) { eidx[0]=-1; eidx[1]=-1; }
virtual void operator() (HbrHalfedge<T> &e) {
if (e.IsSharp(next) and count < 2) {
HbrVertex<T> * 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<T>::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 */

View File

@ -61,33 +61,32 @@
#include <vector>
#include "../version.h"
#include "../far/subdivisionTables.h"
#include "../far/vertexEditTables.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
template <class T, class U> class FarMeshFactory;
template <class T, class U> class FarSubdivisionTables;
template <class T, class U> class FarDispatcher;
template <class T, class U> class FarVertexEditTables;
template <class U> class FarDispatcher;
// Core serialized subdivision mesh class.
//
// In order to support both interleaved & non-interleaved vertex access,
// classes are dual-templated : T corresponds to the Hbr vertex representation
// while U correcsponds to this library's vertex representation. In some cases,
// 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.
/// \brief Feature Adaptive Mesh class.
///
/// FarMesh is a serialized instantiation of an HbrMesh. The HbrMesh contains
/// all the topological data in a highly interconnected data structure for
/// ease of access and modification. When instantiating a FarMesh, the factory
/// analyzes this data structure and serializes the topology into a linear
/// buffers that are ready for efficient parallel processing.
template <class T, class U=T> class FarMesh {
template <class U> class FarMesh {
public:
~FarMesh();
// returns the subdivision method
FarSubdivisionTables<T,U> const * GetSubdivision() const { return _subdivision; }
/// Returns the subdivision method
FarSubdivisionTables<U> const * GetSubdivision() const { return _subdivisionTables; }
// returns the compute dispatcher
FarDispatcher<T,U> const * GetDispatcher() const { return _dispatcher; }
/// Returns the compute dispatcher
FarDispatcher<U> const * GetDispatcher() const { return _dispatcher; }
enum PatchType {
k_BilinearTriangles,
@ -95,49 +94,54 @@ public:
k_Triangles,
};
// returns the type of patches described by the face vertices list
/// Returns the type of patches described by the face vertices list
PatchType GetPatchType() const { return _patchtype; }
// returns the list of vertices in the mesh (from subdiv level 0 to N)
/// Returns the list of vertices in the mesh (from subdiv level 0 to N)
std::vector<U> & GetVertices() { return _vertices; }
U & GetVertex(int index) { return _vertices[index]; }
// returns the list of indices of the vertices of the faces in the mesh
/// Returns the list of indices of the vertices of the faces in the mesh
std::vector<int> const & GetFaceVertices(int level) const;
// returns the ptex coordinates for each face at a given level. The coordinates
// are stored as : (int) faceindex / (ushort) u_index / (ushort) v_index
/// Returns the ptex coordinates for each face at a given level. The coordinates
/// are stored as : (int) faceindex / (ushort) u_index / (ushort) v_index
std::vector<int> const & GetPtexCoordinates(int level) const;
// returns vertex edit tables
FarVertexEditTables<T,U> const * GetVertexEdit() const { return _vertexEdit; }
/// Returns vertex edit tables
FarVertexEditTables<U> const * GetVertexEdit() const { return _vertexEditTables; }
// returns the number of coarse vertices held at the beginning of the vertex
// buffer.
/// Returns the number of coarse vertices held at the beginning of the vertex
/// buffer.
int GetNumCoarseVertices() const;
// returns the total number of vertices in the mesh across across all depths
/// Returns the total number of vertices in the mesh across across all depths
int GetNumVertices() const { return (int)(_vertices.size()); }
// apply the subdivision tables to compute the positions of the vertices up
// to 'level'
/// Apply the subdivision tables to compute the positions of the vertices up
/// to 'level'
void Subdivide(int level=-1);
private:
friend class FarMeshFactory<T,U>;
// Note : the vertex classes are renamed <X,Y> so as not to shadow the
// declaration of the templated vertex class U.
template <class X, class Y> 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<T,U> const &);
FarMesh<T,U> & operator = (FarMesh<T,U> const &);
FarMesh(FarMesh<U> const &);
FarMesh<U> & operator = (FarMesh<U> const &);
// subdivision method used in this mesh
FarSubdivisionTables<T,U> * _subdivision;
FarSubdivisionTables<U> * _subdivisionTables;
// hierarchical vertex edit tables
FarVertexEditTables<U> * _vertexEditTables;
// customizable compute dispatcher class
FarDispatcher<T,U> * _dispatcher;
FarDispatcher<U> * _dispatcher;
// list of vertices (up to N levels of subdivision)
std::vector<U> _vertices;
@ -148,9 +152,6 @@ private:
// ptex coordinates for each face
std::vector< std::vector<int> > _ptexcoordinates;
// hierarchical vertex edit tables
FarVertexEditTables<T,U> * _vertexEdit;
// XXX stub for adaptive work
PatchType _patchtype;
@ -158,47 +159,49 @@ private:
int _numCoarseVertices;
};
template <class T, class U>
FarMesh<T,U>::~FarMesh()
template <class U>
FarMesh<U>::~FarMesh()
{
delete _subdivision;
delete _vertexEdit;
delete _subdivisionTables;
delete _vertexEditTables;
}
template <class T, class U> int
FarMesh<T,U>::GetNumCoarseVertices() const {
template <class U> int
FarMesh<U>::GetNumCoarseVertices() const {
return _numCoarseVertices;
}
template <class T, class U> std::vector<int> const &
FarMesh<T,U>::GetFaceVertices(int level) const {
template <class U> std::vector<int> const &
FarMesh<U>::GetFaceVertices(int level) const {
if ( (level>=0) and (level<(int)_faceverts.size()) )
return _faceverts[level];
return _faceverts[0];
}
template <class T, class U> std::vector<int> const &
FarMesh<T,U>::GetPtexCoordinates(int level) const {
template <class U> std::vector<int> const &
FarMesh<U>::GetPtexCoordinates(int level) const {
if ( (level>=0) and (level<(int)_faceverts.size()) )
return _ptexcoordinates[level];
return _ptexcoordinates[0];
}
template <class T, class U> void
FarMesh<T,U>::Subdivide(int maxlevel) {
template <class U> void
FarMesh<U>::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; i<maxlevel; ++i) {
_subdivision->Apply(i);
if (_vertexEdit)
_vertexEdit->Apply(i);
_subdivisionTables->Apply(i);
if (_vertexEditTables)
_vertexEditTables->Apply(i);
}
}

View File

@ -59,28 +59,33 @@
#include <typeinfo>
#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 {
// The meshFactory institutes a 2 steps process in the conversion of a mesh from
// an HbrMesh<T>. The main reason is that client code may want to have access
// to the remapping table that correlates vertices from both meshes for reasons
// of their own. This is also useful to the unit-test code which can match the
// subdivision results of both code paths for correctness.
/// \brief Instantiates a FarMesh from an HbrMesh.
///
/// FarMeshFactory requires a 2 steps process :
/// 1. Instantiate a FarMeshFactory object from an HbrMesh
/// 2. Call "Create" to obtain the FarMesh instance
///
/// This tiered factory approach offers client-code the opportunity to access
/// useful transient information tied to the lifespan of the factory instance.
/// Specifically, regression code needs to access the remapping tables that
/// tie HbrMesh vertices to their FarMesh counterparts for comparison.
template <class T, class U=T> class FarMeshFactory {
@ -92,47 +97,46 @@ public:
// object can be deleted safely.
FarMeshFactory(HbrMesh<T> * mesh, int maxlevel);
// Create a table-based mesh representation
// XXXX : this creator will take the options for adaptive patch meshes
FarMesh<T,U> * Create( FarDispatcher<T,U> * dispatch=0 );
/// Create a table-based mesh representation
FarMesh<U> * Create( FarDispatcher<U> * dispatch=0 );
// Maximum level of subidivision supported by this factory
/// Maximum level of subidivision supported by this factory
int GetMaxLevel() const { return _maxlevel; }
// Total number of face vertices up to 'level'
/// Total number of face vertices up to 'level'
int GetNumFaceVerticesTotal(int level) const {
return sumList<HbrVertex<T> *>(_faceVertsList, level);
}
// Total number of edge vertices up to 'level'
/// Total number of edge vertices up to 'level'
int GetNumEdgeVerticesTotal(int level) const {
return sumList<HbrVertex<T> *>(_edgeVertsList, level);
}
// Total number of vertex vertices up to 'level'
/// Total number of vertex vertices up to 'level'
int GetNumVertexVerticesTotal(int level) const {
return sumList<HbrVertex<T> *>(_vertVertsList, level);
}
// Valence summation up to 'level'
/// Valence summation up to 'level'
int GetNumAdjacentVertVerticesTotal(int level) const;
// Total number of faces across up to a level
/// Total number of faces across up to a level
int GetNumFacesTotal(int level) const {
return sumList<HbrFace<T> *>(_facesList, level);
}
// Return the corresponding index of the HbrVertex<T> in the new mesh
/// Return the corresponding index of the HbrVertex<T> in the new mesh
int GetVertexID( HbrVertex<T> * v );
// Returns a the mapping between HbrVertex<T>->GetID() and Far vertices indices
/// Returns a the mapping between HbrVertex<T>->GetID() and Far vertices indices
std::vector<int> const & GetRemappingTable( ) const { return _remapTable; }
private:
friend class FarBilinearSubdivisionTables<T,U>;
friend class FarCatmarkSubdivisionTables<T,U>;
friend class FarLoopSubdivisionTables<T,U>;
friend class FarVertexEditTables<T,U>;
friend struct FarBilinearSubdivisionTablesFactory<T,U>;
friend struct FarCatmarkSubdivisionTablesFactory<T,U>;
friend struct FarLoopSubdivisionTablesFactory<T,U>;
friend struct FarVertexEditTablesFactory<T,U>;
// Non-copyable, so these are not implemented:
FarMeshFactory( FarMeshFactory const & );
@ -144,18 +148,17 @@ private:
static bool isLoop(HbrMesh<T> * mesh);
void copyTopology( std::vector<int> & vec, int level );
void generatePtexCoordinates( std::vector<int> & vec, int level );
FarVertexEditTables<T,U> * createVertexEdit(FarMesh<T,U> * mesh);
void copyTopology( std::vector<int> & vec, int level );
static bool compareVertices( HbrVertex<T> const *x, HbrVertex<T> const *y );
static void refine( HbrMesh<T> * mesh, int maxlevel );
template <class Type> static int sumList( std::vector<std::vector<Type> > const & list, int level );
static bool compareNSubfaces(HbrVertexEdit<T> const *a, HbrVertexEdit<T> const *b);
private:
HbrMesh<T> * _hbrMesh;
int _maxlevel,
@ -187,7 +190,7 @@ template <class T, class U>
template <class Type> int
FarMeshFactory<T,U>::sumList( std::vector<std::vector<Type> > const & list, int level) {
level = std::min(level, (int)list.size());
level = std::min(level, (int)list.size()-1);
int total = 0;
for (int i=0; i<=level; ++i)
total += (int)list[i].size();
@ -218,6 +221,27 @@ FarMeshFactory<T,U>::refine( HbrMesh<T> * 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 <class T, class U> bool
FarMeshFactory<T,U>::compareVertices( HbrVertex<T> const * x, HbrVertex<T> const * y ) {
// Masks of the parent vertex decide for the current vertex.
HbrVertex<T> * px=x->GetParentVertex(),
* py=y->GetParentVertex();
assert( (FarSubdivisionTables<U>::getMaskRanking(px->GetMask(false), px->GetMask(true) )!=0xFF) and
(FarSubdivisionTables<U>::getMaskRanking(py->GetMask(false), py->GetMask(true) )!=0xFF) );
return FarSubdivisionTables<U>::getMaskRanking(px->GetMask(false), px->GetMask(true) ) <
FarSubdivisionTables<U>::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 +352,9 @@ FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * 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<T> comparison
// function 'FarSubdivisionTables<T>::compareVertices' ).
// kernel switching.
for (size_t i=1; i<_vertVertsList.size(); ++i)
std::sort(_vertVertsList[i].begin(), _vertVertsList[i].end(),
FarSubdivisionTables<T,U>::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 +425,7 @@ FarMeshFactory<T,U>::copyTopology( std::vector<int> & vec, int level ) {
vec[nv*i+j]=_remapTable[f->GetVertex(j)->GetID()];
}
}
template <class T, class U> void
copyVertex( T & dest, U const & src ) {
}
@ -412,7 +435,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 <class T, class U> void
FarMeshFactory<T,U>::generatePtexCoordinates( std::vector<int> & vec, int level ) {
@ -462,162 +485,31 @@ FarMeshFactory<T,U>::generatePtexCoordinates( std::vector<int> & vec, int level
}
}
template <class T, class U> bool
FarMeshFactory<T,U>::compareNSubfaces(HbrVertexEdit<T> const *a, HbrVertexEdit<T> const *b) {
return a->GetNSubfaces() < b->GetNSubfaces();
}
template <class T, class U> FarVertexEditTables<T,U> *
FarMeshFactory<T,U>::createVertexEdit(FarMesh<T,U> *mesh) {
FarVertexEditTables<T,U> * table = new FarVertexEditTables<T,U>(mesh, _maxlevel);
std::vector<HbrHierarchicalEdit<T>*> const & hEdits = _hbrMesh->GetHierarchicalEdits();
std::vector<HbrVertexEdit<T> const *> vertexEdits;
vertexEdits.reserve(hEdits.size());
for (int i=0; i<(int)hEdits.size(); ++i) {
HbrVertexEdit<T> *vedit = dynamic_cast<HbrVertexEdit<T> *>(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<int> batchIndices;
std::vector<int> batchSizes;
for(int i=0; i<(int)vertexEdits.size(); ++i) {
HbrVertexEdit<T> const *vedit = vertexEdits[i];
// translate operation enum
typename FarVertexEditTables<T,U>::Operation operation = (vedit->GetOperation() == HbrHierarchicalEdit<T>::Set) ?
FarVertexEditTables<T,U>::Set : FarVertexEditTables<T,U>::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<T,U>::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<numBatches; ++i) {
table->_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<int> currentLevels(numBatches);
std::vector<int> currentCounts(numBatches);
for(int i=0; i<(int)vertexEdits.size(); ++i){
HbrVertexEdit<T> const *vedit = vertexEdits[i];
HbrFace<T> * f = _hbrMesh->GetFace(vedit->GetFaceID());
int level = vedit->GetNSubfaces();
for (int j=0; j<level; ++j)
f = f->GetChild(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<T,U>::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<T>::Subtract);
batch._offsets[level-1][batchCount] = vertexID;
for(int i=0; i<batch._width; ++i)
batch._values[level-1][batchCount * batch._width + i] = negate ? -values[i] : values[i];
// set marker
batchCount++;
batch._offsets.SetMarker(level, &batch._offsets[level-1][batchCount]);
batch._values.SetMarker(level, &batch._values[level-1][batchCount * batch._width]);
}
for(int i=0; i<numBatches; ++i) {
typename FarVertexEditTables<T,U>::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 <class T, class U> FarMesh<T,U> *
FarMeshFactory<T,U>::Create( FarDispatcher<T,U> * dispatch ) {
template <class T, class U> FarMesh<U> *
FarMeshFactory<T,U>::Create( FarDispatcher<U> * dispatch ) {
assert( _hbrMesh );
if (_maxlevel<1)
return 0;
FarMesh<T,U> * result = new FarMesh<T,U>();
FarMesh<U> * result = new FarMesh<U>();
if (dispatch)
result->_dispatcher = dispatch;
else
result->_dispatcher = & FarDispatcher<T,U>::_DefaultDispatcher;
result->_dispatcher = & FarDispatcher<U>::_DefaultDispatcher;
if ( isBilinear( _hbrMesh ) ) {
result->_subdivision =
new FarBilinearSubdivisionTables<T,U>( *this, result, _maxlevel );
result->_subdivisionTables = FarBilinearSubdivisionTablesFactory<T,U>::Create( this, result, _maxlevel );
} else if ( isCatmark( _hbrMesh ) ) {
result->_subdivision =
new FarCatmarkSubdivisionTables<T,U>( *this, result, _maxlevel );
result->_subdivisionTables = FarCatmarkSubdivisionTablesFactory<T,U>::Create( this, result, _maxlevel );
} else if ( isLoop(_hbrMesh) ) {
result->_subdivision =
new FarLoopSubdivisionTables<T,U>( *this, result, _maxlevel );
result->_subdivisionTables = FarLoopSubdivisionTablesFactory<T,U>::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 +521,7 @@ FarMeshFactory<T,U>::Create( FarDispatcher<T,U> * dispatch ) {
// Populate topology (face verts indices)
// XXXX : only k_BilinearQuads support for now - adaptive bicubic patches to come
result->_patchtype = FarMesh<T,U>::k_BilinearQuads;
result->_patchtype = FarMesh<U>::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 +534,10 @@ FarMeshFactory<T,U>::Create( FarDispatcher<T,U> * dispatch ) {
// Create VertexEditTables if necessary
if (_hbrMesh->HasVertexEdits()) {
result->_vertexEdit = createVertexEdit(result);
result->_vertexEditTables = FarVertexEditTablesFactory<T,U>::Create( this, result, _maxlevel );
assert(result->_vertexEditTables);
}
return result;
}

View File

@ -57,107 +57,108 @@
#ifndef FAR_SUBDIVISION_TABLES_H
#define FAR_SUBDIVISION_TABLES_H
#include <assert.h>
#include <cassert>
#include <utility>
#include <vector>
#include "../version.h"
#include "../far/table.h"
template <class T> class HbrFace;
template <class T> class HbrHalfedge;
template <class T> class HbrVertex;
template <class T> class HbrMesh;
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
template <class T, class U> class FarMesh;
template <class T, class U> class FarMeshFactory;
template <class U> class FarMesh;
template <class U> 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
// structure. The advantage of this representation is its ability to be executed
// in a massively parallel environment without data dependencies.
//
// The vertex indexing tables require the vertex buffer to be sorted based on the
// nature of the parent of a given vertex : either a face, an edge, or a vertex.
//
// [...Child of a Face...]|[... Child of an Edge ...]|[... Child of a Vertex ...]
//
// Each segment of the buffer is associated the following tables (<T> is the type):
// _<T>_IT : indices of all the adjacent vertices required by the compute kernels
// _<T>_W : fractional weight of the vertex (based on sharpness & topology)
// _<T>_ITa : codex for the two previous tables
// For more details see : "Feature Adaptive GPU Rendering of Catmull-Clark
// Subdivision Surfaces" p.3 - par. 3.2
template <class T, class U=T> class FarSubdivisionTables {
/// \brief FarSubdivisionTables are a serialized topological data representation.
///
/// Subdivision tables store the indexing tables required in order to compute
/// the refined positions of a mesh without the help of a hierarchical data
/// structure. The advantage of this representation is its ability to be executed
/// in a massively parallel environment without data dependencies.
///
/// The vertex indexing tables require the vertex buffer to be sorted based on the
/// nature of the parent of a given vertex : either a face, an edge, or a vertex.
/// (note : the Loop subdivision scheme does not create vertices as a child of a
/// face).
///
/// Each type of vertex in the buffer is associated the following tables :
/// - _<T>_IT : indices of all the adjacent vertices required by the compute kernels
/// - _<T>_W : fractional weight of the vertex (based on sharpness & topology)
/// - _<T>_ITa : codex for the two previous tables
/// (where T denotes a face-vertex / edge-vertex / vertex-vertex)
///
///
/// Because each subdivision scheme (Catmark / Loop / Bilinear) introduces variations
/// in the subdivision rules, a derived class specialization is associated with
/// each scheme.
///
/// For more details see : "Feature Adaptive GPU Rendering of Catmull-Clark
/// Subdivision Surfaces" (p.3 - par. 3.2)
///
template <class U> class FarSubdivisionTables {
public:
// Destructor
virtual ~FarSubdivisionTables<T,U>() {}
/// Destructor
virtual ~FarSubdivisionTables<U>() {}
// Return the highest level of subdivision possible with these tables
/// Return the highest level of subdivision possible with these tables
int GetMaxLevel() const { return (int)(_vertsOffsets.size()); }
// Memory required to store the indexing tables
/// Memory required to store the indexing tables
virtual int GetMemoryUsed() const;
// Compute the positions of refined vertices using the specified kernels
/// Compute the positions of refined vertices using the specified kernels
virtual void Apply( int level, void * clientdata=0 ) const=0;
// Pointer back to the mesh owning the table
FarMesh<T,U> * GetMesh() { return _mesh; }
/// Pointer back to the mesh owning the table
FarMesh<U> * GetMesh() { return _mesh; }
// The index of the first vertex that belongs to the level of subdivision
// represented by this set of FarCatmarkSubdivisionTables
/// The index of the first vertex that belongs to the level of subdivision
/// represented by this set of FarCatmarkSubdivisionTables
int GetFirstVertexOffset( int level ) const;
// Number of vertices children of a face at a given level (always 0 for Loop)
/// Number of vertices children of a face at a given level (always 0 for Loop)
int GetNumFaceVertices( int level ) const;
// Number of vertices children of an edge at a given level
/// Number of vertices children of an edge at a given level
int GetNumEdgeVertices( int level ) const;
// Number of vertices children of a vertex at a given level
/// Number of vertices children of a vertex at a given level
int GetNumVertexVertices( int level ) const;
// Total number of vertices at a given level
int GetNumVertices( int level ) const;
// Indexing tables accessors
/// Indexing tables accessors
// Returns the edge vertices indexing table
/// Returns the edge vertices indexing table
FarTable<int> const & Get_E_IT() const { return _E_IT; }
// Returns the edge vertices weights table
/// Returns the edge vertices weights table
FarTable<float> const & Get_E_W() const { return _E_W; }
// Returns the vertex vertices codex table
/// Returns the vertex vertices codex table
FarTable<int> const & Get_V_ITa() const { return _V_ITa; }
// Returns the vertex vertices indexing table
/// Returns the vertex vertices indexing table
FarTable<unsigned int> const & Get_V_IT() const { return _V_IT; }
// Returns the vertex vertices weights table
/// Returns the vertex vertices weights table
FarTable<float> const & Get_V_W() const { return _V_W; }
// Returns the number of indexing tables needed to represent this particular
// subdivision scheme.
/// Returns the number of indexing tables needed to represent this particular
/// subdivision scheme.
virtual int GetNumTables() const { return 5; }
protected:
friend class FarMeshFactory<T,U>;
template <class X, class Y> friend class FarMeshFactory;
FarSubdivisionTables<T,U>( FarMesh<T,U> * mesh, int maxlevel );
FarSubdivisionTables<U>( FarMesh<U> * 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<T> const * x, HbrVertex<T> const * y );
struct VertexKernelBatch {
int kernelF; // number of face vertices
int kernelE; // number of edge vertices
@ -202,7 +203,7 @@ protected:
protected:
// mesh that owns this subdivisionTable
FarMesh<T,U> * _mesh;
FarMesh<U> * _mesh;
FarTable<int> _E_IT; // vertices from edge refinement
FarTable<float> _E_W; // weigths
@ -217,8 +218,8 @@ protected:
private:
};
template <class T, class U>
FarSubdivisionTables<T,U>::FarSubdivisionTables( FarMesh<T,U> * mesh, int maxlevel ) :
template <class U>
FarSubdivisionTables<U>::FarSubdivisionTables( FarMesh<U> * mesh, int maxlevel ) :
_mesh(mesh),
_E_IT(maxlevel+1),
_E_W(maxlevel+1),
@ -251,8 +252,8 @@ FarSubdivisionTables<T,U>::FarSubdivisionTables( FarMesh<T,U> * mesh, int maxlev
// with :
// - A : compute kernel applying k_Crease / k_Corner rules
// - B : compute kernel applying k_Smooth / k_Dart rules
template <class T, class U> int
FarSubdivisionTables<T,U>::getMaskRanking( unsigned char mask0, unsigned char mask1 ) {
template <class U> int
FarSubdivisionTables<U>::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 +261,26 @@ FarSubdivisionTables<T,U>::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 <class T, class U> bool
FarSubdivisionTables<T,U>::compareVertices( HbrVertex<T> const * x, HbrVertex<T> const * y ) {
// Masks of the parent vertex decide for the current vertex.
HbrVertex<T> * 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 <class T, class U> int
FarSubdivisionTables<T,U>::GetFirstVertexOffset( int level ) const {
template <class U> int
FarSubdivisionTables<U>::GetFirstVertexOffset( int level ) const {
assert(level>=0 and level<=(int)_vertsOffsets.size());
return _vertsOffsets[level];
}
template <class T, class U> int
FarSubdivisionTables<T,U>::GetNumFaceVertices( int level ) const {
template <class U> int
FarSubdivisionTables<U>::GetNumFaceVertices( int level ) const {
assert(level>=0 and level<=(int)_batches.size());
return _batches[level-1].kernelF;
}
template <class T, class U> int
FarSubdivisionTables<T,U>::GetNumEdgeVertices( int level ) const {
template <class U> int
FarSubdivisionTables<U>::GetNumEdgeVertices( int level ) const {
assert(level>=0 and level<=(int)_batches.size());
return _batches[level-1].kernelE;
}
template <class T, class U> int
FarSubdivisionTables<T,U>::GetNumVertexVertices( int level ) const {
template <class U> int
FarSubdivisionTables<U>::GetNumVertexVertices( int level ) const {
assert(level>=0 and level<=(int)_batches.size());
if (level==0)
return _mesh->GetNumCoarseVertices();
@ -310,8 +290,8 @@ FarSubdivisionTables<T,U>::GetNumVertexVertices( int level ) const {
_batches[level-1].kernelA2.second));
}
template <class T, class U> int
FarSubdivisionTables<T,U>::GetNumVertices( int level ) const {
template <class U> int
FarSubdivisionTables<U>::GetNumVertices( int level ) const {
assert(level>=0 and level<=(int)_batches.size());
if (level==0)
return GetNumVertexVertices(0);
@ -321,8 +301,8 @@ FarSubdivisionTables<T,U>::GetNumVertices( int level ) const {
GetNumVertexVertices(level);
}
template <class T, class U> int
FarSubdivisionTables<T,U>::GetMemoryUsed() const {
template <class U> int
FarSubdivisionTables<U>::GetMemoryUsed() const {
return _E_IT.GetMemoryUsed()+
_E_W.GetMemoryUsed()+
_V_ITa.GetMemoryUsed()+

View File

@ -62,11 +62,16 @@
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
// Generic multi-level indexing table : the indices across all the subdivision
// levels are stored in a single std::vector. The table class holds a sequence
// of markers pointing to the first index at the beginning of the sequence
// describing a given level (note that "level 1" vertices are obtained by using
// the indices starting at "level 0" of the tables)
/// \brief A generic "table" with markers.
///
/// Generic multi-level indexing table : the indices across all the subdivision
/// levels are stored in a flat std::vector.
///
/// The table class also holds a sequence of markers pointing to the first index
/// at the beginning of the sequence describing a given level.
/// (note that "level 1" vertices are obtained by using the indices starting at
/// "level 0" of the tables)
///
template <typename Type> class FarTable {
std::vector<Type> _data; // table data
std::vector<Type *> _markers; // pointers to the first datum at each level
@ -76,44 +81,44 @@ public:
FarTable(int maxlevel) : _markers(maxlevel) { }
// Reset max level and clear data
/// Reset max level and clear data
void SetMaxLevel(int maxlevel) {
_data.clear();
_markers.resize(maxlevel);
}
// Returns the memory required to store the data in this table.
/// Returns the memory required to store the data in this table.
int GetMemoryUsed() const {
return (int)_data.size() * sizeof(Type);
}
// Returns the number of elements in level "level"
/// Returns the number of elements in level "level"
int GetNumElements(int level) const {
assert(level>=0 and level<((int)_markers.size()-1));
return (int)(_markers[level+1] - _markers[level]);
}
// Saves a pointer indicating the beginning of data pertaining to "level"
// of subdivision
/// Saves a pointer indicating the beginning of data pertaining to "level"
/// of subdivision
void SetMarker(int level, Type * marker) {
_markers[level] = marker;
}
// Resize the table to size (also resets markers)
/// Resize the table to size (also resets markers)
void Resize(int size) {
_data.resize(size);
_markers[0] = &_data[0];
}
// Returns a pointer to the data at the beginning of level "level" of
// subdivision
/// Returns a pointer to the data at the beginning of level "level" of
/// subdivision
Type * operator[](int level) {
assert(level>=0 and level<(int)_markers.size());
return _markers[level];
}
// Returns a const pointer to the data at the beginning of level "level"
// of subdivision
/// Returns a const pointer to the data at the beginning of level "level"
/// of subdivision
const Type * operator[](int level) const {
return const_cast<FarTable *>(this)->operator[](level);
}

View File

@ -62,31 +62,64 @@
#include <vector>
#include "../version.h"
#include "../far/table.h"
#include "../far/dispatcher.h"
#include "../hbr/vertexEdit.h"
template <class T> class HbrFace;
template <class T> class HbrHalfedge;
template <class T> class HbrVertex;
template <class T> class HbrMesh;
#include "../far/table.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
template <class T, class U> class FarMesh;
template <class T, class U> class FarMeshFactory;
template <class U> class FarMesh;
template <class U> class FarDispatcher;
template <class T, class U=T> class FarVertexEditTables {
/// \brief A serialized container for hierarchical edits.
///
/// Some of the hierarchical edits are resolved into the vertex weights computed
/// into the FarSubdivision tables. Certain edits however have to be "post-processed"
/// after the tables are applied to the vertices and require their HBR representation
/// to be serialized into a specific container.
///
class FarVertexEdit {
public:
FarVertexEditTables( FarMesh<T,U> * mesh, int maxlevel);
// type of edit operation. This enum matches to HbrHiearachicalEdit<T>::Operation
/// Type of edit operation - equivalent to HbrHiearachicalEdit<T>::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 <class U> 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 U> class FarVertexEditTables {
public:
FarVertexEditTables( FarMesh<U> * 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 +127,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<unsigned int> const & Get_Offsets() const { return _offsets; }
FarTable<unsigned int> const & GetVertexIndices() const { return _vertIndices; }
// Returns the edit values table
FarTable<float> const & Get_Values() const { return _values; }
FarTable<float> 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<T,U>;
template <class X, class Y> friend struct FarVertexEditTablesFactory;
friend class FarDispatcher<U>;
FarTable<unsigned int> _offsets; // absolute vertex index array for edits
FarTable<float> _values; // edit values array
FarTable<unsigned int> _vertIndices; // absolute vertex index array for edits
FarTable<float> _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<T,U>;
friend class FarDispatcher<T,U>;
private:
template <class X, class Y> friend struct FarVertexEditTablesFactory;
friend class FarDispatcher<U>;
// 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<T,U> * _mesh;
FarMesh<U> * _mesh;
std::vector<VertexEdit> _batches;
std::vector<VertexEditBatch> _batches;
};
template <class T, class U>
FarVertexEditTables<T,U>::VertexEdit::VertexEdit(int index, int width, Operation operation) :
_index(index),
_width(width),
_operation(operation) {
template <class U>
FarVertexEditTables<U>::VertexEditBatch::VertexEditBatch(int index, int width, FarVertexEdit::Operation op) :
_primvarIndex(index),
_primvarWidth(width),
_op(op) {
}
template <class T, class U>
template <class U>
void
FarVertexEditTables<T,U>::VertexEdit::ApplyVertexEdit(U * vsrc, int level) const
FarVertexEditTables<U>::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; i<n; ++i) {
U * vdst = vsrc + offsets[i];
// XXXX: tentative.
// consider adding new interface to vertex class without HbrVertexEdit,
// such as vdst->ApplyVertexEditAdd(const float *), vdst->ApplyVertexEditSet(const float *)
if (_operation == FarVertexEditTables<T,U>::Set) {
HbrVertexEdit<T> vedit(0, 0, 0, 0, 0, _width, false, HbrVertexEdit<T>::Set, const_cast<float*>(&values[i*_width]));
vdst->ApplyVertexEdit(vedit);
} else {
HbrVertexEdit<T> vedit(0, 0, 0, 0, 0, _width, false, HbrVertexEdit<T>::Add, const_cast<float*>(&values[i*_width]));
vdst->ApplyVertexEdit(vedit);
}
edit.SetEdit( const_cast<float*>(&values[i*GetPrimvarWidth()]) );
vdst->ApplyVertexEdit( edit );
}
}
template <class T, class U>
FarVertexEditTables<T,U>::FarVertexEditTables( FarMesh<T,U> * mesh, int maxlevel) :
template <class U>
FarVertexEditTables<U>::FarVertexEditTables( FarMesh<U> * mesh, int maxlevel) :
_mesh(mesh) {
}
template <class T, class U> void
FarVertexEditTables<T,U>::Apply( int level, void * clientdata ) const {
template <class U> void
FarVertexEditTables<U>::Apply( int level, void * clientdata ) const {
assert(this->_mesh and level>0);
FarDispatcher<T,U> const * dispatch = this->_mesh->GetDispatcher();
FarDispatcher<U> const * dispatch = this->_mesh->GetDispatcher();
assert(dispatch);
dispatch->ApplyVertexEdit(this->_mesh, 0, level, clientdata);
dispatch->ApplyVertexEdits(this->_mesh, 0, level, clientdata);
}
template <class T, class U> void
FarVertexEditTables<T,U>::editVertex(int level, void *clientdata) const {
template <class U> void
FarVertexEditTables<U>::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

View File

@ -0,0 +1,228 @@
//
// 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 <cassert>
#include <vector>
#include "../version.h"
#include "../hbr/vertexEdit.h"
#include "../far/vertexEditTables.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
/// \brief A specialized factory for FarVertexEditTables
///
/// Separating the factory allows us to isolate Far data structures from Hbr dependencies.
///
template <class T, class U> struct FarVertexEditTablesFactory {
/// Compares the number of subfaces in an edit (for sorting purposes)
static bool compareEdits(HbrVertexEdit<T> const *a, HbrVertexEdit<T> const *b);
/// Creates a FarVertexEditTables instance.
static FarVertexEditTables<U> * Create( FarMeshFactory<T,U> const * factory, FarMesh<U> * mesh, int maxlevel );
};
template <class T, class U> bool
FarVertexEditTablesFactory<T,U>::compareEdits(HbrVertexEdit<T> const *a, HbrVertexEdit<T> const *b) {
return a->GetNSubfaces() < b->GetNSubfaces();
}
template <class T, class U> FarVertexEditTables<U> *
FarVertexEditTablesFactory<T,U>::Create( FarMeshFactory<T,U> const * factory, FarMesh<U> * mesh, int maxlevel ) {
assert( factory and mesh );
FarVertexEditTables<U> * result = new FarVertexEditTables<U>(mesh, maxlevel);
std::vector<HbrHierarchicalEdit<T>*> const & hEdits = factory->_hbrMesh->GetHierarchicalEdits();
std::vector<HbrVertexEdit<T> const *> vertexEdits;
vertexEdits.reserve(hEdits.size());
for (int i=0; i<(int)hEdits.size(); ++i) {
HbrVertexEdit<T> *vedit = dynamic_cast<HbrVertexEdit<T> *>(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<int> batchIndices;
std::vector<int> batchSizes;
for(int i=0; i<(int)vertexEdits.size(); ++i) {
HbrVertexEdit<T> const *vedit = vertexEdits[i];
// translate operation enum
FarVertexEdit::Operation op = (vedit->GetOperation() == HbrHierarchicalEdit<T>::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<U>::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<numBatches; ++i) {
result->_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<int> currentLevels(numBatches);
std::vector<int> currentCounts(numBatches);
for(int i=0; i<(int)vertexEdits.size(); ++i){
HbrVertexEdit<T> const *vedit = vertexEdits[i];
HbrFace<T> * f = factory->_hbrMesh->GetFace(vedit->GetFaceID());
int level = vedit->GetNSubfaces();
for (int j=0; j<level; ++j)
f = f->GetChild(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<U>::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<T>::Subtract);
for(int i=0; i<batch.GetPrimvarWidth(); ++i)
batch._edits[level-1][batchCount * batch.GetPrimvarWidth() + i] = negate ? -edit[i] : edit[i];
// Set table markers
batchCount++;
batch._vertIndices.SetMarker(level, &batch._vertIndices[level-1][batchCount]);
batch._edits.SetMarker(level, &batch._edits[level-1][batchCount * batch.GetPrimvarWidth()]);
}
for(int i=0; i<numBatches; ++i) {
typename FarVertexEditTables<U>::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 */

View File

@ -55,7 +55,7 @@
# a particular purpose and non-infringement.
#
set(H_FILES
set(PUBLIC_HEADER_FILES
allocator.h
bilinear.h
catmark.h
@ -75,6 +75,6 @@ set(H_FILES
vertex.h
)
install( FILES ${H_FILES}
install( FILES ${PUBLIC_HEADER_FILES}
DESTINATION include/hbr
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ )

View File

@ -75,6 +75,7 @@
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define CL_CHECK_ERROR(x, ...) { if(x != CL_SUCCESS) { printf("ERROR %d : ", x); printf(__VA_ARGS__);} }

View File

@ -115,7 +115,7 @@ public:
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const;
virtual void ApplyVertexEdit(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const {}
virtual void ApplyVertexEdits(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const {}
virtual void CopyTable(int tableIndex, size_t size, const void *ptr);

View File

@ -60,7 +60,6 @@
#include "../osd/cpuDispatcher.h"
#include "../osd/cpuKernel.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -292,19 +291,18 @@ OsdCpuKernelDispatcher::ApplyLoopVertexVerticesKernelA( FarMesh<OsdVertex> * mes
}
void
OsdCpuKernelDispatcher::ApplyVertexEdit(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const {
OsdCpuKernelDispatcher::ApplyVertexEdits(FarMesh<OsdVertex> *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<OsdVertex>::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<OsdVertex>::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]);
}
}
}

View File

@ -95,7 +95,7 @@ public:
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const;
virtual void ApplyVertexEdit(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const;
virtual void ApplyVertexEdits(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const;
virtual void CopyTable(int tableIndex, size_t size, const void *ptr);

View File

@ -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

View File

@ -58,8 +58,6 @@
#define OSD_CPU_KERNEL_H
#include "../version.h"
#include <stdio.h>
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;
};

View File

@ -330,17 +330,17 @@ OsdCudaKernelDispatcher::ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mes
}
void
OsdCudaKernelDispatcher::ApplyVertexEdit(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const {
OsdCudaKernelDispatcher::ApplyVertexEdits(FarMesh<OsdVertex> *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<OsdVertex>::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<OsdVertex>::Set) {
// XXX:
} else if (info.operation == FarVertexEdit::Set) {
// XXXX TODO
}
}
}

View File

@ -115,7 +115,7 @@ public:
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const;
virtual void ApplyVertexEdit(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const;
virtual void ApplyVertexEdits(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const;
virtual void CopyTable(int tableIndex, size_t size, const void *ptr);

View File

@ -98,7 +98,7 @@ public:
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const;
virtual void ApplyVertexEdit(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const {}
virtual void ApplyVertexEdits(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const {}
virtual void CopyTable(int tableIndex, size_t size, const void *ptr);

View File

@ -125,9 +125,9 @@ OsdMesh::createEditTables( FarVertexEditTables<OsdVertex> const *editTables ) {
_dispatcher->AllocateEditTables(numEditBatches);
for (int i=0; i<numEditBatches; ++i) {
const FarVertexEditTables<OsdVertex>::VertexEdit & edit = editTables->GetBatch(i);
_dispatcher->UpdateEditTable(i, edit.Get_Offsets(), edit.Get_Values(),
edit.GetOperation(), edit.GetPrimvarOffset(), edit.GetPrimvarWidth());
const FarVertexEditTables<OsdVertex>::VertexEditBatch & edit = editTables->GetBatch(i);
_dispatcher->UpdateEditTable(i, edit.GetVertexIndices(), edit.GetValues(),
edit.GetOperation(), edit.GetPrimvarIndex(), edit.GetPrimvarWidth());
}
}

View File

@ -77,7 +77,7 @@ typedef HbrVertex<OsdVertex> OsdHbrVertex;
typedef HbrFace<OsdVertex> OsdHbrFace;
typedef HbrHalfedge<OsdVertex> OsdHbrHalfedge;
template <class T, class U> class FarMesh;
template <class U> class FarMesh;
class OsdKernelDispatcher;
class OsdElementArrayBuffer;

View File

@ -80,4 +80,4 @@ using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif // OSD_PTEXTURE_H
#endif // OSD_MUTEX_H

View File

@ -65,18 +65,27 @@ namespace OPENSUBDIV_VERSION {
template <class T> class HbrVertexEdit;
template <class T> 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<OsdVertex> &) { }
void ApplyMovingVertexEdit(const HbrMovingVertexEdit<OsdVertex> &) { }
void ApplyVertexEdit(HbrVertexEdit<OsdVertex> const &) { }
void ApplyVertexEdit(FarVertexEdit const &) { }
void ApplyMovingVertexEdit(HbrMovingVertexEdit<OsdVertex> const &) { }
};
} // end namespace OPENSUBDIV_VERSION

View File

@ -57,6 +57,10 @@
#ifndef SHAPE_UTILS_H
#define SHAPE_UTILS_H
#include <hbr/mesh.h>
#include <hbr/bilinear.h>
#include <hbr/loop.h>
#include <hbr/catmark.h>
#include <hbr/vertexEdit.h>
#include <hbr/cornerEdit.h>

View File

@ -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<xyzVV> & edit) {
const float *src = edit.GetEdit();
switch(edit.GetOperation()) {
case OpenSubdiv::HbrHierarchicalEdit<xyzVV>::Set:
_pos[0] = src[0];
_pos[1] = src[1];
_pos[2] = src[2];
break;
case OpenSubdiv::HbrHierarchicalEdit<xyzVV>::Add:
_pos[0] += src[0];
_pos[1] += src[1];
_pos[2] += src[2];
break;
case OpenSubdiv::HbrHierarchicalEdit<xyzVV>::Subtract:
_pos[0] -= src[0];
_pos[1] -= src[1];
_pos[2] -= src[2];
break;
}
}
void ApplyVertexEdit(const OpenSubdiv::HbrVertexEdit<xyzVV> & edit) {
const float *src = edit.GetEdit();
switch(edit.GetOperation()) {
case OpenSubdiv::HbrHierarchicalEdit<xyzVV>::Set:
_pos[0] = src[0];
_pos[1] = src[1];
_pos[2] = src[2];
break;
case OpenSubdiv::HbrHierarchicalEdit<xyzVV>::Add:
_pos[0] += src[0];
_pos[1] += src[1];
_pos[2] += src[2];
break;
case OpenSubdiv::HbrHierarchicalEdit<xyzVV>::Subtract:
_pos[0] -= src[0];
_pos[1] -= src[1];
_pos[2] -= src[2];
break;
}
}
void ApplyMovingVertexEdit(const OpenSubdiv::HbrMovingVertexEdit<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<xyzVV> &) { }
const float * GetPos() const { return _pos; }

View File

@ -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<xyzVV> &) { }
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