Siggrpah 2012 - rolling over all of prepro work into beta 1.1

This commit is contained in:
manuelk 2012-08-03 19:51:27 -07:00
parent 2ebf29bbad
commit a1552cfe82
93 changed files with 11953 additions and 3535 deletions

View File

@ -103,19 +103,100 @@ find_package(OpenGL)
find_package(OpenCL) find_package(OpenCL)
find_package(CUDA) find_package(CUDA)
find_package(GLUT) find_package(GLUT)
find_package(PTex)
if (NOT APPLE) if (NOT APPLE)
find_package(GLEW) find_package(GLEW REQUIRED)
endif() endif()
find_package(Maya) find_package(Maya)
# Warn about missing dependencies that will cause parts of OpenSubdiv to be
# disabled. Also, add preprocessor defines that can be used in the source
# code to determine if a specific dependency is present or not.
if(OPENMP_FOUND)
add_definitions(
-DOPENSUBDIV_HAS_OPENMP
${OpenMP_CXX_FLAGS}
)
else()
message(WARNING
"OpenMP was not found : support for OMP parallel compute kernels "
"will be diabled in Osd. If your compiler supports OpenMP "
"directives, please refer to the FindOpenMP.cmake shared module "
"in your cmake installation.")
endif()
# note : (GLSL compute kernels require GL 4.2, which currently excludes APPLE)
if(OPENGL_FOUND AND GLEW_FOUND AND (NOT APPLE))
add_definitions(
-DOPENSUBDIV_HAS_GLSL
)
else()
message(WARNING
"OpenGL was not found : support for GLSL parallel compute kernels "
"will be disabled in Osd. If you have an OpenGL SDK installed "
"(version 4.2 or above), please refer to the FindOpenGL.cmake "
"shared module in your cmake installation.")
endif()
if(OPENCL_FOUND)
add_definitions(
-DOPENSUBDIV_HAS_OPENCL
)
else()
message(WARNING
"OpenCL was not found : support for OpenCL parallel compute kernels "
"will be disabled in Osd. If you have the OpenCL SDK installed, "
"please refer to the FindOpenCL.cmake in ${PROJECT_SOURCE_DIR}/cmake.")
endif()
if(CUDA_FOUND)
add_definitions(
-DOPENSUBDIV_HAS_CUDA
)
else()
message(WARNING
"CUDA was not found : support for CUDA parallel compute kernels "
"will be disabled in Osd. If you have the CUDA SDK installed, please "
"refer to the FindCUDA.cmake shared module in your cmake installation.")
endif()
if(PTEX_FOUND)
add_definitions(
-DOPENSUBDIV_HAS_PTEX
)
else()
message(WARNING
"Ptex was not found : the OpenSubdiv Ptex example will not be "
"available. If you do have Ptex installed and see this message, "
"please add your Ptex path to FindPTex.cmake in "
"${PROJECT_SOURCE_DIR}/cmake or set it through the PTEX_LOCATION "
"cmake command line argument or environment variable."
)
endif()
if(MAYA_FOUND)
add_definitions(
-DOPENSUBDIV_HAS_MAYA
)
else()
message(WARNING
"Maya was not found : the OpenSubdiv mayaViwer plugin will not be "
"available. If you do have Maya installed and see this message, "
"please add your Maya path to FindMaya.cmake in "
"${PROJECT_SOURCE_DIR}/cmake or set it through the MAYA_LOCATION "
"cmake command line argument or environment variable."
)
endif()
# Link examples & regressions dynamically against Osd # Link examples & regressions dynamically against Osd
set( OSD_LINK_TARGET osd_dynamic ) set( OSD_LINK_TARGET osd_dynamic )
if (WIN32) if (WIN32)
add_definitions( add_definitions(
# GLEW gets built as a static library in Windows # Link against the static version of GLEW.
-DGLEW_STATIC -DGLEW_STATIC
) )
# Link examples & regressions statically against Osd for # Link examples & regressions statically against Osd for
@ -178,9 +259,11 @@ if(MSVC)
) )
endif(MSVC) endif(MSVC)
# Macro for adding a cuda executable if cuda is found and a regular # Macro for adding a cuda executable if cuda is found and a regular
# executable otherwise. # executable otherwise.
macro(_add_executable target) macro(_add_possibly_cuda_executable target)
if(CUDA_FOUND) if(CUDA_FOUND)
cuda_add_executable(${target} ${ARGN}) cuda_add_executable(${target} ${ARGN})
else() else()
@ -188,9 +271,10 @@ macro(_add_executable target)
endif() endif()
endmacro() endmacro()
# Macro for adding a cuda library if cuda is found and a regular # Macro for adding a cuda library if cuda is found and a regular
# library otherwise. # library otherwise.
macro(_add_library target) macro(_add_possibly_cuda_library target)
if(CUDA_FOUND) if(CUDA_FOUND)
cuda_add_library(${target} ${ARGN}) cuda_add_library(${target} ${ARGN})
else() else()
@ -199,6 +283,29 @@ macro(_add_library target)
endmacro() endmacro()
# Macro for adding a (potentially cuda) executable.
macro(_add_glut_executable target)
_add_possibly_cuda_executable(${target} ${ARGN})
if(WIN32)
# Windows needs some of its dependency dll's copied into the same
# directory as the executable.
set( LIBRARIES ${ILMBASE_LIBRARIES} ${GLUT_LIBRARIES})
foreach (LIB ${LIBRARIES} )
string(REPLACE ".lib" ".dll" DLL ${LIB})
string(REPLACE ".LIB" ".DLL" DLL ${DLL})
add_custom_command(
TARGET ${target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${DLL}
$<TARGET_FILE_DIR:${target}>
)
endforeach()
endif()
endmacro()
add_subdirectory(opensubdiv) add_subdirectory(opensubdiv)

View File

@ -1,6 +1,6 @@
# OpenSubdiv # # OpenSubdiv #
OpenSubdiv is a set of open source libraries that implement high performance subdivision surface (subdiv) evaluation on massively parallel CPU and GPU architectures. This codepath is optimized for drawing deforming subdivs with static topology at interactive framerates. OpenSubdiv can amplify a 30,000 polygon base mesh into a smooth limit surface of 500,000 polygons in under 3 milliseconds on Kepler Nvidia hardware. The architecture features a precomputation step that uses Renderman's hbr library to compute fast run time data structures that are evaluated with backends in any of C++, CUDA, OpenCL, or GLSL. The resulting limit surface matches Pixar's Renderman to numerical precision. OpenSubdiv also includes support for semi-sharp creases and hierarchical edits on subdivs which both are powerful tools for shaping surfaces. OpenSubdiv is a set of open source libraries that implement high performance subdivision surface (subdiv) evaluation on massively parallel CPU and GPU architectures. This codepath is optimized for drawing deforming subdivs with static topology at interactive framerates. OpenSubdiv can amplify a 30,000 polygon base mesh into a smooth limit surface of 500,000 polygons in under 3 milliseconds on Kepler Nvidia hardware. The architecture features a precomputation step that uses Renderman's hbr library to compute fast run time data structures that are evaluated with backends in any of C++, CUDA, OpenCL, or GLSL. The resulting limit surface matches Pixar's Renderman to numerical precision. OpenSubdiv also includes support for semi-sharp creases and hierarchical edits on subdivs which both are powerful tools for shaping surfaces.
OpenSubdiv is covered by the Microsoft Public License (included below), and is free to use for commercial or non-commercial use. All Pixar patents covering algorithms used inside for semi-sharp crease evaluation and texture coordinate interpolation have also been released for public use. Our intent is to encourage high performance accurate subdiv drawing by giving away the "good stuff" that we use internally. We welcome any involvement in the development or extension of this code, we'd love it in fact. Please contact us if you're interested. OpenSubdiv is covered by the Microsoft Public License (included below), and is free to use for commercial or non-commercial use. All Pixar patents covering algorithms used inside for semi-sharp crease evaluation and texture coordinate interpolation have also been released for public use. Our intent is to encourage high performance accurate subdiv drawing by giving away the "good stuff" that we use internally. We welcome any involvement in the development or extension of this code, we'd love it in fact. Please contact us if you're interested.
@ -39,7 +39,7 @@ Optional :
make make
</code></pre> </code></pre>
### Useful cmake options ### ### Useful cmake options and environment variables ###
<pre><code> <pre><code>
-DCMAKE_BUILD_TYPE=[Debug|Release] -DCMAKE_BUILD_TYPE=[Debug|Release]
@ -48,8 +48,17 @@ Optional :
-DMAYA_LOCATION=[path to Maya] -DMAYA_LOCATION=[path to Maya]
-DPTEX_LOCATION=[path to Ptex]
-DGLUT_LOCATION=[path to GLUT]
-DGLEW_LOCATION=[path to GLEW]
</code></pre> </code></pre>
The paths to Maya, Ptex, GLUT, and GLEW can also be specified through the
following environment variables: MAYA_LOCATION, PTEX_LOCATION, GLUT_LOCATION,
and GLEW_LOCATION.
### Standalone viewer ### ### Standalone viewer ###
<pre><code> <pre><code>
@ -70,12 +79,12 @@ Optional :
Subdivision surfaces are commonly used for final rendering of character shapes for a smooth and controllable limit surfaces. However, subdivision surfaces in interactive apps are typically drawn as their polygonal control hulls because of performance. The polygonal control hull is an approximation that is offset from the true limit surface, Looking at an approximation in the interactive app makes it difficult to see exact contact, like fingers touching a potion bottle or hands touching a cheek. It also makes it difficult to see poke throughs in cloth simulation if the skin and cloth are both approximations. This problem is particularly bad when one character is much larger than another and unequal subdiv face sizes cause approximations errors to be magnified. Subdivision surfaces are commonly used for final rendering of character shapes for a smooth and controllable limit surfaces. However, subdivision surfaces in interactive apps are typically drawn as their polygonal control hulls because of performance. The polygonal control hull is an approximation that is offset from the true limit surface, Looking at an approximation in the interactive app makes it difficult to see exact contact, like fingers touching a potion bottle or hands touching a cheek. It also makes it difficult to see poke throughs in cloth simulation if the skin and cloth are both approximations. This problem is particularly bad when one character is much larger than another and unequal subdiv face sizes cause approximations errors to be magnified.
Maya and Pixar's Presto animation system can take 100ms to subdivide a character of 30,000 polygons to the second level of subdivision (500,000 polygons). By doing the same thing in 3ms OpenSubdiv allows the user to see the smooth, accurate limit surface at all times. Maya and Pixar's Presto animation system can take 100ms to subdivide a character of 30,000 polygons to the second level of subdivision (500,000 polygons). By doing the same thing in 3ms OpenSubdiv allows the user to see the smooth, accurate limit surface at all times.
## Components ## ## Components ##
#### hbr (hierarchical boundary rep) #### #### hbr (hierarchical boundary rep) ####
This base library implements a half edge data structure to store edges, faces, and vertices of a subdivision surface. This code was authored by Julian Fong on the Renderman team. It is the lowest level subdivision libary in renderman. Separate objects are allocated for each vertex and edge (*2) with pointers to neighboring vertices and edges. Hbr is a generic templated API used by clients to create concrete instances by providing the implementation of the vertex class. This base library implements a half edge data structure to store edges, faces, and vertices of a subdivision surface. This code was authored by Julian Fong on the Renderman team. It is the lowest level subdivision libary in renderman. Separate objects are allocated for each vertex and edge (*2) with pointers to neighboring vertices and edges. Hbr is a generic templated API used by clients to create concrete instances by providing the implementation of the vertex class.
#### far (feature-adaptive rep) #### #### far (feature-adaptive rep) ####
Far uses hbr to create and cache fast run time data structures for table driven subdivision of vertices and cubic patches for limit surface evaluation. Feature-adaptive refinement logic is used to adaptively refine coarse topology near features like extrordinary vertices and creases in order to make the topology amenable to cubic patch evaluation. Far is also a generic templated algorthmic base API that clients in higher levels instantiate and use by providing an implementation of a vertex class. Subdivision schemes supported: Far uses hbr to create and cache fast run time data structures for table driven subdivision of vertices and cubic patches for limit surface evaluation. Feature-adaptive refinement logic is used to adaptively refine coarse topology near features like extrordinary vertices and creases in order to make the topology amenable to cubic patch evaluation. Far is also a generic templated algorthmic base API that clients in higher levels instantiate and use by providing an implementation of a vertex class. Subdivision schemes supported:
@ -115,7 +124,7 @@ The second release of OpenSubdiv raises the performance bar to what we believe i
This release will also complete hierarchical edit support and support for face varying coordinate interpolation. This release will also complete hierarchical edit support and support for face varying coordinate interpolation.
We are targeting release 2 for end of year 2012, hopefully earlier than that. We have the patch code working in a very rough implementation but need to rewrite that in a development branch for release-ready code. Let us know if you're interested in contributing to that effort! We are targeting release 2 for end of year 2012, hopefully earlier than that. We have the patch code working in a very rough implementation but need to rewrite that in a development branch for release-ready code. Let us know if you're interested in contributing to that effort!
## Wish List ## ## Wish List ##

View File

@ -62,25 +62,27 @@
# GLEW_FOUND # GLEW_FOUND
# GLEW_INCLUDE_DIR # GLEW_INCLUDE_DIR
# GLEW_LIBRARY # GLEW_LIBRARY
# #
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
if (WIN32) if (WIN32)
find_path( GLEW_INCLUDE_DIR find_path( GLEW_INCLUDE_DIR
NAMES NAMES
GL/glew.h GL/glew.h
PATHS PATHS
${GLEW_LOCATION}/include ${GLEW_LOCATION}/include
$ENV{GLEW_LOCATION}/include
$ENV{PROGRAMFILES}/GLEW/include $ENV{PROGRAMFILES}/GLEW/include
${PROJECT_SOURCE_DIR}/extern/glew/include ${PROJECT_SOURCE_DIR}/extern/glew/include
DOC "The directory where GL/glew.h resides" ) DOC "The directory where GL/glew.h resides" )
find_library( GLEW_LIBRARY find_library( GLEW_LIBRARY
NAMES NAMES
glew GLEW glew32s glew32 glew GLEW glew32s glew32
PATHS PATHS
${GLEW_LOCATION}/lib ${GLEW_LOCATION}/lib
$ENV{GLEW_LOCATION}/lib
$ENV{PROGRAMFILES}/GLEW/lib $ENV{PROGRAMFILES}/GLEW/lib
${PROJECT_SOURCE_DIR}/extern/glew/bin ${PROJECT_SOURCE_DIR}/extern/glew/bin
${PROJECT_SOURCE_DIR}/extern/glew/lib ${PROJECT_SOURCE_DIR}/extern/glew/lib
@ -88,11 +90,12 @@ if (WIN32)
endif () endif ()
if (${CMAKE_HOST_UNIX}) if (${CMAKE_HOST_UNIX})
find_path( GLEW_INCLUDE_DIR find_path( GLEW_INCLUDE_DIR
NAMES NAMES
GL/glew.h GL/glew.h
PATHS PATHS
${GLEW_LOCATION}/include ${GLEW_LOCATION}/include
$ENV{GLEW_LOCATION}/include
/usr/include /usr/include
/usr/local/include /usr/local/include
/sw/include /sw/include
@ -101,10 +104,11 @@ if (${CMAKE_HOST_UNIX})
DOC "The directory where GL/glew.h resides" DOC "The directory where GL/glew.h resides"
) )
find_library( GLEW_LIBRARY find_library( GLEW_LIBRARY
NAMES NAMES
GLEW glew GLEW glew
PATHS PATHS
${GLEW_LOCATION}/lib ${GLEW_LOCATION}/lib
$ENV{GLEW_LOCATION}/lib
/usr/lib64 /usr/lib64
/usr/lib /usr/lib
/usr/local/lib64 /usr/local/lib64

View File

@ -62,16 +62,19 @@
# GLUT_FOUND # GLUT_FOUND
# GLUT_INCLUDE_DIR # GLUT_INCLUDE_DIR
# GLUT_LIBRARIES # GLUT_LIBRARIES
# #
if (WIN32) if (WIN32)
if(CYGWIN) if(CYGWIN)
find_path( GLUT_INCLUDE_DIR GL/glut.h find_path( GLUT_INCLUDE_DIR GL/glut.h
${GLUT_LOCATION}/include ${GLUT_LOCATION}/include
$ENV{GLUT_LOCATION}/include
/usr/include /usr/include
) )
find_library( GLUT_glut_LIBRARY glut32 freeglut find_library( GLUT_glut_LIBRARY glut32 freeglut
${GLUT_LOCATION}/lib ${GLUT_LOCATION}/lib
${GLUT_LOCATION}/lib/x64
$ENV{GLUT_LOCATION}/lib
${OPENGL_LIBRARY_DIR} ${OPENGL_LIBRARY_DIR}
/usr/lib /usr/lib
/usr/lib/w32api /usr/lib/w32api
@ -81,6 +84,7 @@ if (WIN32)
else() else()
find_path( GLUT_INCLUDE_DIR GL/glut.h find_path( GLUT_INCLUDE_DIR GL/glut.h
${GLUT_LOCATION}/include ${GLUT_LOCATION}/include
$ENV{GLUT_LOCATION}/include
${PROJECT_SOURCE_DIR}/extern/glut/include ${PROJECT_SOURCE_DIR}/extern/glut/include
$ENV{PROGRAMFILES}/GLUT/include $ENV{PROGRAMFILES}/GLUT/include
${OPENGL_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR}
@ -89,6 +93,8 @@ if (WIN32)
NAMES glut32 glut32s glut freeglut NAMES glut32 glut32s glut freeglut
PATHS PATHS
${GLUT_LOCATION}/lib ${GLUT_LOCATION}/lib
${GLUT_LOCATION}/lib/x64
$ENV{GLUT_LOCATION}/lib
${PROJECT_SOURCE_DIR}/extern/glut/bin ${PROJECT_SOURCE_DIR}/extern/glut/bin
${PROJECT_SOURCE_DIR}/extern/glut/lib ${PROJECT_SOURCE_DIR}/extern/glut/lib
$ENV{PROGRAMFILES}/GLUT/lib $ENV{PROGRAMFILES}/GLUT/lib
@ -103,11 +109,12 @@ else ()
/System/Library/Frameworks/GLUT.framework/Versions/A/Headers /System/Library/Frameworks/GLUT.framework/Versions/A/Headers
${OPENGL_LIBRARY_DIR} ${OPENGL_LIBRARY_DIR}
) )
set(GLUT_glut_LIBRARY "-framework Glut" CACHE STRING "GLUT library for OSX") set(GLUT_glut_LIBRARY "-framework Glut" CACHE STRING "GLUT library for OSX")
set(GLUT_cocoa_LIBRARY "-framework Cocoa" CACHE STRING "Cocoa framework for OSX") set(GLUT_cocoa_LIBRARY "-framework Cocoa" CACHE STRING "Cocoa framework for OSX")
else () else ()
find_path( GLUT_INCLUDE_DIR GL/glut.h find_path( GLUT_INCLUDE_DIR GL/glut.h
${GLUT_LOCATION}/include ${GLUT_LOCATION}/include
$ENV{GLUT_LOCATION}/include
/usr/include /usr/include
/usr/include/GL /usr/include/GL
/usr/local/include /usr/local/include
@ -120,6 +127,7 @@ else ()
) )
find_library( GLUT_glut_LIBRARY glut find_library( GLUT_glut_LIBRARY glut
${GLUT_LOCATION}/lib ${GLUT_LOCATION}/lib
$ENV{GLUT_LOCATION}/lib
/usr/lib /usr/lib
/usr/local/lib /usr/local/lib
/usr/openwin/lib /usr/openwin/lib
@ -127,6 +135,7 @@ else ()
) )
find_library( GLUT_Xi_LIBRARY Xi find_library( GLUT_Xi_LIBRARY Xi
${GLUT_LOCATION}/lib ${GLUT_LOCATION}/lib
$ENV{GLUT_LOCATION}/lib
/usr/lib /usr/lib
/usr/local/lib /usr/local/lib
/usr/openwin/lib /usr/openwin/lib
@ -134,6 +143,7 @@ else ()
) )
find_library( GLUT_Xmu_LIBRARY Xmu find_library( GLUT_Xmu_LIBRARY Xmu
${GLUT_LOCATION}/lib ${GLUT_LOCATION}/lib
$ENV{GLUT_LOCATION}/lib
/usr/lib /usr/lib
/usr/local/lib /usr/local/lib
/usr/openwin/lib /usr/openwin/lib
@ -151,7 +161,7 @@ if(GLUT_INCLUDE_DIR)
set( GLUT_LIBRARIES set( GLUT_LIBRARIES
${GLUT_glut_LIBRARY} ${GLUT_glut_LIBRARY}
${GLUT_Xmu_LIBRARY} ${GLUT_Xmu_LIBRARY}
${GLUT_Xi_LIBRARY} ${GLUT_Xi_LIBRARY}
${GLUT_cocoa_LIBRARY} ${GLUT_cocoa_LIBRARY}
) )
set( GLUT_FOUND "YES" ) set( GLUT_FOUND "YES" )
@ -175,4 +185,4 @@ mark_as_advanced(
GLUT_Xmu_LIBRARY GLUT_Xmu_LIBRARY
GLUT_Xi_LIBRARY GLUT_Xi_LIBRARY
) )

View File

@ -58,9 +58,9 @@
# - Try to find the IlmBase library # - Try to find the IlmBase library
# Once done this will define # Once done this will define
# #
# ILMBASE_FOUND - System has OPENCL # ILMBASE_FOUND - System has IlmBase
# ILMBASE_INCLUDE_DIR - The include directory # ILMBASE_INCLUDE_DIR - The include directory
# ILMBASE_LIBS_DIRECTORY - The libraries needed # ILMBASE_LIBRARIES - The libraries needed
IF(NOT DEFINED ILMBASE_LOCATION) IF(NOT DEFINED ILMBASE_LOCATION)
IF ( ${CMAKE_HOST_UNIX} ) IF ( ${CMAKE_HOST_UNIX} )
@ -68,17 +68,17 @@ IF(NOT DEFINED ILMBASE_LOCATION)
# TODO: set to default install path when shipping out # TODO: set to default install path when shipping out
SET( ILMBASE_LOCATION NOTFOUND ) SET( ILMBASE_LOCATION NOTFOUND )
ELSE() ELSE()
SET(ILMBASE_LOCATION "/usr/local/ilmbase-1.0.1/" ) SET(ILMBASE_LOCATION /usr/local/ilmbase-1.0.1 )
ENDIF() ENDIF()
ELSE() ELSE()
IF ( WIN32 ) IF ( WIN32 )
SET( ILMBASE_LOCATION "C:/Program Files (x86)/ilmbase-1.0.1/" ) # Note: This assumes that the Deploy directory has been copied
ELSEIF ( WIN64 ) # back into the IlmBase root directory.
SET( ILMBASE_LOCATION "C:/Program Files (x86)/ilmbase-1.0.1/" ) SET( ILMBASE_LOCATION $ENV{PROGRAMFILES}/ilmbase-1.0.1/Deploy )
ENDIF() ENDIF()
ENDIF() ENDIF()
ENDIF() ENDIF()
IF ( ${CMAKE_HOST_UNIX} ) IF ( ${CMAKE_HOST_UNIX} )
SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -lpthread") SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -lpthread")
ELSE() ELSE()
@ -86,6 +86,11 @@ ENDIF()
SET(LIBRARY_PATHS SET(LIBRARY_PATHS
${ILMBASE_LOCATION}/lib ${ILMBASE_LOCATION}/lib
${ILMBASE_LOCATION}/lib/Release
${ILMBASE_LOCATION}/lib/x64/Release
$ENV{ILMBASE_LOCATION}/lib
$ENV{ILMBASE_LOCATION}/lib/Release
$ENV{ILMBASE_LOCATION}/lib/x64/Release
~/Library/Frameworks ~/Library/Frameworks
/Library/Frameworks /Library/Frameworks
/usr/local/lib /usr/local/lib
@ -97,13 +102,11 @@ SET(LIBRARY_PATHS
/usr/freeware/lib64 /usr/freeware/lib64
) )
IF( DEFINED ILMBASE_LIBRARY_DIR )
SET( LIBRARY_PATHS ${ILMBASE_LIBRARY_DIR} ${LIBRARY_PATHS} )
ENDIF()
SET(INCLUDE_PATHS SET(INCLUDE_PATHS
${ILMBASE_LOCATION}/include/OpenEXR/ ${ILMBASE_LOCATION}/include/OpenEXR/
${ILMBASE_LOCATION}/include
$ENV{ILMBASE_LOCATION}/include/OpenEXR/
$ENV{ILMBASE_LOCATION}/include
~/Library/Frameworks ~/Library/Frameworks
/Library/Frameworks /Library/Frameworks
/usr/local/include/OpenEXR/ /usr/local/include/OpenEXR/
@ -128,61 +131,54 @@ FIND_PATH( ILMBASE_INCLUDE_DIR ImathMath.h
NO_CMAKE_SYSTEM_PATH NO_CMAKE_SYSTEM_PATH
DOC "The directory where ImathMath.h resides" ) DOC "The directory where ImathMath.h resides" )
IF( NOT DEFINED ILMBASE_IEX_LIB ) FIND_LIBRARY( ILMBASE_IEX_LIB Iex
FIND_LIBRARY( ILMBASE_IEX_LIB Iex PATHS
PATHS ${LIBRARY_PATHS}
${LIBRARY_PATHS} NO_DEFAULT_PATH
NO_DEFAULT_PATH NO_CMAKE_ENVIRONMENT_PATH
NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_PATH
NO_CMAKE_PATH NO_SYSTEM_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH
NO_CMAKE_SYSTEM_PATH DOC "The Iex library" )
DOC "The Iex library" )
ENDIF()
IF( NOT DEFINED ILMBASE_ILMTHREAD_LIB ) FIND_LIBRARY( ILMBASE_ILMTHREAD_LIB IlmThread
FIND_LIBRARY( ILMBASE_ILMTHREAD_LIB IlmThread PATHS
PATHS ${LIBRARY_PATHS}
${LIBRARY_PATHS} NO_DEFAULT_PATH
NO_DEFAULT_PATH NO_CMAKE_ENVIRONMENT_PATH
NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_PATH
NO_CMAKE_PATH NO_SYSTEM_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH
NO_CMAKE_SYSTEM_PATH DOC "The IlmThread library" )
DOC "The IlmThread library" )
ENDIF()
IF( NOT DEFINED ILMBASE_IMATH_LIB )
FIND_LIBRARY( ILMBASE_IMATH_LIB Imath
PATHS
${LIBRARY_PATHS}
NO_DEFAULT_PATH
NO_CMAKE_ENVIRONMENT_PATH
NO_CMAKE_PATH
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH
DOC "The Imath library" )
ENDIF()
FIND_LIBRARY( ILMBASE_IMATH_LIB Imath
PATHS
${LIBRARY_PATHS}
NO_DEFAULT_PATH
NO_CMAKE_ENVIRONMENT_PATH
NO_CMAKE_PATH
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH
DOC "The Imath library" )
IF ( ${ILMBASE_IEX_LIB} STREQUAL "ILMBASE_IEX_LIB-NOTFOUND" ) IF ( ${ILMBASE_IEX_LIB} STREQUAL "ILMBASE_IEX_LIB-NOTFOUND" )
MESSAGE( FATAL_ERROR "ilmbase libraries (Iex) not found, required" ) MESSAGE( FATAL_ERROR "ilmbase libraries (Iex) not found, required: ILMBASE_LOCATION: ${ILMBASE_LOCATION}" )
ENDIF() ENDIF()
IF ( ${ILMBASE_ILMTHREAD_LIB} STREQUAL "ILMBASE_ILMTHREAD_LIB-NOTFOUND" ) IF ( ${ILMBASE_ILMTHREAD_LIB} STREQUAL "ILMBASE_ILMTHREAD_LIB-NOTFOUND" )
MESSAGE( FATAL_ERROR "ilmbase libraries (IlmThread) not found, required" ) MESSAGE( FATAL_ERROR "ilmbase libraries (IlmThread) not found, required: ILMBASE_LOCATION: ${ILMBASE_LOCATION}" )
ENDIF() ENDIF()
IF ( ${ILMBASE_IMATH_LIB} STREQUAL "ILMBASE_IMATH_LIB-NOTFOUND" ) IF ( ${ILMBASE_IMATH_LIB} STREQUAL "ILMBASE_IMATH_LIB-NOTFOUND" )
MESSAGE( FATAL_ERROR "ilmbase libraries (Imath) not found, required" ) MESSAGE( FATAL_ERROR "ilmbase libraries (Imath) not found, required: ILMBASE_LOCATION: ${ILMBASE_LOCATION}" )
ENDIF() ENDIF()
IF ( ${ILMBASE_INCLUDE_DIR} STREQUAL "ILMBASE_INCLUDE_DIR-NOTFOUND" ) IF ( ${ILMBASE_INCLUDE_DIR} STREQUAL "ILMBASE_INCLUDE_DIR-NOTFOUND" )
MESSAGE( FATAL_ERROR "ilmbase header files not found, required: ILMBASE_LOCATION: ${ILMBASE_LOCATION}" ) MESSAGE( FATAL_ERROR "ilmbase header files not found, required: ILMBASE_LOCATION: ${ILMBASE_LOCATION}" )
ENDIF() ENDIF()
SET( ILMBASE_LIBS_DIRECTORY SET( ILMBASE_LIBRARIES
${ILMBASE_IMATH_LIB} ${ILMBASE_IMATH_LIB}
${ILMBASE_ILMTHREAD_LIB} ${ILMBASE_ILMTHREAD_LIB}
${ILMBASE_IEX_LIB} ${ILMBASE_IEX_LIB}
@ -192,7 +188,7 @@ INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(IlmBase DEFAULT_MSG FIND_PACKAGE_HANDLE_STANDARD_ARGS(IlmBase DEFAULT_MSG
ILMBASE_LOCATION ILMBASE_LOCATION
ILMBASE_INCLUDE_DIR ILMBASE_INCLUDE_DIR
ILMBASE_LIBS_DIRECTORY ILMBASE_LIBRARIES
) )
SET( ILMBASE_FOUND TRUE ) SET( ILMBASE_FOUND TRUE )

View File

@ -56,18 +56,18 @@
# #
# - Maya finder module # - Maya finder module
# This module searches for a valid Maya instalation. # This module searches for a valid Maya instalation.
# It searches for Maya's devkit, libraries, executables # It searches for Maya's devkit, libraries, executables
# and related paths (scripts) # and related paths (scripts)
# #
# Variables that will be defined: # Variables that will be defined:
# MAYA_FOUND Defined if a Maya installation has been detected # MAYA_FOUND Defined if a Maya installation has been detected
# MAYA_EXECUTABLE Path to Maya's executable # MAYA_EXECUTABLE Path to Maya's executable
# MAYA_<lib>_FOUND Defined if <lib> has been found # MAYA_<lib>_FOUND Defined if <lib> has been found
# MAYA_<lib>_LIBRARY Path to <lib> library # MAYA_<lib>_LIBRARY Path to <lib> library
# MAYA_INCLUDE_DIRS Path to the devkit's include directories # MAYA_INCLUDE_DIRS Path to the devkit's include directories
# #
# IMPORTANT: Currently, there's only support for OSX platform and Maya version 2012. # IMPORTANT: Currently, there's only support for OSX platform and Maya version 2012.
#============================================================================= #=============================================================================
# Copyright 2011-2012 Francisco Requena <frarees@gmail.com> # Copyright 2011-2012 Francisco Requena <frarees@gmail.com>
@ -88,83 +88,97 @@ SET(MAYA_VERSION_2012 TRUE)
IF(APPLE) IF(APPLE)
FIND_PATH(MAYA_BASE_DIR include/maya/MFn.h PATH FIND_PATH(MAYA_BASE_DIR include/maya/MFn.h PATH
ENV MAYA_LOCATION ${MAYA_LOCATION}
"/Applications/Autodesk/maya2012.17/Maya.app/Contents" $ENV{MAYA_LOCATION}
"/Applications/Autodesk/maya2012/Maya.app/Contents" "/Applications/Autodesk/maya2013/Maya.app/Contents"
"/Applications/Autodesk/maya2011/Maya.app/Contents" "/Applications/Autodesk/maya2012.17/Maya.app/Contents"
"/Applications/Autodesk/maya2010/Maya.app/Contents" "/Applications/Autodesk/maya2012/Maya.app/Contents"
) "/Applications/Autodesk/maya2011/Maya.app/Contents"
"/Applications/Autodesk/maya2010/Maya.app/Contents"
)
FIND_PATH(MAYA_LIBRARY_DIR libOpenMaya.dylib FIND_PATH(MAYA_LIBRARY_DIR libOpenMaya.dylib
PATHS PATHS
ENV MAYA_LOCATION ${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR} ${MAYA_BASE_DIR}
PATH_SUFFIXES PATH_SUFFIXES
Maya.app/contents/MacOS/ Maya.app/contents/MacOS/
DOC "Maya's libraries path" DOC "Maya's libraries path"
) )
ENDIF(APPLE) ENDIF(APPLE)
IF(UNIX) IF(UNIX)
FIND_PATH(MAYA_BASE_DIR include/maya/MFn.h PATH FIND_PATH(MAYA_BASE_DIR include/maya/MFn.h PATH
ENV MAYA_LOCATION ${MAYA_LOCATION}
"/usr/autodesk/maya2012.17-x64" $ENV{MAYA_LOCATION}
"/usr/autodesk/maya2012-x64" "/usr/autodesk/maya2013-x64"
"/usr/autodesk/maya2011-x64" "/usr/autodesk/maya2012.17-x64"
"/usr/autodesk/maya2010-x64" "/usr/autodesk/maya2012-x64"
) "/usr/autodesk/maya2011-x64"
"/usr/autodesk/maya2010-x64"
)
FIND_PATH(MAYA_LIBRARY_DIR libOpenMaya.so FIND_PATH(MAYA_LIBRARY_DIR libOpenMaya.so
PATHS PATHS
ENV MAYA_LOCATION ${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR} ${MAYA_BASE_DIR}
PATH_SUFFIXES PATH_SUFFIXES
lib/ lib/
DOC "Maya's libraries path" DOC "Maya's libraries path"
) )
ENDIF(UNIX) ENDIF(UNIX)
IF(WIN32) IF(WIN32)
FIND_PATH(MAYA_BASE_DIR include/maya/MFn.h PATH FIND_PATH(MAYA_BASE_DIR include/maya/MFn.h PATH
ENV MAYA_LOCATION ${MAYA_LOCATION}
"C:/Program Files/Autodesk/Maya2012-x64" $ENV{MAYA_LOCATION}
"C:/Program Files/Autodesk/Maya2012" "C:/Program Files/Autodesk/Maya2013-x64"
"C:/Program Files (x86)/Autodesk/Maya2012" "C:/Program Files/Autodesk/Maya2013"
"C:/Autodesk/maya-2012x64" "C:/Program Files (x86)/Autodesk/Maya2013"
"C:/Program Files/Autodesk/Maya2011-x64" "C:/Autodesk/maya-2013x64"
"C:/Program Files/Autodesk/Maya2011" "C:/Program Files/Autodesk/Maya2012-x64"
"C:/Program Files (x86)/Autodesk/Maya2011" "C:/Program Files/Autodesk/Maya2012"
"C:/Autodesk/maya-2011x64" "C:/Program Files (x86)/Autodesk/Maya2012"
"C:/Program Files/Autodesk/Maya2010-x64" "C:/Autodesk/maya-2012x64"
"C:/Program Files/Autodesk/Maya2010" "C:/Program Files/Autodesk/Maya2011-x64"
"C:/Program Files (x86)/Autodesk/Maya2010" "C:/Program Files/Autodesk/Maya2011"
"C:/Autodesk/maya-2010x64" "C:/Program Files (x86)/Autodesk/Maya2011"
) "C:/Autodesk/maya-2011x64"
"C:/Program Files/Autodesk/Maya2010-x64"
"C:/Program Files/Autodesk/Maya2010"
"C:/Program Files (x86)/Autodesk/Maya2010"
"C:/Autodesk/maya-2010x64"
)
FIND_PATH(MAYA_LIBRARY_DIR OpenMaya.lib FIND_PATH(MAYA_LIBRARY_DIR OpenMaya.lib
PATHS PATHS
ENV MAYA_LOCATION ${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR} ${MAYA_BASE_DIR}
PATH_SUFFIXES PATH_SUFFIXES
lib/ lib/
DOC "Maya's libraries path" DOC "Maya's libraries path"
) )
ENDIF(WIN32) ENDIF(WIN32)
FIND_PATH(MAYA_INCLUDE_DIR maya/MFn.h FIND_PATH(MAYA_INCLUDE_DIR maya/MFn.h
PATHS PATHS
ENV MAYA_LOCATION ${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR} ${MAYA_BASE_DIR}
PATH_SUFFIXES PATH_SUFFIXES
../../devkit/include/ ../../devkit/include/
include/ include/
DOC "Maya's devkit headers path" DOC "Maya's devkit headers path"
) )
FIND_PATH(MAYA_LIBRARY_DIR OpenMaya FIND_PATH(MAYA_LIBRARY_DIR OpenMaya
PATHS PATHS
ENV MAYA_LOCATION ${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR} ${MAYA_BASE_DIR}
PATH_SUFFIXES PATH_SUFFIXES
../../devkit/include/ ../../devkit/include/
include/ include/
DOC "Maya's devkit headers path" DOC "Maya's devkit headers path"
) )
@ -172,10 +186,11 @@ LIST(APPEND MAYA_INCLUDE_DIRS ${MAYA_INCLUDE_DIR})
FIND_PATH(MAYA_DEVKIT_INC_DIR GL/glext.h FIND_PATH(MAYA_DEVKIT_INC_DIR GL/glext.h
PATHS PATHS
ENV MAYA_LOCATION ${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR} ${MAYA_BASE_DIR}
PATH_SUFFIXES PATH_SUFFIXES
/devkit/plug-ins/ /devkit/plug-ins/
DOC "Maya's devkit headers path" DOC "Maya's devkit headers path"
) )
LIST(APPEND MAYA_INCLUDE_DIRS ${MAYA_DEVKIT_INC_DIR}) LIST(APPEND MAYA_INCLUDE_DIRS ${MAYA_DEVKIT_INC_DIR})
@ -185,7 +200,7 @@ FOREACH(MAYA_LIB
OpenMayaAnim OpenMayaAnim
OpenMayaFX OpenMayaFX
OpenMayaRender OpenMayaRender
OpenMayaUI OpenMayaUI
Image Image
Foundation Foundation
IMFbase IMFbase
@ -195,24 +210,26 @@ FOREACH(MAYA_LIB
) )
FIND_LIBRARY(MAYA_${MAYA_LIB}_LIBRARY ${MAYA_LIB} FIND_LIBRARY(MAYA_${MAYA_LIB}_LIBRARY ${MAYA_LIB}
PATHS PATHS
ENV MAYA_LOCATION ${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR} ${MAYA_BASE_DIR}
PATH_SUFFIXES PATH_SUFFIXES
MacOS/ MacOS/
lib/ lib/
DOC "Maya's ${MAYA_LIB} library path" DOC "Maya's ${MAYA_LIB} library path"
) )
LIST(APPEND ${MAYA_LIBRARIES} MAYA_${MAYA_LIB}_LIBRARY) LIST(APPEND ${MAYA_LIBRARIES} MAYA_${MAYA_LIB}_LIBRARY)
ENDFOREACH(MAYA_LIB) ENDFOREACH(MAYA_LIB)
FIND_PROGRAM(MAYA_EXECUTABLE maya FIND_PROGRAM(MAYA_EXECUTABLE maya
PATHS PATHS
ENV MAYA_LOCATION ${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR} ${MAYA_BASE_DIR}
PATH_SUFFIXES PATH_SUFFIXES
MacOS/ MacOS/
bin/ bin/
DOC "Maya's executable path" DOC "Maya's executable path"
) )

View File

@ -67,32 +67,32 @@ find_package(PackageHandleStandardArgs)
if (APPLE) if (APPLE)
find_library( OPENCL_LIBRARIES find_library( OPENCL_LIBRARIES
NAMES NAMES
OpenCL OpenCL
DOC "OpenCL lib for OSX" DOC "OpenCL lib for OSX"
) )
find_path( OPENCL_INCLUDE_DIRS find_path( OPENCL_INCLUDE_DIRS
NAMES NAMES
OpenCL/cl.h OpenCL/cl.h
DOC "Include for OpenCL on OSX" DOC "Include for OpenCL on OSX"
) )
find_path( _OPENCL_CPP_INCLUDE_DIRS find_path( _OPENCL_CPP_INCLUDE_DIRS
NAMES NAMES
OpenCL/cl.hpp OpenCL/cl.hpp
DOC "Include for OpenCL CPP bindings on OSX" DOC "Include for OpenCL CPP bindings on OSX"
) )
elseif (WIN32) elseif (WIN32)
find_path( OPENCL_INCLUDE_DIRS find_path( OPENCL_INCLUDE_DIRS
NAMES NAMES
CL/cl.h CL/cl.h
) )
find_path( _OPENCL_CPP_INCLUDE_DIRS find_path( _OPENCL_CPP_INCLUDE_DIRS
NAMES NAMES
CL/cl.hpp CL/cl.hpp
) )
@ -103,39 +103,39 @@ elseif (WIN32)
set(OPENCL_LIB_DIR "$ENV{ATISTREAMSDKROOT}/lib/x86") set(OPENCL_LIB_DIR "$ENV{ATISTREAMSDKROOT}/lib/x86")
endif() endif()
find_library( OPENCL_LIBRARIES find_library( OPENCL_LIBRARIES
NAMES NAMES
OpenCL.lib OpenCL.lib
PATHS PATHS
${OPENCL_LIB_DIR} ${OPENCL_LIB_DIR}
ENV OpenCL_LIBPATH ENV OpenCL_LIBPATH
) )
get_filename_component( _OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE ) get_filename_component( _OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE )
find_path( OPENCL_INCLUDE_DIRS find_path( OPENCL_INCLUDE_DIRS
NAMES NAMES
CL/cl.h CL/cl.h
PATHS PATHS
"${_OPENCL_INC_CAND}" "${_OPENCL_INC_CAND}"
ENV OpenCL_INCPATH ENV OpenCL_INCPATH
) )
find_path( _OPENCL_CPP_INCLUDE_DIRS find_path( _OPENCL_CPP_INCLUDE_DIRS
NAMES NAMES
CL/cl.hpp CL/cl.hpp
PATHS PATHS
"${_OPENCL_INC_CAND}" "${_OPENCL_INC_CAND}"
ENV OpenCL_INCPATH ENV OpenCL_INCPATH
) )
elseif (UNIX) elseif (UNIX)
find_library( OPENCL_LIBRARIES find_library( OPENCL_LIBRARIES
NAMES NAMES
OpenCL OpenCL
PATHS PATHS
ENV LD_LIBRARY_PATH ENV LD_LIBRARY_PATH
ENV OpenCL_LIBPATH ENV OpenCL_LIBPATH
) )
@ -143,29 +143,29 @@ elseif (UNIX)
get_filename_component( _OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE ) get_filename_component( _OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE )
find_path( OPENCL_INCLUDE_DIRS find_path( OPENCL_INCLUDE_DIRS
NAMES NAMES
CL/cl.h CL/cl.h
PATHS PATHS
${_OPENCL_INC_CAND} ${_OPENCL_INC_CAND}
"/usr/local/cuda/include" "/usr/local/cuda/include"
"/opt/AMDAPP/include" "/opt/AMDAPP/include"
ENV OpenCL_INCPATH ENV OpenCL_INCPATH
) )
find_path( _OPENCL_CPP_INCLUDE_DIRS find_path( _OPENCL_CPP_INCLUDE_DIRS
NAMES NAMES
CL/cl.hpp CL/cl.hpp
PATHS PATHS
${_OPENCL_INC_CAND} ${_OPENCL_INC_CAND}
"/usr/local/cuda/include" "/usr/local/cuda/include"
"/opt/AMDAPP/include" "/opt/AMDAPP/include"
ENV OpenCL_INCPATH ENV OpenCL_INCPATH
) )
else () else ()
message( "Could not determine OpenCL platform" ) message( "Could not determine OpenCL platform" )
endif () endif ()

129
cmake/FindPTex.cmake Normal file
View File

@ -0,0 +1,129 @@
#
# 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.
#
#
# Try to find PTex library and include path.
# Once done this will define
#
# PTEX_FOUND
# PTEX_INCLUDE_DIR
# PTEX_LIBRARY
#
if (WIN32)
find_path( PTEX_INCLUDE_DIR
NAMES
Ptexture.h
PATHS
${PTEX_LOCATION}/include
$ENV{PTEX_LOCATION}/include
$ENV{PROGRAMFILES}/Ptex/include
/usr/include
DOC "The directory where Ptexture.h resides")
find_library( PTEX_LIBRARY
NAMES
Ptex32 Ptex32s Ptex
PATHS
${PTEX_LOCATION}/lib
$ENV{PTEX_LOCATION}/lib
$ENV{PROGRAMFILES}/Ptex/lib
/usr/lib
/usr/lib/w32api
/usr/local/lib
/usr/X11R6/lib
DOC "The Ptex library")
else ()
find_path( PTEX_INCLUDE_DIR
NAMES
Ptexture.h
PATHS
${PTEX_LOCATION}/include
${PTEX_LOCATION}/include/wdas
$ENV{PTEX_LOCATION}/include
$ENV{PTEX_LOCATION}/include/wdas
/usr/include
/usr/local/include
/usr/openwin/share/include
/usr/openwin/include
/usr/X11R6/include
/usr/include/X11
DOC "The directory where Ptexture.h resides")
find_library( PTEX_LIBRARY
NAMES
Ptex wdasPtex
PATHS
${PTEX_LOCATION}/lib
$ENV{PTEX_LOCATION}/lib
/usr/lib
/usr/local/lib
/usr/openwin/lib
/usr/X11R6/lib
DOC "The Ptex library")
endif ()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PTEX DEFAULT_MSG
PTEX_INCLUDE_DIR
PTEX_LIBRARY
)
mark_as_advanced(
PTEX_INCLUDE_DIR
PTEX_LIBRARY
)

View File

@ -55,43 +55,38 @@
# a particular purpose and non-infringement. # a particular purpose and non-infringement.
# #
if (APPLE) if( OPENGL_FOUND AND (GLEW_FOUND AND GLUT_FOUND) OR (APPLE AND GLUT_FOUND))
message(STATUS "The OsX platform currently does not support all " add_subdirectory(glutViewer)
"the OpenGL features required by the glutViewer example : skipping.") if(PTEX_FOUND AND (NOT APPLE))
else() add_subdirectory(ptexViewer)
if( OPENGL_FOUND AND GLEW_FOUND AND GLUT_FOUND)
add_subdirectory(glutViewer)
else()
set(MISSING "")
if (NOT OPENGL_FOUND)
list(APPEND MISSING OpenGL)
endif()
if (NOT GLEW_FOUND)
list(APPEND MISSING glew)
endif()
if (NOT GLUT_FOUND)
list(APPEND MISSING glut)
endif()
message(STATUS
"The following libraries could not be found : ${MISSING}. The glutViewer "
"example will not be available. If you have these libraries installed, "
"please specify their path to cmake (by setting the GLEW_LOCATION, GLUT_LOCATION "
"entries for instance)"
)
endif() endif()
else()
set(MISSING "")
if (NOT OPENGL_FOUND)
list(APPEND MISSING OpenGL)
endif()
if (NOT GLEW_FOUND)
list(APPEND MISSING glew)
endif()
if (NOT GLUT_FOUND)
list(APPEND MISSING glut)
endif()
message(WARNING
"The following libraries could not be found : ${MISSING}. "
"The glutViewer and ptexViewer examples will not be available. "
"If you have these libraries installed, please specify their "
"path to cmake (through the GLEW_LOCATION and GLUT_LOCATION "
"command line arguments or environment variables)."
)
endif() endif()
if(MAYA_FOUND) if(MAYA_FOUND)
add_subdirectory(mayaViewer) add_subdirectory(mayaViewer)
else() if(PTEX_FOUND)
message(STATUS add_subdirectory(mayaPtexViewer_siggraph2012)
"Maya could not be found, so the OpenSubdiv mayaViwer plugin will not " endif()
"be available. If you do have Maya installed and see this message, "
"please add your Maya path to cmake/FindMaya.cmake or set it in "
"the MAYA_LOCATION environment variable."
)
endif() endif()

View File

@ -68,7 +68,7 @@ inline int _ConvertSMVer2Cores_local(int major, int minor)
int Cores; int Cores;
} sSMtoCores; } sSMtoCores;
sSMtoCores nGpuArchCoresPerSM[] = sSMtoCores nGpuArchCoresPerSM[] =
{ { 0x10, 8 }, // Tesla Generation (SM 1.0) G80 class { { 0x10, 8 }, // Tesla Generation (SM 1.0) G80 class
{ 0x11, 8 }, // Tesla Generation (SM 1.1) G8x class { 0x11, 8 }, // Tesla Generation (SM 1.1) G8x class
{ 0x12, 8 }, // Tesla Generation (SM 1.2) G9x class { 0x12, 8 }, // Tesla Generation (SM 1.2) G9x class
@ -123,7 +123,7 @@ inline int cutGetMaxGflopsDeviceId()
// If we find GPU with SM major > 2, search only these // If we find GPU with SM major > 2, search only these
if ( best_SM_arch > 2 ) { if ( best_SM_arch > 2 ) {
// If our device==dest_SM_arch, choose this, or else pass // If our device==dest_SM_arch, choose this, or else pass
if (deviceProp.major == best_SM_arch) { if (deviceProp.major == best_SM_arch) {
max_compute_perf = compute_perf; max_compute_perf = compute_perf;
max_perf_device = current_device; max_perf_device = current_device;
} }

View File

@ -0,0 +1,69 @@
import maya.OpenMaya as OpenMaya
selectionList = OpenMaya.MSelectionList()
OpenMaya.MGlobal.getActiveSelectionList(selectionList)
path = OpenMaya.MDagPath()
selectionList.getDagPath(0, path)
meshFn = OpenMaya.MFnMesh(path)
points = OpenMaya.MPointArray()
normals = OpenMaya.MFloatVectorArray()
meshFn.getPoints(points)
meshFn.getVertexNormals(True, normals);
f = open('out.obj', 'w')
for i in range(0,points.length()):
f.write('v %f %f %f\n' % (points[i].x, points[i].y, points[i].z))
for i in range(0,points.length()):
f.write('vt 0 0 \n')
for i in range(0,normals.length()):
f.write('vn %f %f %f\n' % (normals[i].x, normals[i].y, normals[i].z))
f.write('s off\n')
vertexCount = OpenMaya.MIntArray()
vertexList = OpenMaya.MIntArray()
meshFn.getVertices(vertexCount, vertexList)
edgeIds = OpenMaya.MUintArray()
edgeCreaseData = OpenMaya.MDoubleArray()
vtxIds = OpenMaya.MUintArray()
vtxCreaseData = OpenMaya.MDoubleArray()
meshFn.getCreaseEdges(edgeIds, edgeCreaseData)
#meshFn.getCreaseVertices(vtxIds, vtxCreaseData)
vindex = 0
for i in range(0,vertexCount.length()):
f.write('f')
for j in range(0, vertexCount[i]):
v = vertexList[vindex] + 1
f.write(' %d/%d/%d' % (v, v, v))
vindex = vindex+1
f.write('\n')
if vtxIds.length() > 0:
f.write('t corner %d/%d/0' % (vtxIds.length(), vtxIds.length()))
for i in range(0,vtxIds.length()):
f.write(' %d' % vtxIds[i])
for i in range(0,vtxCreaseData.length()):
f.write(' %f' % vtxCreaseData[i])
f.write('\n')
for i in range(0, edgeIds.length()):
edgeIt = OpenMaya.MItMeshEdge(path)
dummy = OpenMaya.MScriptUtil().asIntPtr()
edgeIt.setIndex(edgeIds[i], dummy)
faceList = OpenMaya.MIntArray()
edgeIt.getConnectedFaces(faceList)
vid0 = edgeIt.index(0)
vid1 = edgeIt.index(1)
f.write('t crease 2/1/0 %d %d %f\n' % (vid0, vid1, edgeCreaseData[i]))
f.close()

View File

@ -71,39 +71,39 @@ class Stopwatch {
public: public:
#ifndef _WINDOWS #ifndef _WINDOWS
void Start() { void Start() {
struct timeval l_rtime; struct timeval l_rtime;
gettimeofday(&l_rtime,0); gettimeofday(&l_rtime,0);
_elapsed = l_rtime.tv_sec + l_rtime.tv_usec/1000000.0; _elapsed = l_rtime.tv_sec + l_rtime.tv_usec/1000000.0;
} }
void Stop() { void Stop() {
struct timeval l_rtime; struct timeval l_rtime;
gettimeofday(&l_rtime,0); gettimeofday(&l_rtime,0);
_elapsed = (l_rtime.tv_sec + l_rtime.tv_usec/1000000.0) - _elapsed; _elapsed = (l_rtime.tv_sec + l_rtime.tv_usec/1000000.0) - _elapsed;
_totalElapsed += _elapsed; _totalElapsed += _elapsed;
} }
double GetElapsed() const { double GetElapsed() const {
return _elapsed; return _elapsed;
} }
double GetTotalElapsed() const { double GetTotalElapsed() const {
return _totalElapsed; return _totalElapsed;
} }
#else #else
Stopwatch() { Stopwatch() {
QueryPerformanceFrequency(&_frequency); QueryPerformanceFrequency(&_frequency);
} }
void Start() void Start()
{ {
QueryPerformanceCounter(&_time); QueryPerformanceCounter(&_time);
} }
void Stop() void Stop()
{ {
LARGE_INTEGER currentTime; LARGE_INTEGER currentTime;
QueryPerformanceCounter(&currentTime); QueryPerformanceCounter(&currentTime);
_elapsed = currentTime.QuadPart - _time.QuadPart; _elapsed = currentTime.QuadPart - _time.QuadPart;
@ -113,7 +113,7 @@ public:
double GetElapsed() const { double GetElapsed() const {
return (double) _elapsed / _frequency.QuadPart; return (double) _elapsed / _frequency.QuadPart;
} }
double GetTotalElapsed() const { double GetTotalElapsed() const {
return (double) _totalElapsed / _frequency.QuadPart; return (double) _totalElapsed / _frequency.QuadPart;
} }

View File

@ -57,27 +57,18 @@
# *** glutViewer *** # *** glutViewer ***
set(PLATFORM_LIBRARIES set(SHADER_FILES
shader.glsl
)
set(PLATFORM_LIBRARIES
${OSD_LINK_TARGET} ${OSD_LINK_TARGET}
${ILMBASE_LIBS_DIRECTORY} ${ILMBASE_LIBRARIES}
${OPENGL_LIBRARY} ${OPENGL_LIBRARY}
${GLEW_LIBRARY} ${GLEW_LIBRARY}
${GLUT_LIBRARIES} ${GLUT_LIBRARIES}
) )
if(OPENCL_FOUND)
add_definitions(
-DOPENSUBDIV_HAS_OPENCL
)
endif()
if(CUDA_FOUND)
add_definitions(
-DOPENSUBDIV_HAS_CUDA
)
endif()
include_directories( include_directories(
${PROJECT_SOURCE_DIR}/opensubdiv ${PROJECT_SOURCE_DIR}/opensubdiv
${PROJECT_SOURCE_DIR}/regression ${PROJECT_SOURCE_DIR}/regression
@ -87,33 +78,38 @@ include_directories(
) )
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# Macro for adding a (potentially cuda) executable. # Shader Stringification
macro(_add_glut_executable target) # We want to use preprocessor include directives to include GLSL and OpenCL
# shader source files in cpp files, but since the sources contain newline
# characters we would need raw string literals from C++11 to do this directly.
# To avoid depending on C++11 we instead use a small tool called "line_quote"
# to generate source files that are suitable for direct inclusion.
foreach(shader_file ${SHADER_FILES})
_add_executable(${target} ${ARGN}) string(REGEX REPLACE ".*[.](.*)" "\\1" extension ${shader_file})
if(WIN32)
# Windows needs some of its dependency dll's copied into the same
# directory as the executable
set( LIBRARIES ${ILMBASE_LIBS_DIRECTORY} ${GLUT_LIBRARIES})
foreach (LIB ${LIBRARIES} )
string(REPLACE ".lib" ".dll" LIB ${LIB})
string(REPLACE ".LIB" ".DLL" LIB ${LIB})
add_custom_command(
TARGET ${target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${LIB}
$<TARGET_FILE_DIR:${target}>
)
endforeach()
endif()
endmacro()
string(REGEX REPLACE "(.*)[.].*" "\\1.inc" inc_file ${shader_file})
list(APPEND INC_FILES ${inc_file})
add_custom_command(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${inc_file}
COMMAND stringify ${CMAKE_CURRENT_SOURCE_DIR}/${shader_file}
${CMAKE_CURRENT_SOURCE_DIR}/${inc_file}
DEPENDS stringify ${CMAKE_CURRENT_SOURCE_DIR}/${shader_file}
)
endforeach()
if(APPLE)
_add_glut_executable(glutViewer _add_glut_executable(glutViewer
viewer.cpp viewer_compat.cpp
) )
else()
_add_glut_executable(glutViewer
viewer.cpp
${SHADER_FILES}
${INC_FILES}
)
endif()
target_link_libraries(glutViewer target_link_libraries(glutViewer
${PLATFORM_LIBRARIES} ${PLATFORM_LIBRARIES}

View File

@ -0,0 +1,245 @@
//
// 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.
//
#version 400
//--------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------
#ifdef VERTEX_SHADER
layout (location=0) in vec3 position;
layout (location=1) in vec3 normal;
out vec3 vPosition;
out vec3 vNormal;
out vec4 vColor;
void main()
{
vPosition = position;
vNormal = normal;
vColor = vec4(1, 1, 1, 1);
}
#endif
//--------------------------------------------------------------
// Geometry Shader
//--------------------------------------------------------------
#ifdef GEOMETRY_SHADER
#ifdef PRIM_QUAD
layout(lines_adjacency) in;
#ifdef GEOMETRY_OUT_FILL
layout(triangle_strip, max_vertices = 4) out;
#endif
#ifdef GEOMETRY_OUT_LINE
layout(line_strip, max_vertices = 5) out;
#endif
in vec3 vPosition[4];
in vec3 vNormal[4];
#else // PRIM_TRI
layout(triangles) in;
#ifdef GEOMETRY_OUT_FILL
layout(triangle_strip, max_vertices = 3) out;
#endif
#ifdef GEOMETRY_OUT_LINE
layout(line_strip, max_vertices = 4) out;
#endif
in vec3 vPosition[3];
in vec3 vNormal[3];
#endif // PRIM_TRI/QUAD
uniform mat4 objectToClipMatrix;
uniform mat4 objectToEyeMatrix;
flat out vec3 gFacetNormal;
out vec3 Peye;
out vec3 Neye;
out vec4 Cout;
void emit(int index)
{
Peye = vPosition[index];
gl_Position = objectToClipMatrix * vec4(vPosition[index], 1);
Neye = (objectToEyeMatrix * vec4(vNormal[index], 0)).xyz;
EmitVertex();
}
void main()
{
gl_PrimitiveID = gl_PrimitiveIDIn;
#ifdef PRIM_QUAD
#ifdef GEOMETRY_OUT_FILL
vec3 A = vPosition[0] - vPosition[1];
vec3 B = vPosition[3] - vPosition[1];
vec3 C = vPosition[2] - vPosition[1];
gFacetNormal = (objectToEyeMatrix*vec4(normalize(cross(B, A)), 0)).xyz;
emit(0);
emit(1);
emit(3);
// gFacetNormal = (objectToEyeMatrix*vec4(normalize(cross(C, B)), 0)).xyz;
emit(2);
#else // GEOMETRY_OUT_LINE
emit(0);
emit(1);
emit(2);
emit(3);
emit(0);
#endif
#endif // PRIM_QUAD
#ifdef PRIM_TRI
vec3 A = vPosition[1] - vPosition[0];
vec3 B = vPosition[2] - vPosition[0];
gFacetNormal = (objectToEyeMatrix*vec4(normalize(cross(B, A)), 0)).xyz;
emit(0);
emit(1);
emit(2);
#ifdef GEOMETRY_OUT_LINE
emit(0);
#endif //GEOMETRY_OUT_LINE
#endif // PRIM_TRI
EndPrimitive();
}
#endif
//--------------------------------------------------------------
// Fragment Shader
//--------------------------------------------------------------
#ifdef FRAGMENT_SHADER
flat in vec3 gFacetNormal;
in vec3 Neye;
in vec3 Peye;
in vec4 Cout;
#define NUM_LIGHTS 2
struct LightSource {
vec4 position;
vec4 ambient;
vec4 diffuse;
vec4 specular;
};
uniform LightSource lightSource[NUM_LIGHTS];
vec4
lighting(vec3 Peye, vec3 Neye)
{
vec4 color = vec4(0);
vec4 material = vec4(0.4, 0.4, 0.8, 1);
for (int i = 0; i < NUM_LIGHTS; ++i) {
vec4 Plight = lightSource[i].position;
vec3 l = (Plight.w == 0.0)
? normalize(Plight.xyz) : normalize(Plight.xyz - Peye);
vec3 n = normalize(Neye);
vec3 h = normalize(l + vec3(0,0,1)); // directional viewer
float d = max(0.0, dot(n, l));
float s = pow(max(0.0, dot(n, h)), 500.0f);
color += lightSource[i].ambient * material
+ d * lightSource[i].diffuse * material
+ s * lightSource[i].specular;
}
color.a = 1;
return color;
}
#ifdef GEOMETRY_OUT_LINE
uniform vec4 fragColor;
void
main()
{
gl_FragColor = fragColor;
}
#else
void
main()
{
vec3 N = (gl_FrontFacing ? gFacetNormal : -gFacetNormal);
gl_FragColor = lighting(Peye, N);
}
#endif // GEOMETRY_OUT_LINE
#endif

View File

@ -58,6 +58,7 @@
#if defined(__APPLE__) #if defined(__APPLE__)
#include <GLUT/glut.h> #include <GLUT/glut.h>
#else #else
#include <stdlib.h>
#include <GL/glew.h> #include <GL/glew.h>
#include <GL/glut.h> #include <GL/glut.h>
#endif #endif
@ -81,17 +82,25 @@
#include <cuda_runtime_api.h> #include <cuda_runtime_api.h>
#include <cuda_gl_interop.h> #include <cuda_gl_interop.h>
#include "cudaInit.h" #include "../common/cudaInit.h"
#endif #endif
static const char *shaderSource =
#include "shader.inc"
;
#include <float.h>
#include <vector> #include <vector>
#include <fstream>
#include <sstream>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
struct SimpleShape { struct SimpleShape {
std::string name; std::string name;
Scheme scheme; Scheme scheme;
char const * data; char const * data;
SimpleShape() { }
SimpleShape( char const * idata, char const * iname, Scheme ischeme ) SimpleShape( char const * idata, char const * iname, Scheme ischeme )
: name(iname), scheme(ischeme), data(idata) { } : name(iname), scheme(ischeme), data(idata) { }
}; };
@ -101,7 +110,7 @@ std::vector<SimpleShape> g_defaultShapes;
int g_currentShape = 0; int g_currentShape = 0;
void void
initializeShapes( ) { initializeShapes( ) {
#include <shapes/bilinear_cube.h> #include <shapes/bilinear_cube.h>
@ -161,6 +170,20 @@ initializeShapes( ) {
#include <shapes/catmark_tent.h> #include <shapes/catmark_tent.h>
g_defaultShapes.push_back(SimpleShape(catmark_tent, "catmark_tent", kCatmark)); g_defaultShapes.push_back(SimpleShape(catmark_tent, "catmark_tent", kCatmark));
#include <shapes/catmark_square_hedit0.h>
g_defaultShapes.push_back(SimpleShape(catmark_square_hedit0, "catmark_square_hedit0", kCatmark));
#include <shapes/catmark_square_hedit1.h>
g_defaultShapes.push_back(SimpleShape(catmark_square_hedit1, "catmark_square_hedit1", kCatmark));
#include <shapes/catmark_square_hedit2.h>
g_defaultShapes.push_back(SimpleShape(catmark_square_hedit2, "catmark_square_hedit2", kCatmark));
#include <shapes/catmark_square_hedit3.h>
g_defaultShapes.push_back(SimpleShape(catmark_square_hedit3, "catmark_square_hedit3", kCatmark));
#include <shapes/loop_cube_creases0.h> #include <shapes/loop_cube_creases0.h>
g_defaultShapes.push_back(SimpleShape(loop_cube_creases0, "loop_cube_creases0", kLoop)); g_defaultShapes.push_back(SimpleShape(loop_cube_creases0, "loop_cube_creases0", kLoop));
@ -191,17 +214,22 @@ int g_frame = 0,
g_repeatCount = 0; g_repeatCount = 0;
// GLUT GUI variables // GLUT GUI variables
int g_wire = 0, int g_freeze = 0,
g_wire = 0,
g_drawCoarseMesh = 1,
g_drawNormals = 0, g_drawNormals = 0,
g_mbutton; g_drawHUD = 1,
g_mbutton[3] = {0, 0, 0};
float g_rx = 0, float g_rotate[2] = {0, 0},
g_ry = 0, g_prev_x = 0,
g_prev_x = 0,
g_prev_y = 0, g_prev_y = 0,
g_dolly = 5; g_dolly = 5,
g_pan[2] = {0, 0},
g_center[3] = {0, 0, 0},
g_size = 0;
int g_width, int g_width,
g_height; g_height;
// performance // performance
@ -209,22 +237,33 @@ float g_cpuTime = 0;
float g_gpuTime = 0; float g_gpuTime = 0;
// geometry // geometry
std::vector<float> g_positions, std::vector<float> g_orgPositions,
g_positions,
g_normals; g_normals;
Scheme g_scheme; Scheme g_scheme;
int g_numIndices = 0; int g_numIndices = 0;
int g_level = 2; int g_level = 2;
int g_kernel = OpenSubdiv::OsdKernelDispatcher::kCPU; int g_kernel = OpenSubdiv::OsdKernelDispatcher::kCPU;
float g_moveScale = 1.0f;
GLuint g_indexBuffer; GLuint g_indexBuffer;
GLuint g_quadFillProgram = 0,
g_quadLineProgram = 0,
g_triFillProgram = 0,
g_triLineProgram = 0;
std::vector<int> g_coarseEdges;
std::vector<float> g_coarseEdgeSharpness;
std::vector<float> g_coarseVertexSharpness;
OpenSubdiv::OsdMesh * g_osdmesh = 0; OpenSubdiv::OsdMesh * g_osdmesh = 0;
OpenSubdiv::OsdVertexBuffer * g_vertexBuffer = 0; OpenSubdiv::OsdVertexBuffer * g_vertexBuffer = 0;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
inline void inline void
cross(float *n, const float *p0, const float *p1, const float *p2) { cross(float *n, const float *p0, const float *p1, const float *p2) {
float a[3] = { p1[0]-p0[0], p1[1]-p0[1], p1[2]-p0[2] }; float a[3] = { p1[0]-p0[0], p1[1]-p0[1], p1[2]-p0[2] };
@ -232,15 +271,15 @@ cross(float *n, const float *p0, const float *p1, const float *p2) {
n[0] = a[1]*b[2]-a[2]*b[1]; n[0] = a[1]*b[2]-a[2]*b[1];
n[1] = a[2]*b[0]-a[0]*b[2]; n[1] = a[2]*b[0]-a[0]*b[2];
n[2] = a[0]*b[1]-a[1]*b[0]; n[2] = a[0]*b[1]-a[1]*b[0];
float rn = 1.0f/sqrtf(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]); float rn = 1.0f/sqrtf(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
n[0] *= rn; n[0] *= rn;
n[1] *= rn; n[1] *= rn;
n[2] *= rn; n[2] *= rn;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
inline void inline void
normalize(float * p) { normalize(float * p) {
float dist = sqrtf( p[0]*p[0] + p[1]*p[1] + p[2]*p[2] ); float dist = sqrtf( p[0]*p[0] + p[1]*p[1] + p[2]*p[2] );
@ -249,9 +288,25 @@ normalize(float * p) {
p[2]/=dist; p[2]/=dist;
} }
//------------------------------------------------------------------------------
inline void
multMatrix(float *d, const float *a, const float *b) {
//------------------------------------------------------------------------------ for (int i=0; i<4; ++i)
static void {
for (int j=0; j<4; ++j)
{
d[i*4 + j] =
a[i*4 + 0] * b[0*4 + j] +
a[i*4 + 1] * b[1*4 + j] +
a[i*4 + 2] * b[2*4 + j] +
a[i*4 + 3] * b[3*4 + j];
}
}
}
//------------------------------------------------------------------------------
static void
calcNormals(OpenSubdiv::OsdHbrMesh * mesh, std::vector<float> const & pos, std::vector<float> & result ) { calcNormals(OpenSubdiv::OsdHbrMesh * mesh, std::vector<float> const & pos, std::vector<float> & result ) {
// calc normal vectors // calc normal vectors
@ -259,13 +314,13 @@ calcNormals(OpenSubdiv::OsdHbrMesh * mesh, std::vector<float> const & pos, std::
int nfaces = mesh->GetNumCoarseFaces(); int nfaces = mesh->GetNumCoarseFaces();
for (int i = 0; i < nfaces; ++i) { for (int i = 0; i < nfaces; ++i) {
OpenSubdiv::OsdHbrFace * f = mesh->GetFace(i); OpenSubdiv::OsdHbrFace * f = mesh->GetFace(i);
float const * p0 = &pos[f->GetVertex(0)->GetID()*3], float const * p0 = &pos[f->GetVertex(0)->GetID()*3],
* p1 = &pos[f->GetVertex(1)->GetID()*3], * p1 = &pos[f->GetVertex(1)->GetID()*3],
* p2 = &pos[f->GetVertex(2)->GetID()*3]; * p2 = &pos[f->GetVertex(2)->GetID()*3];
float n[3]; float n[3];
cross( n, p0, p1, p2 ); cross( n, p0, p1, p2 );
@ -281,30 +336,43 @@ calcNormals(OpenSubdiv::OsdHbrMesh * mesh, std::vector<float> const & pos, std::
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
updateGeom() { updateGeom() {
int nverts = (int)g_positions.size() / 3; int nverts = (int)g_orgPositions.size() / 3;
std::vector<float> vertex; std::vector<float> vertex;
vertex.reserve(nverts*6); vertex.reserve(nverts*6);
const float *p = &g_positions[0]; const float *p = &g_orgPositions[0];
const float *n = &g_normals[0]; const float *n = &g_normals[0];
float r = sin(g_frame*0.001f) * g_moveScale;
for (int i = 0; i < nverts; ++i) { for (int i = 0; i < nverts; ++i) {
float move = 0.05f*cosf(p[0]*20+g_frame*0.01f); float move = 0.05f*cosf(p[0]*20+g_frame*0.01f);
float ct = cos(p[2] * r);
float st = sin(p[2] * r);
g_positions[i*3+0] = p[0]*ct + p[1]*st;
g_positions[i*3+1] = -p[0]*st + p[1]*ct;
g_positions[i*3+2] = p[2];
p += 3;
}
p = &g_positions[0];
for (int i = 0; i < nverts; ++i) {
vertex.push_back(p[0]); vertex.push_back(p[0]);
vertex.push_back(p[1]+move); vertex.push_back(p[1]);
vertex.push_back(p[2]); vertex.push_back(p[2]);
vertex.push_back(n[0]); vertex.push_back(n[0]);
vertex.push_back(n[1]); vertex.push_back(n[1]);
vertex.push_back(n[2]); vertex.push_back(n[2]);
p += 3; p += 3;
n += 3; n += 3;
} }
if (!g_vertexBuffer) if (!g_vertexBuffer)
g_vertexBuffer = g_osdmesh->InitializeVertexBuffer(6); g_vertexBuffer = g_osdmesh->InitializeVertexBuffer(6);
g_vertexBuffer->UpdateData(&vertex[0], nverts); g_vertexBuffer->UpdateData(&vertex[0], nverts);
@ -324,41 +392,16 @@ updateGeom() {
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
} }
//-------------------------------------------------------------------------------
void
fitFrame() {
g_pan[0] = g_pan[1] = 0;
g_dolly = g_size;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
createOsdMesh( const char * shape, int level, int kernel, Scheme scheme=kCatmark ) {
// generate Hbr representation from "obj" description
OpenSubdiv::OsdHbrMesh * hmesh = simpleHbr<OpenSubdiv::OsdVertex>(shape, scheme, g_positions);
g_normals.resize(g_positions.size(),0.0f);
calcNormals( hmesh, g_positions, g_normals );
// generate Osd mesh from Hbr mesh
if (g_osdmesh) delete g_osdmesh;
g_osdmesh = new OpenSubdiv::OsdMesh();
g_osdmesh->Create(hmesh, level, kernel);
if (g_vertexBuffer) {
delete g_vertexBuffer;
g_vertexBuffer = NULL;
}
// Hbr mesh can be deleted
delete hmesh;
// update element array buffer
const std::vector<int> &indices = g_osdmesh->GetFarMesh()->GetFaceVertices(level);
g_numIndices = indices.size();
g_scheme = scheme;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*g_numIndices, &(indices[0]), GL_STATIC_DRAW);
updateGeom();
}
//------------------------------------------------------------------------------
void
reshape(int width, int height) { reshape(int width, int height) {
g_width = width; g_width = width;
@ -369,29 +412,55 @@ reshape(int width, int height) {
#define snprintf _snprintf #define snprintf _snprintf
#endif #endif
#define drawString(x, y, fmt, ...) \ #define drawString(x, y, ...) \
{ char line[1024]; \ { char line[1024]; \
snprintf(line, 1024, fmt, __VA_ARGS__); \ snprintf(line, 1024, __VA_ARGS__); \
char *p = line; \ char *p = line; \
glWindowPos2f(x, y); \ glWindowPos2i(x, y); \
while(*p) { glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *p++); } } while(*p) { glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *p++); } }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
const char *getKernelName(int kernel) { const char *getKernelName(int kernel) {
if (kernel == OpenSubdiv::OsdKernelDispatcher::kCPU) if (kernel == OpenSubdiv::OsdKernelDispatcher::kCPU)
return "CPU"; return "CPU";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kOPENMP) else if (kernel == OpenSubdiv::OsdKernelDispatcher::kOPENMP)
return "OpenMP"; return "OpenMP";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kCUDA) else if (kernel == OpenSubdiv::OsdKernelDispatcher::kCUDA)
return "Cuda"; return "Cuda";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kGLSL) else if (kernel == OpenSubdiv::OsdKernelDispatcher::kGLSL)
return "GLSL"; return "GLSL";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kCL) else if (kernel == OpenSubdiv::OsdKernelDispatcher::kCL)
return "OpenCL"; return "OpenCL";
return "Unknown"; return "Unknown";
} }
//------------------------------------------------------------------------------
static GLuint compileShader(GLenum shaderType, const char *section, const char *define)
{
const char *sources[3];
char sdefine[64];
sprintf(sdefine, "#define %s\n", section);
sources[0] = sdefine;
sources[1] = define;
sources[2] = shaderSource;
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 3, sources, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if( status == GL_FALSE ) {
GLchar emsg[1024];
glGetShaderInfoLog(shader, sizeof(emsg), 0, emsg);
fprintf(stderr, "Error compiling GLSL shader (%s): %s\n", section, emsg );
exit(0);
}
return shader;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
drawNormals() { drawNormals() {
@ -404,103 +473,312 @@ drawNormals() {
glBindBuffer(GL_ARRAY_BUFFER, g_vertexBuffer->GetGpuBuffer()); glBindBuffer(GL_ARRAY_BUFFER, g_vertexBuffer->GetGpuBuffer());
glGetBufferSubData(GL_ARRAY_BUFFER,0,datasize*sizeof(float),data); glGetBufferSubData(GL_ARRAY_BUFFER,0,datasize*sizeof(float),data);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_LIGHTING); glDisable(GL_LIGHTING);
glColor3f(0.0f, 0.0f, 0.5f); glColor3f(0.0f, 0.0f, 0.5f);
glBegin(GL_LINES); glBegin(GL_LINES);
int start = g_osdmesh->GetFarMesh()->GetSubdivision()->GetFirstVertexOffset(g_level) * int start = g_osdmesh->GetFarMesh()->GetSubdivision()->GetFirstVertexOffset(g_level) *
g_vertexBuffer->GetNumElements(); g_vertexBuffer->GetNumElements();
for (int i=start; i<datasize; i+=6) { for (int i=start; i<datasize; i+=6) {
glVertex3f( data[i ], glVertex3f( data[i ],
data[i+1], data[i+1],
data[i+2] ); data[i+2] );
float n[3] = { data[i+3], data[i+4], data[i+5] }; float n[3] = { data[i+3], data[i+4], data[i+5] };
normalize(n); normalize(n);
glVertex3f( data[i ]+n[0]*0.2f, glVertex3f( data[i ]+n[0]*0.2f,
data[i+1]+n[1]*0.2f, data[i+1]+n[1]*0.2f,
data[i+2]+n[2]*0.2f ); data[i+2]+n[2]*0.2f );
} }
glEnd(); glEnd();
delete [] data; delete [] data;
} }
inline void
setSharpnessColor(float s)
{
// 0.0 2.0 4.0
// green --- yellow --- red
float r = std::min(1.0f, s * 0.5f);
float g = std::min(1.0f, 2.0f - s*0.5f);
glColor3f(r, g, 0.0f);
}
void
drawCoarseMesh(int mode) {
glDisable(GL_LIGHTING);
glLineWidth(2.0f);
glBegin(GL_LINES);
for(int i=0; i<(int)g_coarseEdges.size(); i+=2) {
setSharpnessColor(g_coarseEdgeSharpness[i/2]);
glVertex3fv(&g_positions[g_coarseEdges[i]*3]);
glVertex3fv(&g_positions[g_coarseEdges[i+1]*3]);
}
glEnd();
glLineWidth(1.0f);
if (mode == 2) {
glPointSize(10.0f);
glBegin(GL_POINTS);
for(int i=0; i<(int)g_positions.size()/3; ++i) {
setSharpnessColor(g_coarseVertexSharpness[i]);
glVertex3fv(&g_positions[i*3]);
}
glEnd();
glPointSize(1.0f);
}
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void GLuint linkProgram(const char *define) {
GLuint vertexShader = compileShader(GL_VERTEX_SHADER,
"VERTEX_SHADER", define);
GLuint geometryShader = compileShader(GL_GEOMETRY_SHADER,
"GEOMETRY_SHADER", define);
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER,
"FRAGMENT_SHADER", define);
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, geometryShader);
glAttachShader(program, fragmentShader);
glBindAttribLocation(program, 0, "position");
glBindAttribLocation(program, 1, "normal");
glLinkProgram(program);
glDeleteShader(vertexShader);
glDeleteShader(geometryShader);
glDeleteShader(fragmentShader);
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status );
if( status == GL_FALSE ) {
GLchar emsg[1024];
glGetProgramInfoLog(program, sizeof(emsg), 0, emsg);
fprintf(stderr, "Error linking GLSL program : %s\n", emsg );
exit(0);
}
return program;
}
//------------------------------------------------------------------------------
void
createOsdMesh( const char * shape, int level, int kernel, Scheme scheme=kCatmark ) {
// generate Hbr representation from "obj" description
OpenSubdiv::OsdHbrMesh * hmesh = simpleHbr<OpenSubdiv::OsdVertex>(shape, scheme, g_orgPositions);
g_normals.resize(g_orgPositions.size(),0.0f);
g_positions.resize(g_orgPositions.size(),0.0f);
calcNormals( hmesh, g_orgPositions, g_normals );
// save coarse topology (used for coarse mesh drawing)
g_coarseEdges.clear();
g_coarseEdgeSharpness.clear();
g_coarseVertexSharpness.clear();
int nf = hmesh->GetNumFaces();
for(int i=0; i<nf; ++i) {
OpenSubdiv::OsdHbrFace *face = hmesh->GetFace(i);
int nv = face->GetNumVertices();
for(int j=0; j<nv; ++j) {
g_coarseEdges.push_back(face->GetVertex(j)->GetID());
g_coarseEdges.push_back(face->GetVertex((j+1)%nv)->GetID());
g_coarseEdgeSharpness.push_back(face->GetEdge(j)->GetSharpness());
}
}
int nv = hmesh->GetNumVertices();
for(int i=0; i<nv; ++i) {
g_coarseVertexSharpness.push_back(hmesh->GetVertex(i)->GetSharpness());
}
// generate Osd mesh from Hbr mesh
if (g_osdmesh) delete g_osdmesh;
g_osdmesh = new OpenSubdiv::OsdMesh();
g_osdmesh->Create(hmesh, level, kernel);
if (g_vertexBuffer) {
delete g_vertexBuffer;
g_vertexBuffer = NULL;
}
// Hbr mesh can be deleted
delete hmesh;
// update element array buffer
const std::vector<int> &indices = g_osdmesh->GetFarMesh()->GetFaceVertices(level);
g_numIndices = (int)indices.size();
g_scheme = scheme;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*g_numIndices, &(indices[0]), GL_STATIC_DRAW);
// compute model bounding
float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX};
float max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
for (size_t i=0; i <g_orgPositions.size()/3; ++i) {
for(int j=0; j<3; ++j) {
float v = g_orgPositions[i*3+j];
min[j] = std::min(min[j], v);
max[j] = std::max(max[j], v);
}
}
for (int j=0; j<3; ++j) {
g_center[j] = (min[j] + max[j]) * 0.5f;
g_size += (max[j]-min[j])*(max[j]-min[j]);
}
g_size = sqrtf(g_size);
updateGeom();
}
//------------------------------------------------------------------------------
void
bindProgram(GLuint program)
{
glUseProgram(program);
// shader uniform setting
GLint position = glGetUniformLocation(program, "lightSource[0].position");
GLint ambient = glGetUniformLocation(program, "lightSource[0].ambient");
GLint diffuse = glGetUniformLocation(program, "lightSource[0].diffuse");
GLint specular = glGetUniformLocation(program, "lightSource[0].specular");
GLint position1 = glGetUniformLocation(program, "lightSource[1].position");
GLint ambient1 = glGetUniformLocation(program, "lightSource[1].ambient");
GLint diffuse1 = glGetUniformLocation(program, "lightSource[1].diffuse");
GLint specular1 = glGetUniformLocation(program, "lightSource[1].specular");
glProgramUniform4f(program, position, 0.5, 0.2f, 1, 0);
glProgramUniform4f(program, ambient, 0.1f, 0.1f, 0.1f, 1.0f);
glProgramUniform4f(program, diffuse, 0.7f, 0.7f, 0.7f, 1.0f);
glProgramUniform4f(program, specular, 0.8f, 0.8f, 0.8f, 1.0f);
glProgramUniform4f(program, position1, -0.8, 0.4f, -1.0, 0);
glProgramUniform4f(program, ambient1, 0.0f, 0.0f, 0.0f, 1.0f);
glProgramUniform4f(program, diffuse1, 0.5f, 0.5f, 0.5f, 1.0f);
glProgramUniform4f(program, specular1, 0.8f, 0.8f, 0.8f, 1.0f);
GLint otcMatrix = glGetUniformLocation(program, "objectToClipMatrix");
GLint oteMatrix = glGetUniformLocation(program, "objectToEyeMatrix");
GLfloat modelView[16], proj[16], mvp[16];
glGetFloatv(GL_MODELVIEW_MATRIX, modelView);
glGetFloatv(GL_PROJECTION_MATRIX, proj);
multMatrix(mvp, modelView, proj);
glProgramUniformMatrix4fv(program, otcMatrix, 1, false, mvp);
glProgramUniformMatrix4fv(program, oteMatrix, 1, false, modelView);
}
//------------------------------------------------------------------------------
void
display() { display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, g_width, g_height); glViewport(0, 0, g_width, g_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_LIGHTING);
glColor3f(1, 1, 1);
glBegin(GL_QUADS);
glColor3f(0.5f, 0.5f, 0.5f);
glVertex3f(-1, -1, 1);
glVertex3f( 1, -1, 1);
glColor3f(0, 0, 0);
glVertex3f( 1, 1, 1);
glVertex3f(-1, 1, 1);
glEnd();
double aspect = g_width/(double)g_height; double aspect = g_width/(double)g_height;
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
gluPerspective(45.0, aspect, 0.001, 100.0); gluPerspective(45.0, aspect, 0.01, 500.0);
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();
glTranslatef(0, 0, -g_dolly); glTranslatef(-g_pan[0], -g_pan[1], -g_dolly);
glRotatef(g_ry, 1, 0, 0); glRotatef(g_rotate[1], 1, 0, 0);
glRotatef(g_rx, 0, 1, 0); glRotatef(g_rotate[0], 0, 1, 0);
glTranslatef(-g_center[0], -g_center[1], -g_center[2]);
glRotatef(-90, 1, 0, 0); // z-up model
GLuint bVertex = g_vertexBuffer->GetGpuBuffer(); GLuint bVertex = g_vertexBuffer->GetGpuBuffer();
#ifdef VARYING_NORMAL glEnableVertexAttribArray(0);
GLuint bVarying = g_varyingBuffer->GetGpuBuffer(); glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, bVertex); glBindBuffer(GL_ARRAY_BUFFER, bVertex);
glVertexPointer(3, GL_FLOAT, 12, ((float*)(0)));
glBindBuffer(GL_ARRAY_BUFFER, bVarying); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, 0);
glNormalPointer(GL_FLOAT, 12, ((float*)(0))); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, (float*)12);
#else
glBindBuffer(GL_ARRAY_BUFFER, bVertex);
glVertexPointer(3, GL_FLOAT, 24, ((float*)(0)));
glNormalPointer(GL_FLOAT, 24, ((float*)(12)));
#endif
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_indexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_indexBuffer);
if (g_wire == 0) { GLenum primType = GL_LINES_ADJACENCY;
glColor3f(1.0f, 1.0f, 1.0f); if (g_scheme == kLoop) {
primType = GL_TRIANGLES;
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); bindProgram(g_triFillProgram);
glDisable(GL_LIGHTING);
glDrawElements(g_scheme==kLoop ? GL_TRIANGLES : GL_QUADS, g_numIndices, GL_UNSIGNED_INT, NULL);
} else { } else {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); bindProgram(g_quadFillProgram);
glEnable(GL_LIGHTING); }
glDrawElements(g_scheme==kLoop ? GL_TRIANGLES : GL_QUADS, g_numIndices, GL_UNSIGNED_INT, NULL);
if(g_wire == 2){ if (g_wire > 0) {
glColor3f(0.0f, 0.0f, 0.5f); glDrawElements(primType, g_numIndices, GL_UNSIGNED_INT, NULL);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_LIGHTING);
glDrawElements(g_scheme==kLoop ? GL_TRIANGLES : GL_QUADS, g_numIndices, GL_UNSIGNED_INT, NULL);
}
glColor3f(1.0f, 1.0f, 1.0f);
} }
if (g_wire == 0 || g_wire == 2) {
GLuint lineProgram = g_scheme == kLoop ? g_triLineProgram : g_quadLineProgram;
bindProgram(lineProgram);
GLuint fragColor = glGetUniformLocation(lineProgram, "fragColor");
if (g_wire == 2) {
glProgramUniform4f(lineProgram, fragColor, 0, 0, 0.5, 1);
} else {
glProgramUniform4f(lineProgram, fragColor, 1, 1, 1, 1);
}
glDrawElements(primType, g_numIndices, GL_UNSIGNED_INT, NULL);
}
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glUseProgram(0);
if (g_drawNormals) if (g_drawNormals)
drawNormals(); drawNormals();
if (g_drawCoarseMesh)
drawCoarseMesh(g_drawCoarseMesh);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glColor3f(1, 1, 1);
drawString(10, 10, "LEVEL = %d", g_level);
drawString(10, 30, "# of Vertices = %d", g_osdmesh->GetFarMesh()->GetNumVertices());
drawString(10, 50, "KERNEL = %s", getKernelName(g_kernel));
drawString(10, 70, "CPU TIME = %.3f ms", g_cpuTime);
drawString(10, 90, "GPU TIME = %.3f ms", g_gpuTime);
drawString(10, 110, "SUBDIVISION = %s", g_scheme==kBilinear ? "BILINEAR" : (g_scheme == kLoop ? "LOOP" : "CATMARK"));
if (g_drawHUD) {
glColor3f(1, 1, 1);
drawString(10, 10, "LEVEL = %d", g_level);
drawString(10, 30, "# of Vertices = %d", g_osdmesh->GetFarMesh()->GetNumVertices());
drawString(10, 50, "KERNEL = %s", getKernelName(g_kernel));
drawString(10, 70, "CPU TIME = %.3f ms", g_cpuTime);
drawString(10, 90, "GPU TIME = %.3f ms", g_gpuTime);
drawString(10, 110, "SUBDIVISION = %s", g_scheme==kBilinear ? "BILINEAR" : (g_scheme == kLoop ? "LOOP" : "CATMARK"));
drawString(10, g_height-30, "w: toggle wireframe");
drawString(10, g_height-50, "e: display normal vector");
drawString(10, g_height-70, "m: toggle vertex deforming");
drawString(10, g_height-90, "h: display control cage");
drawString(10, g_height-110, "n/p: change model");
drawString(10, g_height-130, "1-7: subdivision level");
drawString(10, g_height-150, "space: freeze/unfreeze time");
}
glFinish(); glFinish();
glutSwapBuffers(); glutSwapBuffers();
} }
@ -508,11 +786,17 @@ display() {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void motion(int x, int y) { void motion(int x, int y) {
if(g_mbutton == 0){ if (g_mbutton[0] && !g_mbutton[1] && !g_mbutton[2]) {
g_rx += x - g_prev_x; // orbit
g_ry += y - g_prev_y; g_rotate[0] += x - g_prev_x;
}else if(g_mbutton == 1){ g_rotate[1] += y - g_prev_y;
g_dolly -= 0.01f*(x - g_prev_x); } else if (!g_mbutton[0] && g_mbutton[1] && !g_mbutton[2]) {
// pan
g_pan[0] -= g_dolly*(x - g_prev_x)/g_width;
g_pan[1] += g_dolly*(y - g_prev_y)/g_height;
} else if (g_mbutton[0] && g_mbutton[1] && !g_mbutton[2]) {
// dolly
g_dolly -= g_dolly*0.01f*(x - g_prev_x);
if(g_dolly <= 0.01) g_dolly = 0.01f; if(g_dolly <= 0.01) g_dolly = 0.01f;
} }
@ -525,13 +809,13 @@ void mouse(int button, int state, int x, int y) {
g_prev_x = float(x); g_prev_x = float(x);
g_prev_y = float(y); g_prev_y = float(y);
g_mbutton = button; g_mbutton[button] = !state;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void quit() { void quit() {
if(g_osdmesh) if(g_osdmesh)
delete g_osdmesh; delete g_osdmesh;
if (g_vertexBuffer) if (g_vertexBuffer)
@ -551,24 +835,24 @@ void kernelMenu(int k) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
modelMenu(int m) { modelMenu(int m) {
if (m < 0) if (m < 0)
m = 0; m = 0;
if (m >= (int)g_defaultShapes.size()) if (m >= (int)g_defaultShapes.size())
m = g_defaultShapes.size() - 1; m = (int)g_defaultShapes.size() - 1;
g_currentShape = m; g_currentShape = m;
glutSetWindowTitle( g_defaultShapes[m].name.c_str() ); glutSetWindowTitle( g_defaultShapes[m].name.c_str() );
createOsdMesh( g_defaultShapes[m].data, g_level, g_kernel, g_defaultShapes[ g_currentShape ].scheme ); createOsdMesh( g_defaultShapes[m].data, g_level, g_kernel, g_defaultShapes[ g_currentShape ].scheme );
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
levelMenu(int l) { levelMenu(int l) {
g_level = l; g_level = l;
@ -577,19 +861,23 @@ levelMenu(int l) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
menu(int m) { menu(int m) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
keyboard(unsigned char key, int x, int y) { keyboard(unsigned char key, int x, int y) {
switch (key) { switch (key) {
case 'q': quit(); case 'q': quit();
case ' ': g_freeze = (g_freeze+1)%2; break;
case 'w': g_wire = (g_wire+1)%3; break; case 'w': g_wire = (g_wire+1)%3; break;
case 'e': g_drawNormals = (g_drawNormals+1)%2; break; case 'e': g_drawNormals = (g_drawNormals+1)%2; break;
case 'f': fitFrame(); break;
case 'm': g_moveScale = 1.0f - g_moveScale; break;
case 'h': g_drawCoarseMesh = (g_drawCoarseMesh+1)%3; break;
case '1': case '1':
case '2': case '2':
case '3': case '3':
@ -599,23 +887,26 @@ keyboard(unsigned char key, int x, int y) {
case '7': levelMenu(key-'0'); break; case '7': levelMenu(key-'0'); break;
case 'n': modelMenu(++g_currentShape); break; case 'n': modelMenu(++g_currentShape); break;
case 'p': modelMenu(--g_currentShape); break; case 'p': modelMenu(--g_currentShape); break;
case 0x1b: g_drawHUD = (g_drawHUD+1)%2; break;
} }
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
idle() { idle() {
g_frame++; if (not g_freeze)
g_frame++;
updateGeom(); updateGeom();
glutPostRedisplay(); glutPostRedisplay();
if(g_repeatCount != 0 && g_frame >= g_repeatCount) if (g_repeatCount != 0 and g_frame >= g_repeatCount)
quit(); quit();
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
initGL() { initGL() {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
@ -626,7 +917,7 @@ initGL() {
GLfloat color[4] = {1, 1, 1, 1}; GLfloat color[4] = {1, 1, 1, 1};
GLfloat position[4] = {5, 5, 10, 1}; GLfloat position[4] = {5, 5, 10, 1};
GLfloat ambient[4] = {0.1f, 0.1f, 0.1f, 1.0f}; GLfloat ambient[4] = {0.0f, 0.0f, 0.0f, 1.0f};
GLfloat diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f}; GLfloat diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat shininess = 25.0; GLfloat shininess = 25.0;
@ -637,17 +928,37 @@ initGL() {
glLightfv(GL_LIGHT0, GL_POSITION, position); glLightfv(GL_LIGHT0, GL_POSITION, position);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
g_quadFillProgram = linkProgram("#define PRIM_QUAD\n#define GEOMETRY_OUT_FILL\n");
g_quadLineProgram = linkProgram("#define PRIM_QUAD\n#define GEOMETRY_OUT_LINE\n");
g_triFillProgram = linkProgram("#define PRIM_TRI\n#define GEOMETRY_OUT_FILL\n");
g_triLineProgram = linkProgram("#define PRIM_TRI\n#define GEOMETRY_OUT_LINE\n");
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
int main(int argc, char ** argv) { int main(int argc, char ** argv) {
glutInit(&argc, argv); glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA |GLUT_DOUBLE | GLUT_DEPTH); glutInitDisplayMode(GLUT_RGBA |GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(1024, 1024); glutInitWindowSize(1024, 1024);
glutCreateWindow("OpenSubdiv test"); glutCreateWindow("OpenSubdiv test");
std::string str;
if (argc > 1) {
std::ifstream ifs(argv[1]);
if (ifs) {
std::stringstream ss;
ss << ifs.rdbuf();
ifs.close();
str = ss.str();
g_defaultShapes.push_back(SimpleShape(str.c_str(), argv[1], kCatmark));
}
}
initializeShapes(); initializeShapes();
int smenu = glutCreateMenu(modelMenu); int smenu = glutCreateMenu(modelMenu);
@ -667,9 +978,9 @@ int main(int argc, char ** argv) {
OpenSubdiv::OsdGlslKernelDispatcher::Register(); OpenSubdiv::OsdGlslKernelDispatcher::Register();
#if OPENSUBDIV_HAS_OPENCL #if OPENSUBDIV_HAS_OPENCL
OpenSubdiv::OsdClKernelDispatcher::Register(); OpenSubdiv::OsdClKernelDispatcher::Register();
#endif #endif
#if OPENSUBDIV_HAS_CUDA #if OPENSUBDIV_HAS_CUDA
OpenSubdiv::OsdCudaKernelDispatcher::Register(); OpenSubdiv::OsdCudaKernelDispatcher::Register();
@ -691,7 +1002,7 @@ int main(int argc, char ** argv) {
glutAddSubMenu("Model", smenu); glutAddSubMenu("Model", smenu);
glutAddSubMenu("Kernel", kmenu); glutAddSubMenu("Kernel", kmenu);
glutAttachMenu(GLUT_RIGHT_BUTTON); glutAttachMenu(GLUT_RIGHT_BUTTON);
glutDisplayFunc(display); glutDisplayFunc(display);
glutReshapeFunc(reshape); glutReshapeFunc(reshape);
glutMouseFunc(mouse); glutMouseFunc(mouse);
@ -707,17 +1018,17 @@ int main(int argc, char ** argv) {
g_level = atoi(argv[++i]); g_level = atoi(argv[++i]);
else if (!strcmp(argv[i], "-c")) else if (!strcmp(argv[i], "-c"))
g_repeatCount = atoi(argv[++i]); g_repeatCount = atoi(argv[++i]);
else else
filename = argv[i]; filename = argv[i];
} }
glGenBuffers(1, &g_indexBuffer); glGenBuffers(1, &g_indexBuffer);
modelMenu(0); modelMenu(0);
glutIdleFunc(idle); glutIdleFunc(idle);
glutMainLoop(); glutMainLoop();
quit(); quit();
} }

View File

@ -0,0 +1,925 @@
//
// 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.
//
#if defined(__APPLE__)
#include <OpenGL/gl3.h>
#include <GLUT/glut.h>
#else
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>
#endif
#include <osd/vertex.h>
#include <osd/mesh.h>
#include <osd/cpuDispatcher.h>
#ifdef OPENSUBDIV_HAS_GLSL
#include <osd/glslDispatcher.h>
#endif
#ifdef OPENSUBDIV_HAS_OPENCL
#include <osd/clDispatcher.h>
#endif
#ifdef OPENSUBDIV_HAS_CUDA
#include <osd/cudaDispatcher.h>
#include <cuda_runtime_api.h>
#include <cuda_gl_interop.h>
#include "../common/cudaInit.h"
#endif
#include <common/shape_utils.h>
#include "../common/stopwatch.h"
#include <float.h>
#include <vector>
#include <fstream>
#include <sstream>
//------------------------------------------------------------------------------
struct SimpleShape {
std::string name;
Scheme scheme;
char const * data;
SimpleShape() { }
SimpleShape( char const * idata, char const * iname, Scheme ischeme )
: name(iname), scheme(ischeme), data(idata) { }
};
std::vector<SimpleShape> g_defaultShapes;
int g_currentShape = 0;
void
initializeShapes( ) {
#include <shapes/bilinear_cube.h>
g_defaultShapes.push_back(SimpleShape(bilinear_cube, "bilinear_cube", kBilinear));
#include <shapes/catmark_cube_corner0.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube_corner0, "catmark_cube_corner0", kCatmark));
#include <shapes/catmark_cube_corner1.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube_corner1, "catmark_cube_corner1", kCatmark));
#include <shapes/catmark_cube_corner2.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube_corner2, "catmark_cube_corner2", kCatmark));
#include <shapes/catmark_cube_corner3.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube_corner3, "catmark_cube_corner3", kCatmark));
#include <shapes/catmark_cube_corner4.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube_corner4, "catmark_cube_corner4", kCatmark));
#include <shapes/catmark_cube_creases0.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube_creases0, "catmark_cube_creases0", kCatmark));
#include <shapes/catmark_cube_creases1.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube_creases1, "catmark_cube_creases1", kCatmark));
#include <shapes/catmark_cube.h>
g_defaultShapes.push_back(SimpleShape(catmark_cube, "catmark_cube", kCatmark));
#include <shapes/catmark_dart_edgecorner.h>
g_defaultShapes.push_back(SimpleShape(catmark_dart_edgecorner, "catmark_dart_edgecorner", kCatmark));
#include <shapes/catmark_dart_edgeonly.h>
g_defaultShapes.push_back(SimpleShape(catmark_dart_edgeonly, "catmark_dart_edgeonly", kCatmark));
#include <shapes/catmark_edgecorner.h>
g_defaultShapes.push_back(SimpleShape(catmark_edgecorner ,"catmark_edgecorner", kCatmark));
#include <shapes/catmark_edgeonly.h>
g_defaultShapes.push_back(SimpleShape(catmark_edgeonly, "catmark_edgeonly", kCatmark));
#include <shapes/catmark_pyramid_creases0.h>
g_defaultShapes.push_back(SimpleShape(catmark_pyramid_creases0, "catmark_pyramid_creases0", kCatmark));
#include <shapes/catmark_pyramid_creases1.h>
g_defaultShapes.push_back(SimpleShape(catmark_pyramid_creases1, "catmark_pyramid_creases1", kCatmark));
#include <shapes/catmark_pyramid.h>
g_defaultShapes.push_back(SimpleShape(catmark_pyramid, "catmark_pyramid", kCatmark));
#include <shapes/catmark_tent_creases0.h>
g_defaultShapes.push_back(SimpleShape(catmark_tent_creases0, "catmark_tent_creases0", kCatmark));
#include <shapes/catmark_tent_creases1.h>
g_defaultShapes.push_back(SimpleShape(catmark_tent_creases1, "catmark_tent_creases1", kCatmark));
#include <shapes/catmark_tent.h>
g_defaultShapes.push_back(SimpleShape(catmark_tent, "catmark_tent", kCatmark));
#include <shapes/catmark_square_hedit0.h>
g_defaultShapes.push_back(SimpleShape(catmark_square_hedit0, "catmark_square_hedit0", kCatmark));
#include <shapes/catmark_square_hedit1.h>
g_defaultShapes.push_back(SimpleShape(catmark_square_hedit1, "catmark_square_hedit1", kCatmark));
#include <shapes/catmark_square_hedit2.h>
g_defaultShapes.push_back(SimpleShape(catmark_square_hedit2, "catmark_square_hedit2", kCatmark));
#include <shapes/catmark_square_hedit3.h>
g_defaultShapes.push_back(SimpleShape(catmark_square_hedit3, "catmark_square_hedit3", kCatmark));
#include <shapes/loop_cube_creases0.h>
g_defaultShapes.push_back(SimpleShape(loop_cube_creases0, "loop_cube_creases0", kLoop));
#include <shapes/loop_cube_creases1.h>
g_defaultShapes.push_back(SimpleShape(loop_cube_creases1, "loop_cube_creases1", kLoop));
#include <shapes/loop_cube.h>
g_defaultShapes.push_back(SimpleShape(loop_cube, "loop_cube", kLoop));
#include <shapes/loop_icosahedron.h>
g_defaultShapes.push_back(SimpleShape(loop_icosahedron, "loop_icosahedron", kLoop));
#include <shapes/loop_saddle_edgecorner.h>
g_defaultShapes.push_back(SimpleShape(loop_saddle_edgecorner, "loop_saddle_edgecorner", kLoop));
#include <shapes/loop_saddle_edgeonly.h>
g_defaultShapes.push_back(SimpleShape(loop_saddle_edgeonly, "loop_saddle_edgeonly", kLoop));
#include <shapes/loop_triangle_edgecorner.h>
g_defaultShapes.push_back(SimpleShape(loop_triangle_edgecorner, "loop_triangle_edgecorner", kLoop));
#include <shapes/loop_triangle_edgeonly.h>
g_defaultShapes.push_back(SimpleShape(loop_triangle_edgeonly, "loop_triangle_edgeonly", kLoop));
}
//------------------------------------------------------------------------------
int g_frame = 0,
g_repeatCount = 0;
// GLUT GUI variables
int g_freeze = 0,
g_wire = 0,
g_drawCoarseMesh = 1,
g_drawNormals = 0,
g_drawHUD = 1,
g_mbutton[3] = {0, 0, 0};
float g_rotate[2] = {0, 0},
g_prev_x = 0,
g_prev_y = 0,
g_dolly = 5,
g_pan[2] = {0, 0},
g_center[3] = {0, 0, 0},
g_size = 0;
int g_width,
g_height;
// performance
float g_cpuTime = 0;
float g_gpuTime = 0;
// geometry
std::vector<float> g_orgPositions,
g_positions,
g_normals;
Scheme g_scheme;
int g_numIndices = 0;
int g_level = 2;
int g_kernel = OpenSubdiv::OsdKernelDispatcher::kCPU;
float g_moveScale = 1.0f;
GLuint g_indexBuffer;
std::vector<int> g_coarseEdges;
std::vector<float> g_coarseEdgeSharpness;
std::vector<float> g_coarseVertexSharpness;
OpenSubdiv::OsdMesh * g_osdmesh = 0;
OpenSubdiv::OsdVertexBuffer * g_vertexBuffer = 0;
//------------------------------------------------------------------------------
inline void
cross(float *n, const float *p0, const float *p1, const float *p2) {
float a[3] = { p1[0]-p0[0], p1[1]-p0[1], p1[2]-p0[2] };
float b[3] = { p2[0]-p0[0], p2[1]-p0[1], p2[2]-p0[2] };
n[0] = a[1]*b[2]-a[2]*b[1];
n[1] = a[2]*b[0]-a[0]*b[2];
n[2] = a[0]*b[1]-a[1]*b[0];
float rn = 1.0f/sqrtf(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
n[0] *= rn;
n[1] *= rn;
n[2] *= rn;
}
//------------------------------------------------------------------------------
inline void
normalize(float * p) {
float dist = sqrtf( p[0]*p[0] + p[1]*p[1] + p[2]*p[2] );
p[0]/=dist;
p[1]/=dist;
p[2]/=dist;
}
//------------------------------------------------------------------------------
inline void
multMatrix(float *d, const float *a, const float *b) {
for (int i=0; i<4; ++i)
{
for (int j=0; j<4; ++j)
{
d[i*4 + j] =
a[i*4 + 0] * b[0*4 + j] +
a[i*4 + 1] * b[1*4 + j] +
a[i*4 + 2] * b[2*4 + j] +
a[i*4 + 3] * b[3*4 + j];
}
}
}
//------------------------------------------------------------------------------
static void
calcNormals(OpenSubdiv::OsdHbrMesh * mesh, std::vector<float> const & pos, std::vector<float> & result ) {
// calc normal vectors
int nverts = (int)pos.size()/3;
int nfaces = mesh->GetNumCoarseFaces();
for (int i = 0; i < nfaces; ++i) {
OpenSubdiv::OsdHbrFace * f = mesh->GetFace(i);
float const * p0 = &pos[f->GetVertex(0)->GetID()*3],
* p1 = &pos[f->GetVertex(1)->GetID()*3],
* p2 = &pos[f->GetVertex(2)->GetID()*3];
float n[3];
cross( n, p0, p1, p2 );
for (int j = 0; j < f->GetNumVertices(); j++) {
int idx = f->GetVertex(j)->GetID() * 3;
result[idx ] += n[0];
result[idx+1] += n[1];
result[idx+2] += n[2];
}
}
for (int i = 0; i < nverts; ++i)
normalize( &result[i*3] );
}
//------------------------------------------------------------------------------
void
updateGeom() {
int nverts = (int)g_orgPositions.size() / 3;
std::vector<float> vertex;
vertex.reserve(nverts*6);
const float *p = &g_orgPositions[0];
const float *n = &g_normals[0];
float r = sin(g_frame*0.001f) * g_moveScale;
for (int i = 0; i < nverts; ++i) {
float move = 0.05f*cosf(p[0]*20+g_frame*0.01f);
float ct = cos(p[2] * r);
float st = sin(p[2] * r);
g_positions[i*3+0] = p[0]*ct + p[1]*st;
g_positions[i*3+1] = -p[0]*st + p[1]*ct;
g_positions[i*3+2] = p[2];
p += 3;
}
p = &g_positions[0];
for (int i = 0; i < nverts; ++i) {
vertex.push_back(p[0]);
vertex.push_back(p[1]);
vertex.push_back(p[2]);
vertex.push_back(n[0]);
vertex.push_back(n[1]);
vertex.push_back(n[2]);
p += 3;
n += 3;
}
if (!g_vertexBuffer)
g_vertexBuffer = g_osdmesh->InitializeVertexBuffer(6);
g_vertexBuffer->UpdateData(&vertex[0], nverts);
Stopwatch s;
s.Start();
g_osdmesh->Subdivide(g_vertexBuffer, NULL);
s.Stop();
g_cpuTime = float(s.GetElapsed() * 1000.0f);
s.Start();
g_osdmesh->Synchronize();
s.Stop();
g_gpuTime = float(s.GetElapsed() * 1000.0f);
glBindBuffer(GL_ARRAY_BUFFER, g_vertexBuffer->GetGpuBuffer());
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
//-------------------------------------------------------------------------------
void
fitFrame() {
g_pan[0] = g_pan[1] = 0;
g_dolly = g_size;
}
//------------------------------------------------------------------------------
void
reshape(int width, int height) {
g_width = width;
g_height = height;
}
#if _MSC_VER
#define snprintf _snprintf
#endif
#define drawString(x, y, ...) \
{ char line[1024]; \
snprintf(line, 1024, __VA_ARGS__); \
char *p = line; \
glWindowPos2f(x, y); \
while(*p) { glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *p++); } }
//------------------------------------------------------------------------------
const char *getKernelName(int kernel) {
if (kernel == OpenSubdiv::OsdKernelDispatcher::kCPU)
return "CPU";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kOPENMP)
return "OpenMP";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kCUDA)
return "Cuda";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kGLSL)
return "GLSL";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kCL)
return "OpenCL";
return "Unknown";
}
//------------------------------------------------------------------------------
void
drawNormals() {
float * data=0;
int datasize = g_osdmesh->GetTotalVertices() * g_vertexBuffer->GetNumElements();
data = new float[datasize];
glBindBuffer(GL_ARRAY_BUFFER, g_vertexBuffer->GetGpuBuffer());
glGetBufferSubData(GL_ARRAY_BUFFER,0,datasize*sizeof(float),data);
glDisable(GL_LIGHTING);
glColor3f(0.0f, 0.0f, 0.5f);
glBegin(GL_LINES);
int start = g_osdmesh->GetFarMesh()->GetSubdivision()->GetFirstVertexOffset(g_level) *
g_vertexBuffer->GetNumElements();
for (int i=start; i<datasize; i+=6) {
glVertex3f( data[i ],
data[i+1],
data[i+2] );
float n[3] = { data[i+3], data[i+4], data[i+5] };
normalize(n);
glVertex3f( data[i ]+n[0]*0.2f,
data[i+1]+n[1]*0.2f,
data[i+2]+n[2]*0.2f );
}
glEnd();
delete [] data;
}
inline void
setSharpnessColor(float s)
{
// 0.0 2.0 4.0
// green --- yellow --- red
float r = std::min(1.0f, s * 0.5f);
float g = std::min(1.0f, 2.0f - s*0.5f);
glColor3f(r, g, 0.0f);
}
void
drawCoarseMesh(int mode) {
glDisable(GL_LIGHTING);
glLineWidth(2.0f);
glBegin(GL_LINES);
for(int i=0; i<(int)g_coarseEdges.size(); i+=2) {
setSharpnessColor(g_coarseEdgeSharpness[i/2]);
glVertex3fv(&g_positions[g_coarseEdges[i]*3]);
glVertex3fv(&g_positions[g_coarseEdges[i+1]*3]);
}
glEnd();
glLineWidth(1.0f);
if (mode == 2) {
glPointSize(10.0f);
glBegin(GL_POINTS);
for(int i=0; i<(int)g_positions.size()/3; ++i) {
setSharpnessColor(g_coarseVertexSharpness[i]);
glVertex3fv(&g_positions[i*3]);
}
glEnd();
glPointSize(1.0f);
}
}
//------------------------------------------------------------------------------
void
createOsdMesh( const char * shape, int level, int kernel, Scheme scheme=kCatmark ) {
// generate Hbr representation from "obj" description
OpenSubdiv::OsdHbrMesh * hmesh = simpleHbr<OpenSubdiv::OsdVertex>(shape, scheme, g_orgPositions);
g_normals.resize(g_orgPositions.size(),0.0f);
g_positions.resize(g_orgPositions.size(),0.0f);
calcNormals( hmesh, g_orgPositions, g_normals );
// save coarse topology (used for coarse mesh drawing)
g_coarseEdges.clear();
g_coarseEdgeSharpness.clear();
g_coarseVertexSharpness.clear();
int nf = hmesh->GetNumFaces();
for(int i=0; i<nf; ++i) {
OpenSubdiv::OsdHbrFace *face = hmesh->GetFace(i);
int nv = face->GetNumVertices();
for(int j=0; j<nv; ++j) {
g_coarseEdges.push_back(face->GetVertex(j)->GetID());
g_coarseEdges.push_back(face->GetVertex((j+1)%nv)->GetID());
g_coarseEdgeSharpness.push_back(face->GetEdge(j)->GetSharpness());
}
}
int nv = hmesh->GetNumVertices();
for(int i=0; i<nv; ++i) {
g_coarseVertexSharpness.push_back(hmesh->GetVertex(i)->GetSharpness());
}
// generate Osd mesh from Hbr mesh
if (g_osdmesh) delete g_osdmesh;
g_osdmesh = new OpenSubdiv::OsdMesh();
g_osdmesh->Create(hmesh, level, kernel);
if (g_vertexBuffer) {
delete g_vertexBuffer;
g_vertexBuffer = NULL;
}
// Hbr mesh can be deleted
delete hmesh;
// update element array buffer
const std::vector<int> &indices = g_osdmesh->GetFarMesh()->GetFaceVertices(level);
g_numIndices = indices.size();
g_scheme = scheme;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*g_numIndices, &(indices[0]), GL_STATIC_DRAW);
// compute model bounding
float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX};
float max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
for (size_t i=0; i <g_orgPositions.size()/3; ++i) {
for(int j=0; j<3; ++j) {
float v = g_orgPositions[i*3+j];
min[j] = std::min(min[j], v);
max[j] = std::max(max[j], v);
}
}
for (int j=0; j<3; ++j) {
g_center[j] = (min[j] + max[j]) * 0.5f;
g_size += (max[j]-min[j])*(max[j]-min[j]);
}
g_size = sqrtf(g_size);
updateGeom();
}
//------------------------------------------------------------------------------
void
display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, g_width, g_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_LIGHTING);
glColor3f(1, 1, 1);
glBegin(GL_QUADS);
glColor3f(0.5f, 0.5f, 0.5f);
glVertex3f(-1, -1, 1);
glVertex3f( 1, -1, 1);
glColor3f(0, 0, 0);
glVertex3f( 1, 1, 1);
glVertex3f(-1, 1, 1);
glEnd();
double aspect = g_width/(double)g_height;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, aspect, 0.01, 500.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(-g_pan[0], -g_pan[1], -g_dolly);
glRotatef(g_rotate[1], 1, 0, 0);
glRotatef(g_rotate[0], 0, 1, 0);
glTranslatef(-g_center[0], -g_center[1], -g_center[2]);
glRotatef(-90, 1, 0, 0); // z-up model
GLuint bVertex = g_vertexBuffer->GetGpuBuffer();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, bVertex);
glVertexPointer(3, GL_FLOAT, sizeof (GLfloat) * 6, 0);
glNormalPointer(GL_FLOAT, sizeof (GLfloat) * 6, (float*)12);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_indexBuffer);
GLenum primType = g_scheme == kLoop ? GL_TRIANGLES : GL_QUADS;
glEnable(GL_LIGHTING);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
if (g_wire > 0) {
glDrawElements(primType, g_numIndices, GL_UNSIGNED_INT, NULL);
}
glDisable(GL_LIGHTING);
if (g_wire == 0 || g_wire == 2) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
if (g_wire == 2) {
glColor4f(0, 0, 0.5, 1);
} else {
glColor4f(1, 1, 1, 1);
}
glDrawElements(primType, g_numIndices, GL_UNSIGNED_INT, NULL);
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
if (g_drawNormals)
drawNormals();
if (g_drawCoarseMesh)
drawCoarseMesh(g_drawCoarseMesh);
if (g_drawHUD) {
glColor3f(1, 1, 1);
drawString(10, 10, "LEVEL = %d", g_level);
drawString(10, 30, "# of Vertices = %d", g_osdmesh->GetFarMesh()->GetNumVertices());
drawString(10, 50, "KERNEL = %s", getKernelName(g_kernel));
drawString(10, 70, "CPU TIME = %.3f ms", g_cpuTime);
drawString(10, 90, "GPU TIME = %.3f ms", g_gpuTime);
drawString(10, 110, "SUBDIVISION = %s", g_scheme==kBilinear ? "BILINEAR" : (g_scheme == kLoop ? "LOOP" : "CATMARK"));
drawString(10, g_height-30, "w: toggle wireframe");
drawString(10, g_height-50, "e: display normal vector");
drawString(10, g_height-70, "m: toggle vertex deforming");
drawString(10, g_height-90, "h: display control cage");
drawString(10, g_height-110, "n/p: change model");
drawString(10, g_height-130, "1-7: subdivision level");
drawString(10, g_height-150, "space: freeze/unfreeze time");
}
glFinish();
glutSwapBuffers();
}
//------------------------------------------------------------------------------
void motion(int x, int y) {
if (g_mbutton[0] && !g_mbutton[1] && !g_mbutton[2]) {
// orbit
g_rotate[0] += x - g_prev_x;
g_rotate[1] += y - g_prev_y;
} else if (!g_mbutton[0] && g_mbutton[1] && !g_mbutton[2]) {
// pan
g_pan[0] -= g_dolly*(x - g_prev_x)/g_width;
g_pan[1] += g_dolly*(y - g_prev_y)/g_height;
} else if (g_mbutton[0] && g_mbutton[1] && !g_mbutton[2]) {
// dolly
g_dolly -= g_dolly*0.01f*(x - g_prev_x);
if(g_dolly <= 0.01) g_dolly = 0.01f;
}
g_prev_x = float(x);
g_prev_y = float(y);
}
//------------------------------------------------------------------------------
void mouse(int button, int state, int x, int y) {
g_prev_x = float(x);
g_prev_y = float(y);
g_mbutton[button] = !state;
}
//------------------------------------------------------------------------------
void quit() {
if(g_osdmesh)
delete g_osdmesh;
if (g_vertexBuffer)
delete g_vertexBuffer;
#ifdef OPENSUBDIV_HAS_CUDA
cudaDeviceReset();
#endif
exit(0);
}
//------------------------------------------------------------------------------
void kernelMenu(int k) {
g_kernel = k;
createOsdMesh( g_defaultShapes[ g_currentShape ].data, g_level, g_kernel, g_defaultShapes[ g_currentShape ].scheme );
}
//------------------------------------------------------------------------------
void
modelMenu(int m) {
if (m < 0)
m = 0;
if (m >= (int)g_defaultShapes.size())
m = g_defaultShapes.size() - 1;
g_currentShape = m;
glutSetWindowTitle( g_defaultShapes[m].name.c_str() );
createOsdMesh( g_defaultShapes[m].data, g_level, g_kernel, g_defaultShapes[ g_currentShape ].scheme );
}
//------------------------------------------------------------------------------
void
levelMenu(int l) {
g_level = l;
createOsdMesh( g_defaultShapes[g_currentShape].data, g_level, g_kernel, g_defaultShapes[ g_currentShape ].scheme );
}
//------------------------------------------------------------------------------
void
menu(int m) {
}
//------------------------------------------------------------------------------
void
keyboard(unsigned char key, int x, int y) {
switch (key) {
case 'q': quit();
case ' ': g_freeze = (g_freeze+1)%2; break;
case 'w': g_wire = (g_wire+1)%3; break;
case 'e': g_drawNormals = (g_drawNormals+1)%2; break;
case 'f': fitFrame(); break;
case 'm': g_moveScale = 1.0f - g_moveScale; break;
case 'h': g_drawCoarseMesh = (g_drawCoarseMesh+1)%3; break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': levelMenu(key-'0'); break;
case 'n': modelMenu(++g_currentShape); break;
case 'p': modelMenu(--g_currentShape); break;
case 0x1b: g_drawHUD = (g_drawHUD+1)%2; break;
}
}
//------------------------------------------------------------------------------
void
idle() {
if (not g_freeze)
g_frame++;
updateGeom();
glutPostRedisplay();
if (g_repeatCount != 0 and g_frame >= g_repeatCount)
quit();
}
//------------------------------------------------------------------------------
void
initGL() {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glEnable(GL_LIGHT0);
glColor3f(1, 1, 1);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
GLfloat color[4] = {1, 1, 1, 1};
GLfloat position[4] = {5, 5, 10, 1};
GLfloat ambient[4] = {0.1f, 0.1f, 0.1f, 1.0f};
GLfloat diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat shininess = 25.0;
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shininess);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
}
//------------------------------------------------------------------------------
int main(int argc, char ** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA |GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(1024, 1024);
glutCreateWindow("OpenSubdiv test");
std::string str;
if (argc > 1) {
std::ifstream ifs(argv[1]);
if (ifs) {
std::stringstream ss;
ss << ifs.rdbuf();
ifs.close();
str = ss.str();
g_defaultShapes.push_back(SimpleShape(str.c_str(), argv[1], kCatmark));
}
}
initializeShapes();
int smenu = glutCreateMenu(modelMenu);
for(int i = 0; i < (int)g_defaultShapes.size(); ++i){
glutAddMenuEntry( g_defaultShapes[i].name.c_str(), i);
}
int lmenu = glutCreateMenu(levelMenu);
for(int i = 1; i < 8; ++i){
char level[16];
sprintf(level, "Level %d\n", i);
glutAddMenuEntry(level, i);
}
// Register Osd compute kernels
OpenSubdiv::OsdCpuKernelDispatcher::Register();
#if OPENSUBDIV_HAS_GLSL
OpenSubdiv::OsdGlslKernelDispatcher::Register();
#endif
#if OPENSUBDIV_HAS_OPENCL
OpenSubdiv::OsdClKernelDispatcher::Register();
#endif
#if OPENSUBDIV_HAS_CUDA
OpenSubdiv::OsdCudaKernelDispatcher::Register();
// Note: This function randomly crashes with linux 5.0-dev driver.
// cudaGetDeviceProperties overrun stack..?
cudaGLSetGLDevice( cutGetMaxGflopsDeviceId() );
#endif
int kmenu = glutCreateMenu(kernelMenu);
int nKernels = OpenSubdiv::OsdKernelDispatcher::kMAX;
for(int i = 0; i < nKernels; ++i)
if(OpenSubdiv::OsdKernelDispatcher::HasKernelType(
OpenSubdiv::OsdKernelDispatcher::KernelType(i)))
glutAddMenuEntry(getKernelName(i), i);
glutCreateMenu(menu);
glutAddSubMenu("Level", lmenu);
glutAddSubMenu("Model", smenu);
glutAddSubMenu("Kernel", kmenu);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutMotionFunc(motion);
#if not defined(__APPLE__)
glewInit();
#endif
initGL();
const char *filename = NULL;
for (int i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-d"))
g_level = atoi(argv[++i]);
else if (!strcmp(argv[i], "-c"))
g_repeatCount = atoi(argv[++i]);
else
filename = argv[i];
}
glGenBuffers(1, &g_indexBuffer);
modelMenu(0);
glutIdleFunc(idle);
glutMainLoop();
quit();
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,50 @@
global proc AEopenSubdivPtexShaderTemplate(string $node)
{
editorTemplate -beginScrollLayout;
editorTemplate -beginLayout "Subdivision" -collapse false;
editorTemplate -addControl "scheme";
editorTemplate -addControl "level";
editorTemplate -endLayout;
editorTemplate -beginLayout "PTex" -collapse false;
editorTemplate -addControl "colorFile";
editorTemplate -addControl "displacementFile";
editorTemplate -addControl "occlusionFile";
editorTemplate -endLayout;
editorTemplate -beginLayout "Shader" -collapse false;
editorTemplate -addControl "shaderSource";
editorTemplate -addControl "wireframe";
editorTemplate -beginNoOptimize;
editorTemplate -addControl "enableColor";
editorTemplate -addControl "enableDisplacement";
editorTemplate -addControl "enableOcclusion";
editorTemplate -endNoOptimize;
editorTemplate -addSeparator;
editorTemplate -addControl "diffuse";
editorTemplate -addControl "ambient";
editorTemplate -addControl "specular";
editorTemplate -addSeparator;
editorTemplate -addControl "fresnelBias";
editorTemplate -addControl "fresnelScale";
editorTemplate -addControl "fresnelPower";
editorTemplate -addControl "light";
editorTemplate -endLayout;
editorTemplate -beginLayout "Environment" -collapse false;
editorTemplate -addControl "diffuseMap";
editorTemplate -addControl "environmentMap";
editorTemplate -endLayout;
editorTemplate -addExtraControls;
editorTemplate -endScrollLayout;
editorTemplate -suppress "nodeState";
}

View File

@ -0,0 +1,175 @@
#
# Copyright (C) Pixar. All rights reserved.
#
# This license governs use of the accompanying software. If you
# use the software, you accept this license. If you do not accept
# the license, do not use the software.
#
# 1. Definitions
# The terms "reproduce," "reproduction," "derivative works," and
# "distribution" have the same meaning here as under U.S.
# copyright law. A "contribution" is the original software, or
# any additions or changes to the software.
# A "contributor" is any person or entity that distributes its
# contribution under this license.
# "Licensed patents" are a contributor's patent claims that read
# directly on its contribution.
#
# 2. Grant of Rights
# (A) Copyright Grant- Subject to the terms of this license,
# including the license conditions and limitations in section 3,
# each contributor grants you a non-exclusive, worldwide,
# royalty-free copyright license to reproduce its contribution,
# prepare derivative works of its contribution, and distribute
# its contribution or any derivative works that you create.
# (B) Patent Grant- Subject to the terms of this license,
# including the license conditions and limitations in section 3,
# each contributor grants you a non-exclusive, worldwide,
# royalty-free license under its licensed patents to make, have
# made, use, sell, offer for sale, import, and/or otherwise
# dispose of its contribution in the software or derivative works
# of the contribution in the software.
#
# 3. Conditions and Limitations
# (A) No Trademark License- This license does not grant you
# rights to use any contributor's name, logo, or trademarks.
# (B) If you bring a patent claim against any contributor over
# patents that you claim are infringed by the software, your
# patent license from such contributor to the software ends
# automatically.
# (C) If you distribute any portion of the software, you must
# retain all copyright, patent, trademark, and attribution
# notices that are present in the software.
# (D) If you distribute any portion of the software in source
# code form, you may do so only under this license by including a
# complete copy of this license with your distribution. If you
# distribute any portion of the software in compiled or object
# code form, you may only do so under a license that complies
# with this license.
# (E) The software is licensed "as-is." You bear the risk of
# using it. The contributors give no express warranties,
# guarantees or conditions. You may have additional consumer
# rights under your local laws which this license cannot change.
# To the extent permitted under your local laws, the contributors
# exclude the implied warranties of merchantability, fitness for
# a particular purpose and non-infringement.
#
# *** mayaPtexViewer ***
set(MAYA_FIND_QUIETLY TRUE)
set(SHADER_FILES
shader.glsl
)
if(NOT MAYA_FOUND)
message(STATUS
"Maya could not be found, so the OpenSubdiv mayaViwer plugin will not "
"be available. If you do have Maya installed and see this message, "
"please add your Maya path to cmake/FindMaya.cmake or set it in "
"the MAYA_LOCATION environment variable."
)
return()
endif()
include_directories(
${PROJECT_SOURCE_DIR}/opensubdiv
${MAYA_INCLUDE_DIRS}
${ILMBASE_INCLUDE_DIR}
${GLEW_INCLUDE_DIR}
${PTEX_INCLUDE_DIR}
)
set(SOURCE_FILES
OpenSubdivPtexShader.cpp
hbrUtil.cpp
cudaUtil.cpp
)
set(HEADER_FILES
)
if(UNIX)
set(PLATFORM_COMPILE_FLAGS
-D_BOOL
-DREQUIRE_IOSTREAM
-DLINUX
)
set(PLATFORM_LIBRARIES
)
set(PLATFORM_PLUGIN_EXTENSION
.so
)
set(PLATFORM_LINK_FLAGS
)
endif(UNIX)
if(WIN32)
set(PLATFORM_COMPILE_FLAGS
/D_AFXDLL
/DNT_PLUGIN
/DREQUIRE_IOSTREAM
)
set(PLATFORM_LIBRARIES
)
set(PLATFORM_PLUGIN_EXTENSION
.mll
)
set(PLATFORM_LINK_FLAGS
"/export:initializePlugin /export:uninitializePlugin"
)
endif(WIN32)
add_definitions(
${PLATFORM_COMPILE_FLAGS}
)
#-------------------------------------------------------------------------------
# Shader Stringification
# We want to use preprocessor include directives to include GLSL and OpenCL
# shader source files in cpp files, but since the sources contain newline
# characters we would need raw string literals from C++11 to do this directly.
# To avoid depending on C++11 we instead use a small tool called "line_quote"
# to generate source files that are suitable for direct inclusion.
foreach(shader_file ${SHADER_FILES})
string(REGEX REPLACE ".*[.](.*)" "\\1" extension ${shader_file})
string(REGEX REPLACE "(.*)[.].*" "\\1.inc" inc_file ${shader_file})
list(APPEND INC_FILES ${inc_file})
add_custom_command(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${inc_file}
COMMAND stringify ${CMAKE_CURRENT_SOURCE_DIR}/${shader_file}
${CMAKE_CURRENT_SOURCE_DIR}/${inc_file}
DEPENDS stringify ${CMAKE_CURRENT_SOURCE_DIR}/${shader_file}
)
endforeach()
#-------------------------------------------------------------------------------
add_library(maya_ptex_plugin SHARED
${SOURCE_FILES}
${HEADER_FILES}
${SHADER_FILES}
${INC_FILES}
)
set_target_properties(maya_ptex_plugin
PROPERTIES
OUTPUT_NAME "mayaPtexViewer"
SUFFIX ${PLATFORM_PLUGIN_EXTENSION}
LINK_FLAGS "${PLATFORM_LINK_FLAGS}"
)
target_link_libraries(maya_ptex_plugin
${OSD_LINK_TARGET}
${MAYA_Foundation_LIBRARY}
${MAYA_OpenMaya_LIBRARY}
${MAYA_OpenMayaRender_LIBRARY}
${MAYA_tbb_LIBRARY}
${PLATFORM_LIBRARIES}
${ILMBASE_LIBRARIES}
${GLEW_LIBRARY}
${PTEX_LIBRARY}
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,12 @@
#include <GL/glew.h>
#include <cuda_runtime_api.h>
#include <cuda_gl_interop.h>
#include <stdio.h>
#include <algorithm>
#include "../common/cudaInit.h"
void cudaInit()
{
cudaGLSetGLDevice( cutGetMaxGflopsDeviceId() );
}

View File

@ -0,0 +1,197 @@
//
// 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.
//
#include "hbrUtil.h"
#include <far/mesh.h>
#include <hbr/mesh.h>
#include <hbr/bilinear.h>
#include <hbr/loop.h>
#include <hbr/catmark.h>
#define OSD_ERROR printf // XXXX
OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices,
std::vector<int> const & numIndices,
std::vector<int> const & faceIndices,
std::vector<int> const & vtxCreaseIndices,
std::vector<float> const & vtxCreases,
std::vector<int> const & edgeCrease1Indices, // face index, local edge index
std::vector<float> const & edgeCreases1,
std::vector<int> const & edgeCrease2Indices, // 2 vertex indices (Maya friendly)
std::vector<float> const & edgeCreases2,
int interpBoundary, int scheme)
{
static OpenSubdiv::HbrBilinearSubdivision<OpenSubdiv::OsdVertex> _bilinear;
static OpenSubdiv::HbrLoopSubdivision<OpenSubdiv::OsdVertex> _loop;
static OpenSubdiv::HbrCatmarkSubdivision<OpenSubdiv::OsdVertex> _catmark;
OpenSubdiv::OsdHbrMesh *hbrMesh;
if (scheme == 0)
hbrMesh = new OpenSubdiv::OsdHbrMesh(&_catmark);
else if (scheme == 1)
hbrMesh = new OpenSubdiv::OsdHbrMesh(&_loop);
else
hbrMesh = new OpenSubdiv::OsdHbrMesh(&_bilinear);
OpenSubdiv::OsdVertex v;
for(int i = 0; i < nVertices; ++i){
// create empty vertex : actual vertices will be initialized in UpdatePoints();
hbrMesh->NewVertex(i, v);
}
// get face indices
std::vector<int> vIndex;
int nFaces = (int)numIndices.size(), offset = 0, ptxidx = 0;
for (int i = 0; i < nFaces; ++i) {
int numVertex = numIndices[i];
vIndex.resize(numVertex);
bool valid=true;
for (int j=0; j<numVertex; ++j) {
vIndex[j] = faceIndices[j + offset];
int vNextIndex = faceIndices[(j+1)%numVertex + offset];
// check for non-manifold face
OpenSubdiv::OsdHbrVertex * origin = hbrMesh->GetVertex( vIndex[j] );
OpenSubdiv::OsdHbrVertex * destination = hbrMesh->GetVertex( vNextIndex );
if (!origin || !destination) {
OSD_ERROR("ERROR : An edge was specified that connected a nonexistent vertex");
valid=false;
}
if (origin == destination) {
OSD_ERROR("ERROR : An edge was specified that connected a vertex to itself");
valid=false;
}
OpenSubdiv::OsdHbrHalfedge * opposite = destination->GetEdge(origin);
if (opposite && opposite->GetOpposite()) {
OSD_ERROR("ERROR : A non-manifold edge incident to more than 2 faces was found");
valid=false;
}
if (origin->GetEdge(destination)) {
OSD_ERROR("ERROR : An edge connecting two vertices was specified more than once. "
"It's likely that an incident face was flipped");
valid=false;
}
}
if ( valid ) {
OpenSubdiv::OsdHbrFace *face = hbrMesh->NewFace(numVertex, &(vIndex[0]), 0);
face->SetPtexIndex(ptxidx);
ptxidx += (numVertex == 4) ? 1 : numVertex;
}
else
OSD_ERROR("Face %d will be ignored\n", i);
offset += numVertex;
}
// XXX: use hbr enum or redefine same enum in gsd
hbrMesh->SetInterpolateBoundaryMethod((OpenSubdiv::OsdHbrMesh::InterpolateBoundaryMethod)interpBoundary);
// set edge crease in two different indexing way
int nEdgeCreases = (int)edgeCreases1.size();
for (int i = 0; i < nEdgeCreases; ++i) {
if( edgeCreases1[i] <= 0. )
continue;
OpenSubdiv::OsdHbrHalfedge * e = hbrMesh->GetFace(edgeCrease1Indices[i*2])->GetEdge(edgeCrease1Indices[i*2+1]);
if (!e) {
OSD_ERROR("Can't find edge (face %d edge %d)\n", edgeCrease1Indices[i*2], edgeCrease1Indices[i*2+1]);
continue;
}
e->SetSharpness( (float)edgeCreases1[i] );
}
nEdgeCreases = (int)edgeCreases2.size();
for (int i = 0; i < nEdgeCreases; ++i) {
if( edgeCreases1[i] <= 0. )
continue;
OpenSubdiv::OsdHbrVertex * v0 = hbrMesh->GetVertex(edgeCrease2Indices[i*2]);
OpenSubdiv::OsdHbrVertex * v1 = hbrMesh->GetVertex(edgeCrease2Indices[i*2+1]);
OpenSubdiv::OsdHbrHalfedge * e = NULL;
if ( v0 && v1 )
if ( ! (e = v0->GetEdge(v1)) )
e = v1->GetEdge(v0);
if (!e) {
OSD_ERROR("ERROR can't find edge");
continue;
}
e->SetSharpness( (float)edgeCreases2[i] );
}
// set corner
{
int nVertexCreases = (int)vtxCreases.size();
for ( int i = 0; i< nVertexCreases; ++i ) {
if( vtxCreases[i] <= 0. )
continue;
OpenSubdiv::OsdHbrVertex * v = hbrMesh->GetVertex(vtxCreaseIndices[i]);
if (!v) {
OSD_ERROR("Can't find vertex %d\n", vtxCreaseIndices[i]);
continue;
}
v->SetSharpness( (float)vtxCreases[i] );
}
}
hbrMesh->Finish();
return hbrMesh;
}

View File

@ -0,0 +1,74 @@
//
// 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 OSD_HBR_UTIL_H
#define OSD_HBR_UTIL_H
#include <vector>
#include <osd/mesh.h>
extern "C" OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices,
std::vector<int> const & numIndices,
std::vector<int> const & faceIndices,
std::vector<int> const & vtxCreaseIndices,
std::vector<float> const & vtxCreases,
std::vector<int> const & edgeCrease1Indices,
std::vector<float> const & edgeCreases1,
std::vector<int> const & edgeCrease2Indices,
std::vector<float> const & edgeCreases2,
int interpBoundary,
int scheme);
#endif

View File

@ -0,0 +1,294 @@
//
// 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.
//
#version 400
//--------------------------------------------------------------
// Common
//--------------------------------------------------------------
uniform int ptexLevel;
uniform isamplerBuffer ptexIndices;
vec4 PTexLookup(vec2 faceUV,
sampler2DArray data,
samplerBuffer packings,
isamplerBuffer pages)
{
ivec2 ptexIndex = texelFetch(ptexIndices, gl_PrimitiveID).xy;
int faceID = abs(ptexIndex.x);
int u = ptexIndex.y >> 16;
int v = (ptexIndex.y & 0xffff);
int lv = ptexLevel;
if (ptexIndex.x < 0) lv >>= 1; // non-quad root face
int page = texelFetch(pages, faceID).x;
vec4 packing = texelFetch(packings, faceID);
vec2 uv = (faceUV * vec2(1.0)/lv) + vec2(u, v)/lv;
vec3 coords = vec3( packing.x + uv.x * packing.z,
packing.y + uv.y * packing.w,
page);
return texture(data, coords);
}
//--------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------
#ifdef VERTEX_SHADER
layout (location=0) in vec3 position;
layout (location=1) in vec3 normal;
out vec3 vPosition;
out vec3 vNormal;
void main()
{
vPosition = position;
vNormal = normal;
}
#endif
//--------------------------------------------------------------
// Geometry Shader
//--------------------------------------------------------------
#ifdef GEOMETRY_SHADER
layout(lines_adjacency) in;
layout(triangle_strip, max_vertices = 4) out;
#if USE_PTEX_DISPLACEMENT
uniform sampler2DArray textureDisplace_Data;
uniform samplerBuffer textureDisplace_Packing;
uniform isamplerBuffer textureDisplace_Pages;
#endif
uniform mat4 objectToClipMatrix;
uniform mat4 objectToEyeMatrix;
in vec3 vPosition[4];
in vec3 vNormal[4];
flat out vec3 gFacetNormal;
out vec3 Pobj;
out vec3 Nobj;
out vec2 gFaceUV;
void main()
{
gl_PrimitiveID = gl_PrimitiveIDIn;
vec3 pos[4];
vec2 teTextureCoord[4];
teTextureCoord[0] = vec2(0, 0);
teTextureCoord[1] = vec2(1, 0);
teTextureCoord[2] = vec2(1, 1);
teTextureCoord[3] = vec2(0, 1);
pos[0] = vPosition[0];
pos[1] = vPosition[1];
pos[2] = vPosition[2];
pos[3] = vPosition[3];
#if USE_PTEX_DISPLACEMENT
for(int i=0; i< 4; i++){
vec4 displace = PTexLookup(teTextureCoord[i],
textureDisplace_Data,
textureDisplace_Packing,
textureDisplace_Pages);
pos[i] += displace.x * vNormal[i];
}
#endif
vec3 A = pos[0] - pos[1];
vec3 B = pos[3] - pos[1];
vec3 C = pos[2] - pos[1];
gFacetNormal = normalize(cross(B, A));
Pobj = pos[0];
gl_Position = objectToClipMatrix * vec4(pos[0], 1);
Nobj = vNormal[0];
gFaceUV = teTextureCoord[0];
EmitVertex();
Pobj = pos[1];
gl_Position = objectToClipMatrix * vec4(pos[1], 1);
Nobj = vNormal[1];
gFaceUV = teTextureCoord[1];
EmitVertex();
Pobj = pos[3];
gl_Position = objectToClipMatrix * vec4(pos[3], 1);
Nobj = vNormal[3];
gFaceUV = teTextureCoord[3];
EmitVertex();
gFacetNormal = normalize(cross(C, B));
Pobj = pos[2];
gl_Position = objectToClipMatrix * vec4(pos[2], 1);
Nobj = vNormal[2];
gFaceUV = teTextureCoord[2];
EmitVertex();
EndPrimitive();
}
#endif
//--------------------------------------------------------------
// Fragment Shader
//--------------------------------------------------------------
#ifdef FRAGMENT_SHADER
uniform int ptexFaceOffset;
#if USE_PTEX_COLOR
uniform sampler2DArray textureImage_Data;
uniform samplerBuffer textureImage_Packing;
uniform isamplerBuffer textureImage_Pages;
#endif
#if USE_PTEX_OCCLUSION
uniform sampler2DArray textureOcclusion_Data;
uniform samplerBuffer textureOcclusion_Packing;
uniform isamplerBuffer textureOcclusion_Pages;
#endif
uniform sampler2D diffuseMap;
uniform sampler2D environmentMap;
flat in vec3 gFacetNormal;
in vec3 Pobj;
in vec3 Nobj;
in vec2 gFaceUV;
#define NUM_LIGHTS 1
struct LightSource {
vec4 position;
vec4 ambient;
vec4 diffuse;
vec4 specular;
};
uniform LightSource lightSource[NUM_LIGHTS];
uniform vec3 diffuse;
uniform vec3 ambient;
uniform vec3 specular;
uniform vec3 eyePositionInWorld;
uniform float fresnelBias;
uniform float fresnelScale;
uniform float fresnelPower;
vec4 getEnvironment(sampler2D sampler, vec3 dir)
{
return texture(sampler, vec2((atan(dir.x,dir.z)/3.1415926+1)*0.5, (1-dir.y)*0.5));
}
void
main()
{
#if USE_PTEX_COLOR
vec4 texColor = PTexLookup(gFaceUV,
textureImage_Data,
textureImage_Packing,
textureImage_Pages);
#else
vec4 texColor = vec4(1);
#endif
#if USE_PTEX_DISPLACEMENT
vec3 objN = (gl_FrontFacing ? gFacetNormal : -gFacetNormal);
#else
vec3 objN = (gl_FrontFacing ? Nobj : -Nobj);
#endif
#if USE_PTEX_OCCLUSION
float occ = PTexLookup(gFaceUV,
textureOcclusion_Data,
textureOcclusion_Packing,
textureOcclusion_Pages).x;
#else
float occ = 0.0;
#endif
vec4 a = vec4(ambient, 1);
vec4 d = getEnvironment(diffuseMap, objN) * 1.4;
vec3 eye = normalize(Pobj - eyePositionInWorld);
vec3 reflect = reflect(eye, objN);
vec4 s = getEnvironment(environmentMap, reflect);
float fresnel = fresnelBias + fresnelScale * pow(1.0+dot(objN,eye), fresnelPower);
a *= (1.0-occ);
d *= (1.0-occ)*vec4(diffuse, 1);
s *= (1.0-pow(occ, 0.2))*vec4(specular, 1) * fresnel;
gl_FragColor = (a + d) * texColor + s;
gl_FragColor = pow(gl_FragColor, vec4(0.4545));
}
#endif

View File

@ -137,5 +137,6 @@ target_link_libraries(maya_plugin
${MAYA_OpenMayaRender_LIBRARY} ${MAYA_OpenMayaRender_LIBRARY}
${MAYA_tbb_LIBRARY} ${MAYA_tbb_LIBRARY}
${PLATFORM_LIBRARIES} ${PLATFORM_LIBRARIES}
${ILMBASE_LIBRARIES}
${GLEW_LIBRARY} ${GLEW_LIBRARY}
) )

View File

@ -160,7 +160,7 @@ class OpenSubdivDrawOverride : public MHWRender::MPxDrawOverride
public: public:
static MHWRender::MPxDrawOverride* Creator(const MObject& obj) { static MHWRender::MPxDrawOverride* Creator(const MObject& obj) {
return new OpenSubdivDrawOverride(obj); return new OpenSubdivDrawOverride(obj);
} }
virtual ~OpenSubdivDrawOverride(); virtual ~OpenSubdivDrawOverride();
@ -202,7 +202,7 @@ SubdivUserData::~SubdivUserData()
glDeleteBuffers(1, &_index); glDeleteBuffers(1, &_index);
} }
void void
SubdivUserData::Populate(MObject mesh) SubdivUserData::Populate(MObject mesh)
{ {
MStatus s; MStatus s;
@ -254,7 +254,7 @@ SubdivUserData::Populate(MObject mesh)
} }
// XXX redundant copy... replace _vertexList with numIndices, etc // XXX redundant copy... replace _vertexList with numIndices, etc
// create Osd mesh // create Osd mesh
std::vector<int> numIndices, faceIndices, edgeCreaseIndices, vtxCreaseIndices; std::vector<int> numIndices, faceIndices, edgeCreaseIndices, vtxCreaseIndices;
std::vector<float> edgeCreases, vtxCreases; std::vector<float> edgeCreases, vtxCreases;
@ -307,7 +307,7 @@ SubdivUserData::Populate(MObject mesh)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _index); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _index);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*_numIndices, glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*_numIndices,
&(indices[0]), GL_STATIC_DRAW); &(indices[0]), GL_STATIC_DRAW);
_cachedTotal = -1; _cachedTotal = -1;
UpdatePoints(mesh); UpdatePoints(mesh);
} }
@ -546,8 +546,8 @@ OpenSubdivCommand::doIt(const MArgList &args)
// Plugin Registration // Plugin Registration
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
MString drawDbClassification("drawdb/geometry/mesh"); MString drawDbClassification("drawdb/geometry/mesh");
MString drawRegistrantId("OpenSubdivDrawOverridePlugin"); MString drawRegistrantId("OpenSubdivDrawOverridePlugin");
MStatus initializePlugin( MObject obj ) MStatus initializePlugin( MObject obj )
{ {

View File

@ -77,7 +77,7 @@ OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices,
static OpenSubdiv::HbrBilinearSubdivision<OpenSubdiv::OsdVertex> _bilinear; static OpenSubdiv::HbrBilinearSubdivision<OpenSubdiv::OsdVertex> _bilinear;
static OpenSubdiv::HbrLoopSubdivision<OpenSubdiv::OsdVertex> _loop; static OpenSubdiv::HbrLoopSubdivision<OpenSubdiv::OsdVertex> _loop;
static OpenSubdiv::HbrCatmarkSubdivision<OpenSubdiv::OsdVertex> _catmark; static OpenSubdiv::HbrCatmarkSubdivision<OpenSubdiv::OsdVertex> _catmark;
OpenSubdiv::OsdHbrMesh *hbrMesh; OpenSubdiv::OsdHbrMesh *hbrMesh;
if (loop) if (loop)
hbrMesh = new OpenSubdiv::OsdHbrMesh(&_loop); hbrMesh = new OpenSubdiv::OsdHbrMesh(&_loop);
@ -128,9 +128,9 @@ OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices,
} }
} }
if ( valid ) if ( valid )
hbrMesh->NewFace(numVertex, &(vIndex[0]), 0); hbrMesh->NewFace(numVertex, &(vIndex[0]), 0);
else else
OSD_ERROR("Face %d will be ignored\n", i); OSD_ERROR("Face %d will be ignored\n", i);
offset += numVertex; offset += numVertex;
@ -142,7 +142,7 @@ OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices,
// set edge crease in two different indexing way // set edge crease in two different indexing way
int nEdgeCreases = (int)edgeCreases1.size(); int nEdgeCreases = (int)edgeCreases1.size();
for (int i = 0; i < nEdgeCreases; ++i) { for (int i = 0; i < nEdgeCreases; ++i) {
if( edgeCreases1[i] <= 0. ) if( edgeCreases1[i] <= 0. )
continue; continue;
OpenSubdiv::OsdHbrHalfedge * e = hbrMesh->GetFace(edgeCrease1Indices[i*2])->GetEdge(edgeCrease1Indices[i*2+1]); OpenSubdiv::OsdHbrHalfedge * e = hbrMesh->GetFace(edgeCrease1Indices[i*2])->GetEdge(edgeCrease1Indices[i*2+1]);
@ -154,14 +154,14 @@ OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices,
} }
nEdgeCreases = (int)edgeCreases2.size(); nEdgeCreases = (int)edgeCreases2.size();
for (int i = 0; i < nEdgeCreases; ++i) { for (int i = 0; i < nEdgeCreases; ++i) {
if( edgeCreases1[i] <= 0. ) if( edgeCreases1[i] <= 0. )
continue; continue;
OpenSubdiv::OsdHbrVertex * v0 = hbrMesh->GetVertex(edgeCrease2Indices[i*2]); OpenSubdiv::OsdHbrVertex * v0 = hbrMesh->GetVertex(edgeCrease2Indices[i*2]);
OpenSubdiv::OsdHbrVertex * v1 = hbrMesh->GetVertex(edgeCrease2Indices[i*2+1]); OpenSubdiv::OsdHbrVertex * v1 = hbrMesh->GetVertex(edgeCrease2Indices[i*2+1]);
OpenSubdiv::OsdHbrHalfedge * e = NULL; OpenSubdiv::OsdHbrHalfedge * e = NULL;
if ( v0 && v1 ) if ( v0 && v1 )
if ( ! (e = v0->GetEdge(v1)) ) if ( ! (e = v0->GetEdge(v1)) )
e = v1->GetEdge(v0); e = v1->GetEdge(v0);
if (!e) { if (!e) {
@ -170,14 +170,14 @@ OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices,
} }
e->SetSharpness( (float)edgeCreases2[i] ); e->SetSharpness( (float)edgeCreases2[i] );
} }
// set corner // set corner
{ {
int nVertexCreases = (int)vtxCreases.size(); int nVertexCreases = (int)vtxCreases.size();
for ( int i = 0; i< nVertexCreases; ++i ) { for ( int i = 0; i< nVertexCreases; ++i ) {
if( vtxCreases[i] <= 0. ) if( vtxCreases[i] <= 0. )
continue; continue;
OpenSubdiv::OsdHbrVertex * v = hbrMesh->GetVertex(vtxCreaseIndices[i]); OpenSubdiv::OsdHbrVertex * v = hbrMesh->GetVertex(vtxCreaseIndices[i]);
if (!v) { if (!v) {
OSD_ERROR("Can't find vertex %d\n", vtxCreaseIndices[i]); OSD_ERROR("Can't find vertex %d\n", vtxCreaseIndices[i]);
continue; continue;

View File

@ -0,0 +1,114 @@
#
# 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.
#
# *** ptexViewer ***
set(SHADER_FILES
shader.glsl
)
set(PLATFORM_LIBRARIES
${OSD_LINK_TARGET}
${ILMBASE_LIBRARIES}
${OPENGL_LIBRARY}
${GLEW_LIBRARY}
${GLUT_LIBRARIES}
${PTEX_LIBRARY}
)
include_directories(
${PROJECT_SOURCE_DIR}/opensubdiv
${PROJECT_SOURCE_DIR}/regression
${ILMBASE_INCLUDE_DIR}
${GLEW_INCLUDE_DIR}
${GLUT_INCLUDE_DIR}
${PTEX_INCLUDE_DIR}
)
#-------------------------------------------------------------------------------
# Shader Stringification
# We want to use preprocessor include directives to include GLSL and OpenCL
# shader source files in cpp files, but since the sources contain newline
# characters we would need raw string literals from C++11 to do this directly.
# To avoid depending on C++11 we instead use a small tool called "line_quote"
# to generate source files that are suitable for direct inclusion.
foreach(shader_file ${SHADER_FILES})
string(REGEX REPLACE ".*[.](.*)" "\\1" extension ${shader_file})
string(REGEX REPLACE "(.*)[.].*" "\\1.inc" inc_file ${shader_file})
list(APPEND INC_FILES ${inc_file})
add_custom_command(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${inc_file}
COMMAND stringify ${CMAKE_CURRENT_SOURCE_DIR}/${shader_file}
${CMAKE_CURRENT_SOURCE_DIR}/${inc_file}
DEPENDS stringify ${CMAKE_CURRENT_SOURCE_DIR}/${shader_file}
)
endforeach()
#-------------------------------------------------------------------------------
_add_glut_executable(ptexViewer
viewer.cpp
${SHADER_FILES}
${INC_FILES}
)
target_link_libraries(ptexViewer
${PLATFORM_LIBRARIES}
)

View File

@ -0,0 +1,336 @@
//
// 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.
//
#version 400
//--------------------------------------------------------------
// Common
//--------------------------------------------------------------
uniform int ptexLevel;
uniform isamplerBuffer ptexIndices;
vec4 PTexLookup(vec2 faceUV,
sampler2DArray data,
samplerBuffer packings,
isamplerBuffer pages)
{
ivec2 ptexIndex = texelFetch(ptexIndices, gl_PrimitiveID).xy;
int faceID = abs(ptexIndex.x);
int u = ptexIndex.y >> 16;
int v = (ptexIndex.y & 0xffff);
int lv = ptexLevel;
if (ptexIndex.x < 0) lv >>= 1; // non-quad root face
int page = texelFetch(pages, faceID).x;
vec4 packing = texelFetch(packings, faceID);
vec2 uv = (faceUV * vec2(1.0)/lv) + vec2(u, v)/lv;
vec3 coords = vec3( packing.x + uv.x * packing.z,
packing.y + uv.y * packing.w,
page);
return texture(data, coords);
}
//--------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------
#ifdef VERTEX_SHADER
layout (location=0) in vec3 position;
layout (location=1) in vec3 normal;
out vec3 vPosition;
out vec3 vNormal;
out vec4 vColor;
void main()
{
vPosition = position;
vNormal = normal;
vColor = vec4(1, 1, 1, 1);
}
#endif
//--------------------------------------------------------------
// Geometry Shader
//--------------------------------------------------------------
#ifdef GEOMETRY_SHADER
layout(lines_adjacency) in;
layout(triangle_strip, max_vertices = 4) out;
#if USE_PTEX_DISPLACEMENT
uniform sampler2DArray textureDisplace_Data;
uniform samplerBuffer textureDisplace_Packing;
uniform isamplerBuffer textureDisplace_Pages;
#endif
uniform mat4 objectToClipMatrix;
uniform mat4 objectToEyeMatrix;
in vec3 vPosition[4];
in vec3 vNormal[4];
flat out vec3 gFacetNormal;
out vec3 Peye;
out vec3 Neye;
out vec4 Cout;
out vec2 gFaceUV;
void main()
{
gl_PrimitiveID = gl_PrimitiveIDIn;
vec3 pos[4];
vec2 teTextureCoord[4];
teTextureCoord[0] = vec2(0, 0);
teTextureCoord[1] = vec2(1, 0);
teTextureCoord[2] = vec2(1, 1);
teTextureCoord[3] = vec2(0, 1);
pos[0] = vPosition[0];
pos[1] = vPosition[1];
pos[2] = vPosition[2];
pos[3] = vPosition[3];
#if USE_PTEX_DISPLACEMENT
for(int i=0; i< 4; i++){
vec4 displace = PTexLookup(teTextureCoord[i],
textureDisplace_Data,
textureDisplace_Packing,
textureDisplace_Pages);
pos[i] += displace.x * vNormal[i];
}
#endif
vec3 A = pos[0] - pos[1];
vec3 B = pos[3] - pos[1];
vec3 C = pos[2] - pos[1];
gFacetNormal = (objectToEyeMatrix*vec4(normalize(cross(B, A)), 0)).xyz;
Peye = pos[0];
gl_Position = objectToClipMatrix * vec4(pos[0], 1);
Neye = (objectToEyeMatrix * vec4(vNormal[0], 0)).xyz;
gFaceUV = teTextureCoord[0];
EmitVertex();
Peye = pos[1];
gl_Position = objectToClipMatrix * vec4(pos[1], 1);
Neye = (objectToEyeMatrix * vec4(vNormal[1], 0)).xyz;
gFaceUV = teTextureCoord[1];
EmitVertex();
Peye = pos[3];
gl_Position = objectToClipMatrix * vec4(pos[3], 1);
Neye = (objectToEyeMatrix * vec4(vNormal[3], 0)).xyz;
gFaceUV = teTextureCoord[3];
EmitVertex();
gFacetNormal = (objectToEyeMatrix*vec4(normalize(cross(C, B)), 0)).xyz;
Peye = pos[2];
gl_Position = objectToClipMatrix * vec4(pos[2], 1);
Neye = (objectToEyeMatrix * vec4(vNormal[2], 0)).xyz;
gFaceUV = teTextureCoord[2];
EmitVertex();
EndPrimitive();
}
#endif
//--------------------------------------------------------------
// Fragment Shader
//--------------------------------------------------------------
#ifdef FRAGMENT_SHADER
uniform int ptexFaceOffset;
#if USE_PTEX_COLOR
uniform sampler2DArray textureImage_Data;
uniform samplerBuffer textureImage_Packing;
uniform isamplerBuffer textureImage_Pages;
#endif
#if USE_PTEX_OCCLUSION
uniform sampler2DArray textureOcclusion_Data;
uniform samplerBuffer textureOcclusion_Packing;
uniform isamplerBuffer textureOcclusion_Pages;
#endif
flat in vec3 gFacetNormal;
in vec3 Neye;
in vec3 Peye;
in vec4 Cout;
in vec2 gFaceUV;
#define NUM_LIGHTS 1
struct LightSource {
vec4 position;
vec4 ambient;
vec4 diffuse;
vec4 specular;
};
uniform LightSource lightSource[NUM_LIGHTS];
uniform bool useLighting = true;
vec4
lighting(vec3 Peye, vec3 Neye)
{
vec4 color = vec4(0);
for (int i = 0; i < NUM_LIGHTS; ++i) {
vec4 Plight = lightSource[i].position;
vec3 l = (Plight.w == 0.0)
? normalize(Plight.xyz) : normalize(Plight.xyz - Peye);
vec3 n = normalize(Neye);
vec3 h = normalize(l + vec3(0,0,1)); // directional viewer
float d = max(0.0, dot(n, l));
float s = pow(max(0.0, dot(n, h)), 8.0f);
#if USE_PTEX_OCCLUSION
float occ = PTexLookup(gFaceUV,
textureOcclusion_Data,
textureOcclusion_Packing,
textureOcclusion_Pages).x;
#else
float occ = 0.0;
#endif
color += (1.0-occ) * ((lightSource[i].ambient +
d * lightSource[i].diffuse +
s * lightSource[i].specular));
}
color.a = 1;
return color;
}
void
main()
{
#if USE_PTEX_COLOR
vec4 texColor = PTexLookup(gFaceUV,
textureImage_Data,
textureImage_Packing,
textureImage_Pages);
#else
vec4 texColor = vec4(1);
#endif
texColor = pow(texColor, vec4(0.4545));
if (useLighting) {
#if USE_PTEX_DISPLACEMENT
vec3 N = (gl_FrontFacing ? gFacetNormal : -gFacetNormal);
#else
vec3 N = (gl_FrontFacing ? Neye : -Neye);
#endif
//gl_FragColor = lighting(Peye, N) * texColor * Cout;
gl_FragColor = lighting(Peye, N) * texColor;
} else {
gl_FragColor = texColor*Cout;
}
}
#endif
//--------------------------------------------------------------
// Ptex debug vertex shader
//--------------------------------------------------------------
#ifdef PTEX_DEBUG_VERTEX_SHADER
in vec3 position;
out vec2 texCoord;
void
main()
{
gl_Position = vec4(position, 1);
texCoord = position.xy;
}
#endif
//--------------------------------------------------------------
// Ptex debug fragment shader
//--------------------------------------------------------------
#ifdef PTEX_DEBUG_FRAGMENT_SHADER
uniform int ptexDebugPage;
uniform sampler2DArray ptexDebugData;
in vec2 texCoord;
void
main()
{
gl_FragColor = texture(ptexDebugData, vec3(texCoord.x, texCoord.y, ptexDebugPage));
}
#endif

View File

@ -0,0 +1,999 @@
//
// 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.
//
#if defined(__APPLE__)
#include <GLUT/glut.h>
#else
#include <GL/glew.h>
#include <GL/glut.h>
#endif
#include <osd/vertex.h>
#include <osd/mesh.h>
#include <osd/cpuDispatcher.h>
#include <osd/glslDispatcher.h>
#include <osd/pTexture.h>
#include "../common/stopwatch.h"
#ifdef OPENSUBDIV_HAS_OPENCL
#include <osd/clDispatcher.h>
#endif
#ifdef OPENSUBDIV_HAS_CUDA
#include <osd/cudaDispatcher.h>
#include <cuda_runtime_api.h>
#include <cuda_gl_interop.h>
#include "../common/cudaInit.h"
#endif
#include "Ptexture.h"
#include "PtexUtils.h"
static const char *shaderSource =
#include "shader.inc"
;
#include <vector>
//------------------------------------------------------------------------------
int g_frame = 0,
g_repeatCount = 0;
// GLUT GUI variables
int g_wire = 0,
g_drawNormals = 0,
g_mbutton[3] = {0, 0, 0},
g_level = 2,
g_kernel = OpenSubdiv::OsdKernelDispatcher::kCPU,
g_scheme = 0,
g_gutterWidth = 1,
g_ptexDebug = 0,
g_gutterDebug = 0;
float g_moveScale = 1.0f;
// ptex switch
int g_color = 1,
g_occlusion = 0,
g_displacement = 0;
// camera
float g_rotate[2] = {0, 0},
g_prev_x = 0,
g_prev_y = 0,
g_dolly = 5,
g_pan[2] = {0, 0},
g_center[3] = {0, 0, 0},
g_size = 0;
// viewport
int g_width,
g_height;
// performance
float g_cpuTime = 0;
float g_gpuTime = 0;
Stopwatch g_fpsTimer;
// geometry
std::vector<float> g_positions,
g_normals;
int g_numIndices = 0;
GLuint g_indexBuffer;
GLuint g_program = 0;
GLuint g_debugProgram = 0;
OpenSubdiv::OsdMesh * g_osdmesh = 0;
OpenSubdiv::OsdVertexBuffer * g_vertexBuffer = 0;
OpenSubdiv::OsdPTexture * g_osdPTexImage = 0;
OpenSubdiv::OsdPTexture * g_osdPTexDisplacement = 0;
OpenSubdiv::OsdPTexture * g_osdPTexOcclusion = 0;
const char * g_ptexColorFile = 0;
const char * g_ptexDisplacementFile = 0;
const char * g_ptexOcclusionFile = 0;
//------------------------------------------------------------------------------
inline void
cross(float *n, const float *p0, const float *p1, const float *p2) {
float a[3] = { p1[0]-p0[0], p1[1]-p0[1], p1[2]-p0[2] };
float b[3] = { p2[0]-p0[0], p2[1]-p0[1], p2[2]-p0[2] };
n[0] = a[1]*b[2]-a[2]*b[1];
n[1] = a[2]*b[0]-a[0]*b[2];
n[2] = a[0]*b[1]-a[1]*b[0];
float rn = 1.0f/sqrtf(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
n[0] *= rn;
n[1] *= rn;
n[2] *= rn;
}
//------------------------------------------------------------------------------
inline void
normalize(float * p) {
float dist = sqrtf( p[0]*p[0] + p[1]*p[1] + p[2]*p[2] );
p[0]/=dist;
p[1]/=dist;
p[2]/=dist;
}
//------------------------------------------------------------------------------
inline void
multMatrix(float *d, const float *a, const float *b) {
for (int i=0; i<4; ++i)
{
for (int j=0; j<4; ++j)
{
d[i*4 + j] =
a[i*4 + 0] * b[0*4 + j] +
a[i*4 + 1] * b[1*4 + j] +
a[i*4 + 2] * b[2*4 + j] +
a[i*4 + 3] * b[3*4 + j];
}
}
}
//------------------------------------------------------------------------------
static void
calcNormals(OpenSubdiv::OsdHbrMesh * mesh, std::vector<float> const & pos, std::vector<float> & result ) {
// calc normal vectors
int nverts = (int)pos.size()/3;
int nfaces = mesh->GetNumCoarseFaces();
for (int i = 0; i < nfaces; ++i) {
OpenSubdiv::OsdHbrFace * f = mesh->GetFace(i);
float const * p0 = &pos[f->GetVertex(0)->GetID()*3],
* p1 = &pos[f->GetVertex(1)->GetID()*3],
* p2 = &pos[f->GetVertex(2)->GetID()*3];
float n[3];
cross( n, p0, p1, p2 );
for (int j = 0; j < f->GetNumVertices(); j++) {
int idx = f->GetVertex(j)->GetID() * 3;
result[idx ] += n[0];
result[idx+1] += n[1];
result[idx+2] += n[2];
}
}
for (int i = 0; i < nverts; ++i)
normalize( &result[i*3] );
}
//------------------------------------------------------------------------------
void
updateGeom() {
int nverts = (int)g_positions.size() / 3;
std::vector<float> vertex;
vertex.reserve(nverts*6);
const float *p = &g_positions[0];
const float *n = &g_normals[0];
for (int i = 0; i < nverts; ++i) {
float move = g_size*0.005f*cosf(p[0]*100/g_size+g_frame*0.01f);
vertex.push_back(p[0]);
vertex.push_back(p[1]+g_moveScale*move);
vertex.push_back(p[2]);
vertex.push_back(n[0]);
vertex.push_back(n[1]);
vertex.push_back(n[2]);
p += 3;
n += 3;
}
if (!g_vertexBuffer)
g_vertexBuffer = g_osdmesh->InitializeVertexBuffer(6);
g_vertexBuffer->UpdateData(&vertex[0], nverts);
Stopwatch s;
s.Start();
g_osdmesh->Subdivide(g_vertexBuffer, NULL);
s.Stop();
g_cpuTime = float(s.GetElapsed() * 1000.0f);
s.Start();
g_osdmesh->Synchronize();
s.Stop();
g_gpuTime = float(s.GetElapsed() * 1000.0f);
glBindBuffer(GL_ARRAY_BUFFER, g_vertexBuffer->GetGpuBuffer());
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
//-------------------------------------------------------------------------------
void
fitFrame() {
g_pan[0] = g_pan[1] = 0;
g_dolly = g_size;
}
//-------------------------------------------------------------------------------
template <class T>
OpenSubdiv::HbrMesh<T> * createPTexGeo(PtexTexture * r)
{
PtexMetaData* meta = r->getMetaData();
if(meta->numKeys()<3) return NULL;
const float* vp;
const int *vi, *vc;
int nvp, nvi, nvc;
meta->getValue("PtexFaceVertCounts", vc, nvc);
if (nvc==0)
return NULL;
meta->getValue("PtexVertPositions", vp, nvp);
if (nvp==0)
return NULL;
meta->getValue("PtexFaceVertIndices", vi, nvi);
if (nvi==0)
return NULL;
static OpenSubdiv::HbrCatmarkSubdivision<T> _catmark;
static OpenSubdiv::HbrBilinearSubdivision<T> _bilinear;
OpenSubdiv::HbrMesh<T> * mesh;
if(g_scheme == 0)
mesh = new OpenSubdiv::HbrMesh<T>(&_catmark);
else
mesh = new OpenSubdiv::HbrMesh<T>(&_bilinear);
g_positions.clear();
g_positions.reserve(nvp);
// compute model bounding
float min[3] = {vp[0], vp[1], vp[2]};
float max[3] = {vp[0], vp[1], vp[2]};
for (int i=0; i<nvp/3; ++i) {
for(int j=0; j<3; ++j) {
float v = vp[i*3+j];
g_positions.push_back(v);
min[j] = std::min(min[j], v);
max[j] = std::max(max[j], v);
}
mesh->NewVertex(i, T());
}
for (int j=0; j<3; ++j) {
g_center[j] = (min[j] + max[j]) * 0.5f;
g_size += (max[j]-min[j])*(max[j]-min[j]);
}
g_size = sqrtf(g_size);
const int *fv = vi;
for (int i=0, ptxidx=0; i<nvc; ++i) {
int nv = vc[i];
OpenSubdiv::HbrFace<T> * face = mesh->NewFace(nv, (int *)fv, 0);
face->SetPtexIndex(ptxidx);
if(nv != 4)
ptxidx+=nv;
else
ptxidx++;
fv += nv;
}
mesh->SetInterpolateBoundaryMethod( OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryEdgeOnly );
// set creases here
// applyTags<T>( mesh, sh );
mesh->Finish();
return mesh;
}
//------------------------------------------------------------------------------
void
reshape(int width, int height) {
g_width = width;
g_height = height;
}
#if _MSC_VER
#define snprintf _snprintf
#endif
#define drawFmtString(x, y, fmt, ...) \
{ char line[1024]; \
snprintf(line, 1024, fmt, __VA_ARGS__); \
const char *p = line; \
glWindowPos2f(x, y); \
while(*p) { glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *p++); } }
#define drawString(x, y, str) \
{ const char *p = str; \
glWindowPos2f(x, y); \
while(*p) { glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *p++); } }
//------------------------------------------------------------------------------
const char *getKernelName(int kernel) {
if (kernel == OpenSubdiv::OsdKernelDispatcher::kCPU)
return "CPU";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kOPENMP)
return "OpenMP";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kCUDA)
return "Cuda";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kGLSL)
return "GLSL";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kCL)
return "OpenCL";
return "Unknown";
}
//------------------------------------------------------------------------------
static GLuint compileShader(GLenum shaderType, const char *section)
{
const char *sources[2];
char define[1024];
sprintf(define,
"#define %s\n"
"#define USE_PTEX_COLOR %d\n"
"#define USE_PTEX_OCCLUSION %d\n"
"#define USE_PTEX_DISPLACEMENT %d\n",
section, g_color, g_occlusion, g_displacement);
sources[0] = define;
sources[1] = shaderSource;
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 2, sources, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if( status == GL_FALSE ) {
GLchar emsg[1024];
glGetShaderInfoLog(shader, sizeof(emsg), 0, emsg);
fprintf(stderr, "Error compiling GLSL shader (%s): %s\n", section, emsg );
exit(0);
}
return shader;
}
void bindPTexture(OpenSubdiv::OsdPTexture *osdPTex, GLuint data, GLuint packing, GLuint pages, int samplerUnit)
{
glProgramUniform1i(g_program, data, samplerUnit + 0);
glActiveTexture(GL_TEXTURE0 + samplerUnit + 0);
glBindTexture(GL_TEXTURE_2D_ARRAY, osdPTex->GetTexelsTexture());
glProgramUniform1i(g_program, packing, samplerUnit + 1);
glActiveTexture(GL_TEXTURE0 + samplerUnit + 1);
glBindTexture(GL_TEXTURE_BUFFER, osdPTex->GetLayoutTextureBuffer());
glProgramUniform1i(g_program, pages, samplerUnit + 2);
glActiveTexture(GL_TEXTURE0 + samplerUnit + 2);
glBindTexture(GL_TEXTURE_BUFFER, osdPTex->GetPagesTextureBuffer());
glActiveTexture(GL_TEXTURE0);
}
void linkDebugProgram() {
if (g_debugProgram)
glDeleteProgram(g_debugProgram);
GLuint vertexShader = compileShader(GL_VERTEX_SHADER,
"PTEX_DEBUG_VERTEX_SHADER");
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER,
"PTEX_DEBUG_FRAGMENT_SHADER");
g_debugProgram = glCreateProgram();
glAttachShader(g_debugProgram, vertexShader);
glAttachShader(g_debugProgram, fragmentShader);
glLinkProgram(g_debugProgram);
glDeleteShader(fragmentShader);
GLint status;
glGetProgramiv(g_debugProgram, GL_LINK_STATUS, &status );
if( status == GL_FALSE ) {
GLchar emsg[1024];
glGetProgramInfoLog(g_debugProgram, sizeof(emsg), 0, emsg);
fprintf(stderr, "Error linking GLSL program : %s\n", emsg );
exit(0);
}
GLint texData = glGetUniformLocation(g_debugProgram, "ptexDebugData");
glProgramUniform1i(g_debugProgram, texData, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_ARRAY, g_osdPTexImage->GetTexelsTexture());
}
void linkProgram() {
if (g_program)
glDeleteProgram(g_program);
GLuint vertexShader = compileShader(GL_VERTEX_SHADER,
"VERTEX_SHADER");
GLuint geometryShader = compileShader(GL_GEOMETRY_SHADER,
"GEOMETRY_SHADER");
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER,
"FRAGMENT_SHADER");
g_program = glCreateProgram();
glAttachShader(g_program, vertexShader);
glAttachShader(g_program, geometryShader);
glAttachShader(g_program, fragmentShader);
glBindAttribLocation(g_program, 0, "position");
glBindAttribLocation(g_program, 1, "normal");
glLinkProgram(g_program);
glDeleteShader(vertexShader);
glDeleteShader(geometryShader);
glDeleteShader(fragmentShader);
GLint status;
glGetProgramiv(g_program, GL_LINK_STATUS, &status );
if( status == GL_FALSE ) {
GLchar emsg[1024];
glGetProgramInfoLog(g_program, sizeof(emsg), 0, emsg);
fprintf(stderr, "Error linking GLSL program : %s\n", emsg );
exit(0);
}
// bind ptexture
GLint texIndices = glGetUniformLocation(g_program, "ptexIndices");
GLint ptexLevel = glGetUniformLocation(g_program, "ptexLevel");
glProgramUniform1i(g_program, ptexLevel, 1<<g_level);
glProgramUniform1i(g_program, texIndices, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, g_osdmesh->GetPtexCoordinatesTextureBuffer(g_level));
// color ptex
GLint texData = glGetUniformLocation(g_program, "textureImage_Data");
GLint texPacking = glGetUniformLocation(g_program, "textureImage_Packing");
GLint texPages = glGetUniformLocation(g_program, "textureImage_Pages");
bindPTexture(g_osdPTexImage, texData, texPacking, texPages, 1);
// displacement ptex
if (g_displacement) {
texData = glGetUniformLocation(g_program, "textureDisplace_Data");
texPacking = glGetUniformLocation(g_program, "textureDisplace_Packing");
texPages = glGetUniformLocation(g_program, "textureDisplace_Pages");
bindPTexture(g_osdPTexDisplacement, texData, texPacking, texPages, 4);
}
// occlusion ptex
if (g_occlusion) {
texData = glGetUniformLocation(g_program, "textureOcclusion_Data");
texPacking = glGetUniformLocation(g_program, "textureOcclusion_Packing");
texPages = glGetUniformLocation(g_program, "textureOcclusion_Pages");
bindPTexture(g_osdPTexOcclusion, texData, texPacking, texPages, 7);
}
}
//------------------------------------------------------------------------------
void
createOsdMesh(int level, int kernel) {
Ptex::String ptexError;
PtexTexture *ptexColor = PtexTexture::open(g_ptexColorFile, ptexError, true);
// generate Hbr representation from ptex
OpenSubdiv::OsdHbrMesh * hmesh = createPTexGeo<OpenSubdiv::OsdVertex>(ptexColor);
if(hmesh == NULL) return;
g_normals.resize(g_positions.size(),0.0f);
calcNormals( hmesh, g_positions, g_normals );
// generate Osd mesh from Hbr mesh
if (g_osdmesh) delete g_osdmesh;
g_osdmesh = new OpenSubdiv::OsdMesh();
g_osdmesh->Create(hmesh, level, kernel);
if (g_vertexBuffer) {
delete g_vertexBuffer;
g_vertexBuffer = NULL;
}
// Hbr mesh can be deleted
delete hmesh;
// update element array buffer
const std::vector<int> &indices = g_osdmesh->GetFarMesh()->GetFaceVertices(level);
// generate oOsdPTexture
if (g_osdPTexDisplacement) delete g_osdPTexDisplacement;
if (g_osdPTexOcclusion) delete g_osdPTexOcclusion;
g_osdPTexDisplacement = NULL;
g_osdPTexOcclusion = NULL;
OpenSubdiv::OsdPTexture::SetGutterWidth(g_gutterWidth);
OpenSubdiv::OsdPTexture::SetPageMargin(g_gutterWidth*8);
OpenSubdiv::OsdPTexture::SetGutterDebug(g_gutterDebug);
if (g_osdPTexImage) delete g_osdPTexImage;
g_osdPTexImage = OpenSubdiv::OsdPTexture::Create(ptexColor, 0 /*targetmemory*/);
ptexColor->release();
if (g_ptexDisplacementFile) {
PtexTexture *ptexDisplacement = PtexTexture::open(g_ptexDisplacementFile, ptexError, true);
g_osdPTexDisplacement = OpenSubdiv::OsdPTexture::Create(ptexDisplacement, 0);
ptexDisplacement->release();
}
if (g_ptexOcclusionFile) {
PtexTexture *ptexOcclusion = PtexTexture::open(g_ptexOcclusionFile, ptexError, true);
g_osdPTexOcclusion = OpenSubdiv::OsdPTexture::Create(ptexOcclusion, 0);
ptexOcclusion->release();
}
// bind index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_indexBuffer);
g_numIndices = indices.size();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*g_numIndices, &(indices[0]), GL_STATIC_DRAW);
updateGeom();
linkProgram();
linkDebugProgram();
}
//------------------------------------------------------------------------------
void
drawNormals() {
float * data=0;
int datasize = g_osdmesh->GetTotalVertices() * g_vertexBuffer->GetNumElements();
data = new float[datasize];
glBindBuffer(GL_ARRAY_BUFFER, g_vertexBuffer->GetGpuBuffer());
glGetBufferSubData(GL_ARRAY_BUFFER,0,datasize*sizeof(float),data);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_LIGHTING);
glColor3f(0.0f, 0.0f, 0.5f);
glBegin(GL_LINES);
int start = g_osdmesh->GetFarMesh()->GetSubdivision()->GetFirstVertexOffset(g_level) *
g_vertexBuffer->GetNumElements();
for (int i=start; i<datasize; i+=6) {
glVertex3f( data[i ],
data[i+1],
data[i+2] );
float n[3] = { data[i+3], data[i+4], data[i+5] };
normalize(n);
glVertex3f( data[i ]+n[0]*0.2f,
data[i+1]+n[1]*0.2f,
data[i+2]+n[2]*0.2f );
}
glEnd();
delete [] data;
}
//------------------------------------------------------------------------------
void
drawPtexLayout(int page) {
glUseProgram(g_debugProgram);
GLint width, height, depth;
glGetTexLevelParameteriv(GL_TEXTURE_2D_ARRAY, 0, GL_TEXTURE_WIDTH, &width);
glGetTexLevelParameteriv(GL_TEXTURE_2D_ARRAY, 0, GL_TEXTURE_HEIGHT, &height);
glGetTexLevelParameteriv(GL_TEXTURE_2D_ARRAY, 0, GL_TEXTURE_DEPTH, &depth);
GLint pageUniform = glGetUniformLocation(g_debugProgram, "ptexDebugPage");
glProgramUniform1i(g_debugProgram, pageUniform, page);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(0, 0, 0);
glVertex3f(0, 1, 0);
glVertex3f(1, 0, 0);
glVertex3f(1, 1, 0);
glEnd();
glUseProgram(0);
drawFmtString(g_width/2, g_height - 10, "Size = %dx%d, Page = %d/%d", width, height, page, depth);
}
//------------------------------------------------------------------------------
void
display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, g_width, g_height);
double aspect = g_width/(double)g_height;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, aspect, g_size*0.001f, g_size+g_dolly);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(-g_pan[0], -g_pan[1], -g_dolly);
glRotatef(g_rotate[1], 1, 0, 0);
glRotatef(g_rotate[0], 0, 1, 0);
glTranslatef(-g_center[0], -g_center[1], -g_center[2]);
glUseProgram(g_program);
{
// shader uniform setting
GLint position = glGetUniformLocation(g_program, "lightSource[0].position");
GLint ambient = glGetUniformLocation(g_program, "lightSource[0].ambient");
GLint diffuse = glGetUniformLocation(g_program, "lightSource[0].diffuse");
GLint specular = glGetUniformLocation(g_program, "lightSource[0].specular");
glProgramUniform4f(g_program, position, 0, 0.2f, 1, 0);
glProgramUniform4f(g_program, ambient, 0.4f, 0.4f, 0.4f, 1.0f);
glProgramUniform4f(g_program, diffuse, 0.3f, 0.3f, 0.3f, 1.0f);
glProgramUniform4f(g_program, specular, 0.2f, 0.2f, 0.2f, 1.0f);
GLint otcMatrix = glGetUniformLocation(g_program, "objectToClipMatrix");
GLint oteMatrix = glGetUniformLocation(g_program, "objectToEyeMatrix");
GLfloat modelView[16], proj[16], mvp[16];
glGetFloatv(GL_MODELVIEW_MATRIX, modelView);
glGetFloatv(GL_PROJECTION_MATRIX, proj);
multMatrix(mvp, modelView, proj);
glProgramUniformMatrix4fv(g_program, otcMatrix, 1, false, mvp);
glProgramUniformMatrix4fv(g_program, oteMatrix, 1, false, modelView);
}
GLuint bVertex = g_vertexBuffer->GetGpuBuffer();
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, bVertex);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, 0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, (float*)12);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_indexBuffer);
glPolygonMode(GL_FRONT_AND_BACK, g_wire==0 ? GL_LINE : GL_FILL);
// glPatchParameteri(GL_PATCH_VERTICES, 4);
// glDrawElements(GL_PATCHES, g_numIndices, GL_UNSIGNED_INT, 0);
glDrawElements(GL_LINES_ADJACENCY, g_numIndices, GL_UNSIGNED_INT, 0);
glUseProgram(0);
if (g_drawNormals)
drawNormals();
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
if (g_ptexDebug)
drawPtexLayout(g_ptexDebug-1);
glColor3f(1, 1, 1);
drawFmtString(10, 10, "LEVEL = %d", g_level);
drawFmtString(10, 30, "# of Vertices = %d", g_osdmesh->GetFarMesh()->GetNumVertices());
drawFmtString(10, 50, "KERNEL = %s", getKernelName(g_kernel));
drawFmtString(10, 70, "CPU TIME = %.3f ms", g_cpuTime);
drawFmtString(10, 90, "GPU TIME = %.3f ms", g_gpuTime);
g_fpsTimer.Stop();
drawFmtString(10, 110, "FPS = %3.1f", 1.0/g_fpsTimer.GetElapsed());
g_fpsTimer.Start();
drawFmtString(10, 130, "SUBDIVISION = %s", g_scheme==0 ? "CATMARK" : "BILINEAR");
drawString(10, g_height-10, "a: ambient occlusion on/off");
drawString(10, g_height-30, "c: color on/off");
drawString(10, g_height-50, "d: displacement on/off");
drawString(10, g_height-70, "e: show normal vector");
drawString(10, g_height-90, "f: fit frame");
drawString(10, g_height-110, "w: toggle wireframe");
drawString(10, g_height-130, "m: toggle vertex moving");
drawString(10, g_height-150, "s: bilinear / catmark");
drawString(10, g_height-170, "1-7: subdivision level");
glFinish();
glutSwapBuffers();
}
//------------------------------------------------------------------------------
void mouse(int button, int state, int x, int y) {
g_prev_x = float(x);
g_prev_y = float(y);
g_mbutton[button] = !state;
}
//------------------------------------------------------------------------------
void motion(int x, int y) {
if (g_mbutton[0] && !g_mbutton[1] && !g_mbutton[2]) {
// orbit
g_rotate[0] += x - g_prev_x;
g_rotate[1] += y - g_prev_y;
} else if (!g_mbutton[0] && g_mbutton[1] && !g_mbutton[2]) {
// pan
g_pan[0] -= g_dolly*(x - g_prev_x)/g_width;
g_pan[1] += g_dolly*(y - g_prev_y)/g_height;
} else if (g_mbutton[0] && g_mbutton[1] && !g_mbutton[2]) {
// dolly
g_dolly -= g_dolly*0.01f*(x - g_prev_x);
if(g_dolly <= 0.01) g_dolly = 0.01f;
}
g_prev_x = float(x);
g_prev_y = float(y);
}
//------------------------------------------------------------------------------
void quit() {
if(g_osdmesh)
delete g_osdmesh;
if (g_vertexBuffer)
delete g_vertexBuffer;
#ifdef OPENSUBDIV_HAS_CUDA
cudaDeviceReset();
#endif
exit(0);
}
//------------------------------------------------------------------------------
void kernelMenu(int k) {
g_kernel = k;
createOsdMesh(g_level, g_kernel);
}
//------------------------------------------------------------------------------
void
levelMenu(int l) {
g_level = l;
createOsdMesh(g_level, g_kernel);
}
//------------------------------------------------------------------------------
void
schemeMenu(int s) {
g_scheme = s;
createOsdMesh(g_level, g_kernel);
}
//------------------------------------------------------------------------------
void
menu(int m) {
// top menu
}
//------------------------------------------------------------------------------
void
keyboard(unsigned char key, int x, int y) {
switch (key) {
case 'q': quit();
case 'w': g_wire = (g_wire+1)%2; break;
case 'e': g_drawNormals = (g_drawNormals+1)%2; break;
case 'f': fitFrame(); break;
case 'a': if (g_osdPTexOcclusion) g_occlusion = !g_occlusion; linkProgram(); break;
case 'd': if (g_osdPTexDisplacement) g_displacement = !g_displacement; linkProgram();break;
case 'c': g_color = !g_color; linkProgram(); break;
case 's': schemeMenu(!g_scheme); break;
case 'm': g_moveScale = 1.0f - g_moveScale; break;
case 'p': g_ptexDebug++; break;
case 'o': g_ptexDebug = std::max(0, g_ptexDebug-1); break;
case 'g': g_gutterWidth = (g_gutterWidth+1)%8; createOsdMesh(g_level, g_kernel); break;
case 'h': g_gutterDebug = !g_gutterDebug; createOsdMesh(g_level, g_kernel); break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': levelMenu(key-'0'); break;
}
}
//------------------------------------------------------------------------------
void
idle() {
g_frame++;
updateGeom();
glutPostRedisplay();
if(g_repeatCount != 0 && g_frame >= g_repeatCount)
quit();
}
//------------------------------------------------------------------------------
void
initGL() {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glEnable(GL_LIGHT0);
glColor3f(1, 1, 1);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
GLfloat color[4] = {1, 1, 1, 1};
GLfloat position[4] = {5, 5, 10, 1};
GLfloat ambient[4] = {0.9f, 0.9f, 0.9f, 1.0f};
GLfloat diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat shininess = 25.0;
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &shininess);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
}
//------------------------------------------------------------------------------
int main(int argc, char ** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA |GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(1024, 1024);
glutCreateWindow("OpenSubdiv ptexViewer");
int lmenu = glutCreateMenu(levelMenu);
for(int i = 1; i < 8; ++i){
char level[16];
sprintf(level, "Level %d\n", i);
glutAddMenuEntry(level, i);
}
int smenu = glutCreateMenu(schemeMenu);
glutAddMenuEntry("Catmark", 0);
glutAddMenuEntry("Bilinear", 1);
// Register Osd compute kernels
OpenSubdiv::OsdCpuKernelDispatcher::Register();
OpenSubdiv::OsdGlslKernelDispatcher::Register();
#if OPENSUBDIV_HAS_OPENCL
OpenSubdiv::OsdClKernelDispatcher::Register();
#endif
#if OPENSUBDIV_HAS_CUDA
OpenSubdiv::OsdCudaKernelDispatcher::Register();
// Note: This function randomly crashes with linux 5.0-dev driver.
// cudaGetDeviceProperties overrun stack..?
cudaGLSetGLDevice( cutGetMaxGflopsDeviceId() );
#endif
int kmenu = glutCreateMenu(kernelMenu);
int nKernels = OpenSubdiv::OsdKernelDispatcher::kMAX;
for(int i = 0; i < nKernels; ++i)
if(OpenSubdiv::OsdKernelDispatcher::HasKernelType(
OpenSubdiv::OsdKernelDispatcher::KernelType(i)))
glutAddMenuEntry(getKernelName(i), i);
glutCreateMenu(menu);
glutAddSubMenu("Level", lmenu);
glutAddSubMenu("Scheme", smenu);
glutAddSubMenu("Kernel", kmenu);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutMotionFunc(motion);
glewInit();
initGL();
for (int i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-d"))
g_level = atoi(argv[++i]);
else if (!strcmp(argv[i], "-c"))
g_repeatCount = atoi(argv[++i]);
else if (g_ptexColorFile == NULL)
g_ptexColorFile = argv[i];
else if (g_ptexDisplacementFile == NULL)
g_ptexDisplacementFile = argv[i];
else if (g_ptexOcclusionFile == NULL)
g_ptexOcclusionFile = argv[i];
}
if (g_ptexColorFile == NULL) {
printf("Usage: %s <color.ptx> [<displacement.ptx>] [<occlusion.ptx>] \n", argv[0]);
return 1;
}
glGenBuffers(1, &g_indexBuffer);
createOsdMesh(g_level, g_kernel);
fitFrame();
glutIdleFunc(idle);
glutMainLoop();
quit();
}
//------------------------------------------------------------------------------

View File

@ -65,4 +65,4 @@ add_subdirectory(osd)
install( FILES version.h install( FILES version.h
DESTINATION include/ DESTINATION include/
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ ) PERMISSIONS OWNER_READ GROUP_READ WORLD_READ )

View File

@ -63,8 +63,10 @@ set(H_FILES
meshFactory.h meshFactory.h
mesh.h mesh.h
subdivisionTables.h subdivisionTables.h
table.h
vertexEditTables.h
) )
install( FILES ${H_FILES} install( FILES ${H_FILES}
DESTINATION include/far DESTINATION include/far
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ ) PERMISSIONS OWNER_READ GROUP_READ WORLD_READ )

View File

@ -83,14 +83,14 @@ public:
// Memory required to store the indexing tables // Memory required to store the indexing tables
virtual int GetMemoryUsed() const; virtual int GetMemoryUsed() const;
// Compute the positions of refined vertices using the specified kernels
virtual void Refine( int level, void * data=0 ) const;
// Table accessors
typename FarSubdivisionTables<T,U>::template Table<unsigned int> const & Get_F_IT( ) const { return _F_IT; }
typename FarSubdivisionTables<T,U>::template Table<int> const & Get_F_ITa( ) const { return _F_ITa; } // Compute the positions of refined vertices using the specified kernels
virtual void Apply( int level, void * data=0 ) const;
// Table accessors
FarTable<unsigned int> const & Get_F_IT( ) const { return _F_IT; }
FarTable<int> const & Get_F_ITa( ) const { return _F_ITa; }
// Returns the number of indexing tables needed to represent this particular // Returns the number of indexing tables needed to represent this particular
// subdivision scheme. // subdivision scheme.
@ -100,7 +100,7 @@ private:
friend class FarMeshFactory<T,U>; friend class FarMeshFactory<T,U>;
friend class FarDispatcher<T,U>; friend class FarDispatcher<T,U>;
// Constructor : build level table at depth 'level' // Constructor : build level table at depth 'level'
FarBilinearSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int level ); FarBilinearSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int level );
@ -112,12 +112,12 @@ private:
// Compute-kernel applied to vertices resulting from the refinement of a vertex // 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; void computeVertexPoints(int offset, int level, int start, int end, void * clientdata) const;
private: private:
typename FarSubdivisionTables<T,U>::template Table<int> _F_ITa; FarTable<int> _F_ITa;
typename FarSubdivisionTables<T,U>::template Table<unsigned int> _F_IT; FarTable<unsigned int> _F_IT;
}; };
template <class T, class U> int template <class T, class U> int
@ -137,12 +137,12 @@ FarBilinearSubdivisionTables<T,U>::GetMemoryUsed() const {
// _F_ITa[1] : valence of the face // _F_ITa[1] : valence of the face
// //
// _E_ITa[0] : index of the org / dest vertices of the parent edge // _E_ITa[0] : index of the org / dest vertices of the parent edge
// _E_ITa[1] : // _E_ITa[1] :
// //
// _V_ITa[0] : index of the parent vertex // _V_ITa[0] : index of the parent vertex
// //
template <class T, class U> template <class T, class U>
FarBilinearSubdivisionTables<T,U>::FarBilinearSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int maxlevel ) : FarBilinearSubdivisionTables<T,U>::FarBilinearSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int maxlevel ) :
FarSubdivisionTables<T,U>(mesh, maxlevel), FarSubdivisionTables<T,U>(mesh, maxlevel),
_F_ITa(maxlevel+1), _F_ITa(maxlevel+1),
_F_IT(maxlevel+1) _F_IT(maxlevel+1)
@ -160,12 +160,12 @@ FarBilinearSubdivisionTables<T,U>::FarBilinearSubdivisionTables( FarMeshFactory<
for (int level=1; level<=maxlevel; ++level) { for (int level=1; level<=maxlevel; ++level) {
// pointer to the first vertex corresponding to this level // pointer to the first vertex corresponding to this level
this->_vertsOffsets[level] = factory._vertVertIdx[level-1] + this->_vertsOffsets[level] = factory._vertVertIdx[level-1] +
factory._vertVertsList[level-1].size(); (int)factory._vertVertsList[level-1].size();
typename FarSubdivisionTables<T,U>::VertexKernelBatch * batch = & (this->_batches[level-1]); typename FarSubdivisionTables<T,U>::VertexKernelBatch * batch = & (this->_batches[level-1]);
// Face vertices // Face vertices
// "For each vertex, gather all the vertices from the parent face." // "For each vertex, gather all the vertices from the parent face."
int offset = 0; int offset = 0;
int * F_ITa = this->_F_ITa[level-1]; int * F_ITa = this->_F_ITa[level-1];
@ -190,10 +190,10 @@ FarBilinearSubdivisionTables<T,U>::FarBilinearSubdivisionTables( FarMeshFactory<
_F_ITa.SetMarker(level, &F_ITa[2*batch->kernelF]); _F_ITa.SetMarker(level, &F_ITa[2*batch->kernelF]);
_F_IT.SetMarker(level, &F_IT[offset]); _F_IT.SetMarker(level, &F_IT[offset]);
// Edge vertices // Edge vertices
// "Average the end-points of the parent edge" // "Average the end-points of the parent edge"
unsigned int * E_IT = this->_E_IT[level-1]; int * E_IT = this->_E_IT[level-1];
batch->kernelE = (int)factory._edgeVertsList[level].size(); batch->kernelE = (int)factory._edgeVertsList[level].size();
for (int i=0; i < batch->kernelE; ++i) { for (int i=0; i < batch->kernelE; ++i) {
@ -208,8 +208,8 @@ FarBilinearSubdivisionTables<T,U>::FarBilinearSubdivisionTables( FarMeshFactory<
} }
this->_E_IT.SetMarker(level, &E_IT[2*batch->kernelE]); this->_E_IT.SetMarker(level, &E_IT[2*batch->kernelE]);
// Vertex vertices // Vertex vertices
// "Pass down the parent vertex" // "Pass down the parent vertex"
offset = 0; offset = 0;
@ -230,10 +230,10 @@ FarBilinearSubdivisionTables<T,U>::FarBilinearSubdivisionTables( FarMeshFactory<
} }
template <class T, class U> void template <class T, class U> void
FarBilinearSubdivisionTables<T,U>::Refine( int level, void * clientdata ) const { FarBilinearSubdivisionTables<T,U>::Apply( int level, void * clientdata ) const {
assert(this->_mesh and level>0); assert(this->_mesh and level>0);
typename FarSubdivisionTables<T,U>::VertexKernelBatch const * batch = & (this->_batches[level-1]); typename FarSubdivisionTables<T,U>::VertexKernelBatch const * batch = & (this->_batches[level-1]);
FarDispatcher<T,U> const * dispatch = this->_mesh->GetDispatcher(); FarDispatcher<T,U> const * dispatch = this->_mesh->GetDispatcher();
@ -256,11 +256,11 @@ FarBilinearSubdivisionTables<T,U>::Refine( int level, void * clientdata ) const
// Face-vertices compute Kernel - completely re-entrant // Face-vertices compute Kernel - completely re-entrant
// //
template <class T, class U> void template <class T, class U> void
FarBilinearSubdivisionTables<T,U>::computeFacePoints( int offset, int level, int start, int end, void * clientdata ) const { FarBilinearSubdivisionTables<T,U>::computeFacePoints( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh); assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0), U * vsrc = &this->_mesh->GetVertices().at(0),
* vdst = vsrc + offset + start; * vdst = vsrc + offset + start;
@ -268,10 +268,10 @@ FarBilinearSubdivisionTables<T,U>::computeFacePoints( int offset, int level, int
const unsigned int * F_IT = _F_IT[level-1]; const unsigned int * F_IT = _F_IT[level-1];
for (int i=start; i<end; ++i, ++vdst ) { for (int i=start; i<end; ++i, ++vdst ) {
vdst->Clear(clientdata); vdst->Clear(clientdata);
int h = F_ITa[2*i ], int h = F_ITa[2*i ],
n = F_ITa[2*i+1]; n = F_ITa[2*i+1];
float weight = 1.0f/n; float weight = 1.0f/n;
@ -286,18 +286,18 @@ FarBilinearSubdivisionTables<T,U>::computeFacePoints( int offset, int level, int
// Edge-vertices compute Kernel - completely re-entrant // Edge-vertices compute Kernel - completely re-entrant
// //
template <class T, class U> void template <class T, class U> void
FarBilinearSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const { FarBilinearSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh); assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0), U * vsrc = &this->_mesh->GetVertices().at(0),
* vdst = vsrc + offset + start; * vdst = vsrc + offset + start;
const unsigned int * E_IT = this->_E_IT[level-1]; const int * E_IT = this->_E_IT[level-1];
for (int i=start; i<end; ++i, ++vdst ) { for (int i=start; i<end; ++i, ++vdst ) {
vdst->Clear(clientdata); vdst->Clear(clientdata);
int eidx0 = E_IT[2*i+0], int eidx0 = E_IT[2*i+0],
@ -315,11 +315,11 @@ FarBilinearSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, in
// Vertex-vertices compute Kernel - completely re-entrant // Vertex-vertices compute Kernel - completely re-entrant
// //
template <class T, class U> void template <class T, class U> void
FarBilinearSubdivisionTables<T,U>::computeVertexPoints( int offset, int level, int start, int end, void * clientdata ) const { FarBilinearSubdivisionTables<T,U>::computeVertexPoints( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh); assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0), U * vsrc = &this->_mesh->GetVertices().at(0),
* vdst = vsrc + offset + start; * vdst = vsrc + offset + start;
@ -329,7 +329,7 @@ FarBilinearSubdivisionTables<T,U>::computeVertexPoints( int offset, int level, i
vdst->Clear(clientdata); vdst->Clear(clientdata);
int p=V_ITa[i]; // index of the parent vertex int p=V_ITa[i]; // index of the parent vertex
vdst->AddWithWeight( vsrc[p], 1.0f, clientdata ); vdst->AddWithWeight( vsrc[p], 1.0f, clientdata );
vdst->AddVaryingWithWeight( vsrc[p], 1.0f, clientdata ); vdst->AddVaryingWithWeight( vsrc[p], 1.0f, clientdata );

View File

@ -83,14 +83,14 @@ public:
// Memory required to store the indexing tables // Memory required to store the indexing tables
virtual int GetMemoryUsed() const; virtual int GetMemoryUsed() const;
// Compute the positions of refined vertices using the specified kernels
virtual void Refine( int level, void * data=0 ) const;
// Table accessors
typename FarSubdivisionTables<T,U>::template Table<unsigned int> const & Get_F_IT( ) const { return _F_IT; }
typename FarSubdivisionTables<T,U>::template Table<int> const & Get_F_ITa( ) const { return _F_ITa; } // Compute the positions of refined vertices using the specified kernels
virtual void Apply( int level, void * data=0 ) const;
// Table accessors
FarTable<unsigned int> const & Get_F_IT( ) const { return _F_IT; }
FarTable<int> const & Get_F_ITa( ) const { return _F_ITa; }
// Returns the number of indexing tables needed to represent this particular // Returns the number of indexing tables needed to represent this particular
// subdivision scheme. // subdivision scheme.
@ -100,7 +100,7 @@ private:
friend class FarMeshFactory<T,U>; friend class FarMeshFactory<T,U>;
friend class FarDispatcher<T,U>; friend class FarDispatcher<T,U>;
// Constructor : build level table at depth 'level' // Constructor : build level table at depth 'level'
FarCatmarkSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int level ); FarCatmarkSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int level );
@ -113,15 +113,15 @@ private:
// Compute-kernel applied to vertices resulting from the refinement of a vertex // Compute-kernel applied to vertices resulting from the refinement of a vertex
// Kernel "A" Handles the k_Smooth and k_Dart rules // Kernel "A" Handles the k_Smooth and k_Dart rules
void computeVertexPointsA(int offset, bool pass, int level, int start, int end, void * clientdata) const; void computeVertexPointsA(int offset, bool pass, int level, int start, int end, void * clientdata) const;
// Compute-kernel applied to vertices resulting from the refinement of a vertex // Compute-kernel applied to vertices resulting from the refinement of a vertex
// Kernel "B" Handles the k_Crease and k_Corner rules // Kernel "B" Handles the k_Crease and k_Corner rules
void computeVertexPointsB(int offset, int level, int start, int end, void * clientdata) const; void computeVertexPointsB(int offset, int level, int start, int end, void * clientdata) const;
private: private:
typename FarSubdivisionTables<T,U>::template Table<int> _F_ITa; FarTable<int> _F_ITa;
typename FarSubdivisionTables<T,U>::template Table<unsigned int> _F_IT; FarTable<unsigned int> _F_IT;
}; };
template <class T, class U> int template <class T, class U> int
@ -139,7 +139,7 @@ FarCatmarkSubdivisionTables<T,U>::GetMemoryUsed() const {
// _F_ITa[1] : valence of the face // _F_ITa[1] : valence of the face
// //
// _E_ITa[0] : index of the org / dest vertices of the parent edge // _E_ITa[0] : index of the org / dest vertices of the parent edge
// _E_ITa[1] : // _E_ITa[1] :
// _E_ITa[2] : index of vertices refined from the faces left / right // _E_ITa[2] : index of vertices refined from the faces left / right
// _E_ITa[3] : of the parent edge // _E_ITa[3] : of the parent edge
// //
@ -150,7 +150,7 @@ FarCatmarkSubdivisionTables<T,U>::GetMemoryUsed() const {
// _V_ITa[4] : index of adjacent edge 1 (k_Crease rule) // _V_ITa[4] : index of adjacent edge 1 (k_Crease rule)
// //
template <class T, class U> template <class T, class U>
FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int maxlevel ) : FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int maxlevel ) :
FarSubdivisionTables<T,U>(mesh, maxlevel), FarSubdivisionTables<T,U>(mesh, maxlevel),
_F_ITa(maxlevel+1), _F_ITa(maxlevel+1),
_F_IT(maxlevel+1) _F_IT(maxlevel+1)
@ -171,12 +171,12 @@ FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,
for (int level=1; level<=maxlevel; ++level) { for (int level=1; level<=maxlevel; ++level) {
// pointer to the first vertex corresponding to this level // pointer to the first vertex corresponding to this level
this->_vertsOffsets[level] = factory._vertVertIdx[level-1] + this->_vertsOffsets[level] = factory._vertVertIdx[level-1] +
factory._vertVertsList[level-1].size(); (int)factory._vertVertsList[level-1].size();
typename FarSubdivisionTables<T,U>::VertexKernelBatch * batch = & (this->_batches[level-1]); typename FarSubdivisionTables<T,U>::VertexKernelBatch * batch = & (this->_batches[level-1]);
// Face vertices // Face vertices
// "For each vertex, gather all the vertices from the parent face." // "For each vertex, gather all the vertices from the parent face."
int offset = 0; int offset = 0;
int * F_ITa = this->_F_ITa[level-1]; int * F_ITa = this->_F_ITa[level-1];
@ -201,17 +201,17 @@ FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,
_F_ITa.SetMarker(level, &F_ITa[2*batch->kernelF]); _F_ITa.SetMarker(level, &F_ITa[2*batch->kernelF]);
_F_IT.SetMarker(level, &F_IT[offset]); _F_IT.SetMarker(level, &F_IT[offset]);
// Edge vertices // Edge vertices
// Triangular interpolation mode : // Triangular interpolation mode :
// see "smoothtriangle" tag introduced in prman 3.9 and HbrCatmarkSubdivision<T> // see "smoothtriangle" tag introduced in prman 3.9 and HbrCatmarkSubdivision<T>
typename HbrCatmarkSubdivision<T>::TriangleSubdivision triangleMethod = typename HbrCatmarkSubdivision<T>::TriangleSubdivision triangleMethod =
dynamic_cast<HbrCatmarkSubdivision<T> *>(factory._hbrMesh->GetSubdivision())->GetTriangleSubdivisionMethod(); dynamic_cast<HbrCatmarkSubdivision<T> *>(factory._hbrMesh->GetSubdivision())->GetTriangleSubdivisionMethod();
// "For each vertex, gather the 2 vertices from the parent edege and the // "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. // 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." // Adjust if edge has a crease or is on a boundary."
unsigned int * E_IT = this->_E_IT[level-1]; int * E_IT = this->_E_IT[level-1];
float * E_W = this->_E_W[level-1]; float * E_W = this->_E_W[level-1];
batch->kernelE = (int)factory._edgeVertsList[level].size(); batch->kernelE = (int)factory._edgeVertsList[level].size();
for (int i=0; i < batch->kernelE; ++i) { for (int i=0; i < batch->kernelE; ++i) {
@ -257,10 +257,10 @@ FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,
} }
this->_E_IT.SetMarker(level, &E_IT[4*batch->kernelE]); this->_E_IT.SetMarker(level, &E_IT[4*batch->kernelE]);
this->_E_W.SetMarker(level, &E_W[2*batch->kernelE]); this->_E_W.SetMarker(level, &E_W[2*batch->kernelE]);
// Vertex vertices
batch->InitVertexKernels( factory._vertVertsList[level].size(), 0 ); // Vertex vertices
batch->InitVertexKernels( (int)factory._vertVertsList[level].size(), 0 );
offset = 0; offset = 0;
int * V_ITa = this->_V_ITa[level-1]; int * V_ITa = this->_V_ITa[level-1];
@ -274,19 +274,19 @@ FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,
assert(v and pv); assert(v and pv);
// Look at HbrCatmarkSubdivision<T>::Subdivide for more details about // Look at HbrCatmarkSubdivision<T>::Subdivide for more details about
// the multi-pass interpolation // the multi-pass interpolation
int masks[2], npasses; int masks[2], npasses;
float weights[2]; float weights[2];
masks[0] = pv->GetMask(false); masks[0] = pv->GetMask(false);
masks[1] = pv->GetMask(true); masks[1] = pv->GetMask(true);
// If the masks are identical, only a single pass is necessary. If the // If the masks are identical, only a single pass is necessary. If the
// vertex is transitionning to another rule, two passes are necessary, // vertex is transitioning to another rule, two passes are necessary,
// except when transitionning from k_Dart to k_Smooth : the same // except when transitioning from k_Dart to k_Smooth : the same
// compute kernel is applied twice. Combining this special case allows // compute kernel is applied twice. Combining this special case allows
// to batch the compute kernels into fewer calls. // to batch the compute kernels into fewer calls.
if (masks[0] != masks[1] and ( if (masks[0] != masks[1] and (
not (masks[0]==HbrVertex<T>::k_Smooth and not (masks[0]==HbrVertex<T>::k_Smooth and
masks[1]==HbrVertex<T>::k_Dart))) { masks[1]==HbrVertex<T>::k_Dart))) {
weights[1] = pv->GetFractionalMask(); weights[1] = pv->GetFractionalMask();
weights[0] = 1.0f - weights[1]; weights[0] = 1.0f - weights[1];
@ -315,11 +315,11 @@ FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,
V_ITa[5*i+1]++; V_ITa[5*i+1]++;
V_IT[offset++] = remap[ e->GetDestVertex()->GetID() ]; V_IT[offset++] = remap[ e->GetDestVertex()->GetID() ];
V_IT[offset++] = remap[ e->GetLeftFace()->Subdivide()->GetID() ]; V_IT[offset++] = remap[ e->GetLeftFace()->Subdivide()->GetID() ];
e = e->GetPrev()->GetOpposite(); e = e->GetPrev()->GetOpposite();
if (e==start) break; if (e==start) break;
} }
break; break;
@ -350,7 +350,7 @@ FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,
V_ITa[5*i+3] = remap[op.eidx[0]]; V_ITa[5*i+3] = remap[op.eidx[0]];
V_ITa[5*i+4] = remap[op.eidx[1]]; V_ITa[5*i+4] = remap[op.eidx[1]];
break; break;
} }
case HbrVertex<T>::k_Corner : case HbrVertex<T>::k_Corner :
// in the case of a k_Crease / k_Corner pass combination, we // 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 // need to set the valence to -1 to tell the "B" Kernel to
@ -363,7 +363,7 @@ FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,
if (rank>7) if (rank>7)
// the k_Corner and k_Crease single-pass cases apply a weight of 1.0 // the k_Corner and k_Crease single-pass cases apply a weight of 1.0
// but this value is inverted in the kernel // but this value is inverted in the kernel
V_W[i] = 0.0; V_W[i] = 0.0;
else else
@ -382,10 +382,10 @@ FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,
} }
template <class T, class U> void template <class T, class U> void
FarCatmarkSubdivisionTables<T,U>::Refine( int level, void * clientdata ) const { FarCatmarkSubdivisionTables<T,U>::Apply( int level, void * clientdata ) const {
assert(this->_mesh and level>0); assert(this->_mesh and level>0);
typename FarSubdivisionTables<T,U>::VertexKernelBatch const * batch = & (this->_batches[level-1]); typename FarSubdivisionTables<T,U>::VertexKernelBatch const * batch = & (this->_batches[level-1]);
FarDispatcher<T,U> const * dispatch = this->_mesh->GetDispatcher(); FarDispatcher<T,U> const * dispatch = this->_mesh->GetDispatcher();
@ -412,11 +412,11 @@ FarCatmarkSubdivisionTables<T,U>::Refine( int level, void * clientdata ) const {
// Face-vertices compute Kernel - completely re-entrant // Face-vertices compute Kernel - completely re-entrant
// //
template <class T, class U> void template <class T, class U> void
FarCatmarkSubdivisionTables<T,U>::computeFacePoints( int offset, int level, int start, int end, void * clientdata ) const { FarCatmarkSubdivisionTables<T,U>::computeFacePoints( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh); assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0), U * vsrc = &this->_mesh->GetVertices().at(0),
* vdst = vsrc + offset + start; * vdst = vsrc + offset + start;
@ -424,10 +424,10 @@ FarCatmarkSubdivisionTables<T,U>::computeFacePoints( int offset, int level, int
const unsigned int * F_IT = _F_IT[level-1]; const unsigned int * F_IT = _F_IT[level-1];
for (int i=start; i<end; ++i, ++vdst ) { for (int i=start; i<end; ++i, ++vdst ) {
vdst->Clear(clientdata); vdst->Clear(clientdata);
int h = F_ITa[2*i ], int h = F_ITa[2*i ],
n = F_ITa[2*i+1]; n = F_ITa[2*i+1];
float weight = 1.0f/n; float weight = 1.0f/n;
@ -442,36 +442,36 @@ FarCatmarkSubdivisionTables<T,U>::computeFacePoints( int offset, int level, int
// Edge-vertices compute Kernel - completely re-entrant // Edge-vertices compute Kernel - completely re-entrant
// //
template <class T, class U> void template <class T, class U> void
FarCatmarkSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const { FarCatmarkSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh); assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0), U * vsrc = &this->_mesh->GetVertices().at(0),
* vdst = vsrc + offset + start; * vdst = vsrc + offset + start;
const unsigned int * E_IT = this->_E_IT[level-1]; const int * E_IT = this->_E_IT[level-1];
const float * E_W = this->_E_W[level-1]; const float * E_W = this->_E_W[level-1];
for (int i=start; i<end; ++i, ++vdst ) { for (int i=start; i<end; ++i, ++vdst ) {
vdst->Clear(clientdata); vdst->Clear(clientdata);
int eidx0 = E_IT[4*i+0], int eidx0 = E_IT[4*i+0],
eidx1 = E_IT[4*i+1], eidx1 = E_IT[4*i+1],
eidx2 = E_IT[4*i+2], eidx2 = E_IT[4*i+2],
eidx3 = E_IT[4*i+3]; eidx3 = E_IT[4*i+3];
float vertWeight = E_W[i*2+0]; float vertWeight = E_W[i*2+0];
// Fully sharp edge : vertWeight = 0.5f // Fully sharp edge : vertWeight = 0.5f
vdst->AddWithWeight( vsrc[eidx0], vertWeight, clientdata ); vdst->AddWithWeight( vsrc[eidx0], vertWeight, clientdata );
vdst->AddWithWeight( vsrc[eidx1], vertWeight, clientdata ); vdst->AddWithWeight( vsrc[eidx1], vertWeight, clientdata );
if (eidx2!=-1) { if (eidx2!=-1) {
// Apply fractional sharpness // Apply fractional sharpness
float faceWeight = E_W[i*2+1]; float faceWeight = E_W[i*2+1];
vdst->AddWithWeight( vsrc[eidx2], faceWeight, clientdata ); vdst->AddWithWeight( vsrc[eidx2], faceWeight, clientdata );
vdst->AddWithWeight( vsrc[eidx3], faceWeight, clientdata ); vdst->AddWithWeight( vsrc[eidx3], faceWeight, clientdata );
} }
@ -486,11 +486,11 @@ FarCatmarkSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int
// //
// multi-pass kernel handling k_Crease and k_Corner rules // multi-pass kernel handling k_Crease and k_Corner rules
template <class T, class U> void template <class T, class U> void
FarCatmarkSubdivisionTables<T,U>::computeVertexPointsA( int offset, bool pass, int level, int start, int end, void * clientdata ) const { FarCatmarkSubdivisionTables<T,U>::computeVertexPointsA( int offset, bool pass, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh); assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0), U * vsrc = &this->_mesh->GetVertices().at(0),
* vdst = vsrc + offset + start; * vdst = vsrc + offset + start;
@ -501,16 +501,16 @@ FarCatmarkSubdivisionTables<T,U>::computeVertexPointsA( int offset, bool pass, i
if (not pass) if (not pass)
vdst->Clear(clientdata); vdst->Clear(clientdata);
int n=V_ITa[5*i+1], // number of vertices in the _VO_IT array (valence) int n=V_ITa[5*i+1], // number of vertices in the _VO_IT array (valence)
p=V_ITa[5*i+2], // index of the parent vertex p=V_ITa[5*i+2], // index of the parent vertex
eidx0=V_ITa[5*i+3], // index of the first crease rule edge eidx0=V_ITa[5*i+3], // index of the first crease rule edge
eidx1=V_ITa[5*i+4]; // index of the second crease rule edge eidx1=V_ITa[5*i+4]; // index of the second crease rule edge
float weight = pass ? V_W[i] : 1.0f - V_W[i]; float weight = pass ? V_W[i] : 1.0f - V_W[i];
// In the case of fractional weight, the weight must be inverted since // In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the // the value is shared with the k_Smooth kernel (statistically the
// k_Smooth kernel runs much more often than this one) // k_Smooth kernel runs much more often than this one)
if (weight>0.0f and weight<1.0f and n>0) if (weight>0.0f and weight<1.0f and n>0)
weight=1.0f-weight; weight=1.0f-weight;
@ -531,11 +531,11 @@ FarCatmarkSubdivisionTables<T,U>::computeVertexPointsA( int offset, bool pass, i
} }
// multi-pass kernel handling k_Dart and k_Smooth rules // multi-pass kernel handling k_Dart and k_Smooth rules
template <class T, class U> void template <class T, class U> void
FarCatmarkSubdivisionTables<T,U>::computeVertexPointsB( int offset, int level, int start, int end, void * clientdata ) const { FarCatmarkSubdivisionTables<T,U>::computeVertexPointsB( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh); assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0), U * vsrc = &this->_mesh->GetVertices().at(0),
* vdst = vsrc + offset + start; * vdst = vsrc + offset + start;
@ -544,25 +544,25 @@ FarCatmarkSubdivisionTables<T,U>::computeVertexPointsB( int offset, int level, i
const float * V_W = this->_V_W[level-1]; const float * V_W = this->_V_W[level-1];
for (int i=start; i<end; ++i, ++vdst ) { for (int i=start; i<end; ++i, ++vdst ) {
vdst->Clear(clientdata); vdst->Clear(clientdata);
int h = V_ITa[5*i ], // offset of the vertices in the _V0_IT array int h = V_ITa[5*i ], // offset of the vertices in the _V0_IT array
n = V_ITa[5*i+1], // number of vertices in the _VO_IT array (valence) n = V_ITa[5*i+1], // number of vertices in the _VO_IT array (valence)
p = V_ITa[5*i+2]; // index of the parent vertex p = V_ITa[5*i+2]; // index of the parent vertex
float weight = V_W[i], float weight = V_W[i],
wp = 1.0f/(n*n), wp = 1.0f/(n*n),
wv = (n-2.0f)*n*wp; wv = (n-2.0f)*n*wp;
vdst->AddWithWeight( vsrc[p], weight * wv, clientdata ); vdst->AddWithWeight( vsrc[p], weight * wv, clientdata );
for (int j=0; j<n; ++j) { for (int j=0; j<n; ++j) {
vdst->AddWithWeight( vsrc[V_IT[h+j*2 ]], weight * wp, clientdata ); vdst->AddWithWeight( vsrc[V_IT[h+j*2 ]], weight * wp, clientdata );
vdst->AddWithWeight( vsrc[V_IT[h+j*2+1]], weight * wp, clientdata ); vdst->AddWithWeight( vsrc[V_IT[h+j*2+1]], weight * wp, clientdata );
} }
vdst->AddVaryingWithWeight( vsrc[p], 1.0f, clientdata ); vdst->AddVaryingWithWeight( vsrc[p], 1.0f, clientdata );
} }
} }
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION

View File

@ -64,13 +64,14 @@
#include "../far/bilinearSubdivisionTables.h" #include "../far/bilinearSubdivisionTables.h"
#include "../far/catmarkSubdivisionTables.h" #include "../far/catmarkSubdivisionTables.h"
#include "../far/loopSubdivisionTables.h" #include "../far/loopSubdivisionTables.h"
#include "../far/vertexEditTables.h"
namespace OpenSubdiv { namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION { namespace OPENSUBDIV_VERSION {
// Compute dispatcher : allows client code to customize parts or the entire // Compute dispatcher : allows client code to customize parts or the entire
// computation process. This pattern aims at hiding the logic specific to // computation process. This pattern aims at hiding the logic specific to
// the subdivision algorithms and expose a simplified access to minimalistic // the subdivision algorithms and expose a simplified access to minimalistic
// compute kernels. By default, meshes revert to a default dispatcher that // compute kernels. By default, meshes revert to a default dispatcher that
// implements single-threaded CPU kernels. // implements single-threaded CPU kernels.
// //
@ -87,10 +88,11 @@ protected:
friend class FarBilinearSubdivisionTables<T,U>; friend class FarBilinearSubdivisionTables<T,U>;
friend class FarCatmarkSubdivisionTables<T,U>; friend class FarCatmarkSubdivisionTables<T,U>;
friend class FarLoopSubdivisionTables<T,U>; friend class FarLoopSubdivisionTables<T,U>;
friend class FarVertexEditTables<T,U>;
friend class FarMesh<T,U>; friend class FarMesh<T,U>;
virtual void Refine(FarMesh<T,U> * mesh, int maxlevel, void * clientdata=0) const; virtual void Refine(FarMesh<T,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<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const;
@ -114,9 +116,11 @@ protected:
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<T,U> * mesh, int offset, bool pass, 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 ApplyVertexEdit(FarMesh<T,U> *mesh, int offset, int level, void * clientdata) const;
private: private:
friend class FarMeshFactory<T,U>; friend class FarMeshFactory<T,U>;
static FarDispatcher _DefaultDispatcher; static FarDispatcher _DefaultDispatcher;
}; };
@ -130,95 +134,108 @@ FarDispatcher<T,U>::Refine( FarMesh<T,U> * mesh, int maxlevel, void * data) cons
FarSubdivisionTables<T,U> const * tables = mesh->GetSubdivision(); FarSubdivisionTables<T,U> const * tables = mesh->GetSubdivision();
FarVertexEditTables<T,U> const * edits = mesh->GetVertexEdit();
if ( (maxlevel < 0) ) if ( (maxlevel < 0) )
maxlevel=tables->GetMaxLevel(); maxlevel=tables->GetMaxLevel();
else else
maxlevel = std::min(maxlevel, tables->GetMaxLevel()); maxlevel = std::min(maxlevel, tables->GetMaxLevel());
for (int i=1; i<maxlevel; ++i) for (int i=1; i<maxlevel; ++i) {
tables->Refine(i, data); tables->Apply(i, data);
if (edits)
edits->Apply(i, data);
}
} }
template <class T, class U> void 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 { FarDispatcher<T,U>::ApplyBilinearFaceVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarBilinearSubdivisionTables<T,U> const * subdivision = FarBilinearSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarBilinearSubdivisionTables<T,U> const *>(mesh->GetSubdivision()); dynamic_cast<FarBilinearSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
assert(subdivision); assert(subdivision);
subdivision->computeFacePoints(offset, level, start, end, clientdata); subdivision->computeFacePoints(offset, level, start, end, clientdata);
} }
template <class T, class U> void 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 { FarDispatcher<T,U>::ApplyBilinearEdgeVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarBilinearSubdivisionTables<T,U> const * subdivision = FarBilinearSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarBilinearSubdivisionTables<T,U> const *>(mesh->GetSubdivision()); dynamic_cast<FarBilinearSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
assert(subdivision); assert(subdivision);
subdivision->computeEdgePoints(offset, level, start, end, clientdata); subdivision->computeEdgePoints(offset, level, start, end, clientdata);
} }
template <class T, class U> void 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 { FarDispatcher<T,U>::ApplyBilinearVertexVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarBilinearSubdivisionTables<T,U> const * subdivision = FarBilinearSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarBilinearSubdivisionTables<T,U> const *>(mesh->GetSubdivision()); dynamic_cast<FarBilinearSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
assert(subdivision); assert(subdivision);
subdivision->computeVertexPoints(offset, level, start, end, clientdata); subdivision->computeVertexPoints(offset, level, start, end, clientdata);
} }
template <class T, class U> void 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 { FarDispatcher<T,U>::ApplyCatmarkFaceVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarCatmarkSubdivisionTables<T,U> const * subdivision = FarCatmarkSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarCatmarkSubdivisionTables<T,U> const *>(mesh->GetSubdivision()); dynamic_cast<FarCatmarkSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
assert(subdivision); assert(subdivision);
subdivision->computeFacePoints(offset, level, start, end, clientdata); subdivision->computeFacePoints(offset, level, start, end, clientdata);
} }
template <class T, class U> void 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 { FarDispatcher<T,U>::ApplyCatmarkEdgeVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarCatmarkSubdivisionTables<T,U> const * subdivision = FarCatmarkSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarCatmarkSubdivisionTables<T,U> const *>(mesh->GetSubdivision()); dynamic_cast<FarCatmarkSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
assert(subdivision); assert(subdivision);
subdivision->computeEdgePoints(offset, level, start, end, clientdata); subdivision->computeEdgePoints(offset, level, start, end, clientdata);
} }
template <class T, class U> void 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 { FarDispatcher<T,U>::ApplyCatmarkVertexVerticesKernelB(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarCatmarkSubdivisionTables<T,U> const * subdivision = FarCatmarkSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarCatmarkSubdivisionTables<T,U> const *>(mesh->GetSubdivision()); dynamic_cast<FarCatmarkSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
assert(subdivision); assert(subdivision);
subdivision->computeVertexPointsB(offset, level, start, end, clientdata); subdivision->computeVertexPointsB(offset, level, start, end, clientdata);
} }
template <class T, class U> void 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 { 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 = FarCatmarkSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarCatmarkSubdivisionTables<T,U> const *>(mesh->GetSubdivision()); dynamic_cast<FarCatmarkSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
assert(subdivision); assert(subdivision);
subdivision->computeVertexPointsA(offset, pass, level, start, end, clientdata); subdivision->computeVertexPointsA(offset, pass, level, start, end, clientdata);
} }
template <class T, class U> void 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 { FarDispatcher<T,U>::ApplyLoopEdgeVerticesKernel(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarLoopSubdivisionTables<T,U> const * subdivision = FarLoopSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarLoopSubdivisionTables<T,U> const *>(mesh->GetSubdivision()); dynamic_cast<FarLoopSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
assert(subdivision); assert(subdivision);
subdivision->computeEdgePoints(offset, level, start, end, clientdata); subdivision->computeEdgePoints(offset, level, start, end, clientdata);
} }
template <class T, class U> void 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 { FarDispatcher<T,U>::ApplyLoopVertexVerticesKernelB(FarMesh<T,U> * mesh, int offset, int level, int start, int end, void * clientdata) const {
FarLoopSubdivisionTables<T,U> const * subdivision = FarLoopSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarLoopSubdivisionTables<T,U> const *>(mesh->GetSubdivision()); dynamic_cast<FarLoopSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
assert(subdivision); assert(subdivision);
subdivision->computeVertexPointsB(offset, level, start, end, clientdata); subdivision->computeVertexPointsB(offset, level, start, end, clientdata);
} }
template <class T, class U> void 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 { 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 = FarLoopSubdivisionTables<T,U> const * subdivision =
dynamic_cast<FarLoopSubdivisionTables<T,U> const *>(mesh->GetSubdivision()); dynamic_cast<FarLoopSubdivisionTables<T,U> const *>(mesh->GetSubdivision());
assert(subdivision); assert(subdivision);
subdivision->computeVertexPointsA(offset, pass, level, start, end, clientdata); 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);
}
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION; using namespace OPENSUBDIV_VERSION;

View File

@ -82,14 +82,14 @@ template <class T, class U=T> class FarLoopSubdivisionTables : public FarSubdivi
public: public:
// Compute the positions of refined vertices using the specified kernels // Compute the positions of refined vertices using the specified kernels
virtual void Refine( int level, void * data=0 ) const; virtual void Apply( int level, void * data=0 ) const;
private: private:
friend class FarMeshFactory<T,U>; friend class FarMeshFactory<T,U>;
friend class FarDispatcher<T,U>; friend class FarDispatcher<T,U>;
// Constructor : build level table at depth 'level' // Constructor : build level table at depth 'level'
FarLoopSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int level ); FarLoopSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int level );
@ -100,7 +100,7 @@ private:
// Compute-kernel applied to vertices resulting from the refinement of a vertex // Compute-kernel applied to vertices resulting from the refinement of a vertex
// Kernel "A" Handles the k_Smooth and k_Dart rules // Kernel "A" Handles the k_Smooth and k_Dart rules
void computeVertexPointsA(int offset, bool pass, int level, int start, int end, void * clientdata) const; void computeVertexPointsA(int offset, bool pass, int level, int start, int end, void * clientdata) const;
// Compute-kernel applied to vertices resulting from the refinement of a vertex // Compute-kernel applied to vertices resulting from the refinement of a vertex
// Kernel "B" Handles the k_Crease and k_Corner rules // Kernel "B" Handles the k_Crease and k_Corner rules
void computeVertexPointsB(int offset,int level, int start, int end, void * clientdata) const; void computeVertexPointsB(int offset,int level, int start, int end, void * clientdata) const;
@ -114,7 +114,7 @@ private:
// codices detail : // codices detail :
// //
// _E_ITa[0] : index of the org / dest vertices of the parent edge // _E_ITa[0] : index of the org / dest vertices of the parent edge
// _E_ITa[1] : // _E_ITa[1] :
// _E_ITa[2] : index of vertices refined from the faces left / right // _E_ITa[2] : index of vertices refined from the faces left / right
// _E_ITa[3] : of the parent edge // _E_ITa[3] : of the parent edge
// //
@ -125,8 +125,8 @@ private:
// _V_ITa[3] : index of adjacent edge 1 (k_Crease rule) // _V_ITa[3] : index of adjacent edge 1 (k_Crease rule)
// //
template <class T, class U> template <class T, class U>
FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int maxlevel ) FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int maxlevel )
: FarSubdivisionTables<T,U>(mesh, maxlevel) : FarSubdivisionTables<T,U>(mesh, maxlevel)
{ {
std::vector<int> const & remap = factory._remapTable; std::vector<int> const & remap = factory._remapTable;
@ -141,13 +141,13 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
for (int level=1; level<=maxlevel; ++level) { for (int level=1; level<=maxlevel; ++level) {
// pointer to the first vertex corresponding to this level // pointer to the first vertex corresponding to this level
this->_vertsOffsets[level] = factory._vertVertIdx[level-1] + this->_vertsOffsets[level] = factory._vertVertIdx[level-1] +
factory._vertVertsList[level-1].size(); (int)factory._vertVertsList[level-1].size();
typename FarSubdivisionTables<T,U>::VertexKernelBatch * batch = & (this->_batches[level-1]); typename FarSubdivisionTables<T,U>::VertexKernelBatch * batch = & (this->_batches[level-1]);
// Edge vertices // Edge vertices
unsigned int * E_IT = this->_E_IT[level-1]; int * E_IT = this->_E_IT[level-1];
float * E_W = this->_E_W[level-1]; float * E_W = this->_E_W[level-1];
batch->kernelE = (int)factory._edgeVertsList[level].size(); batch->kernelE = (int)factory._edgeVertsList[level].size();
for (int i=0; i < batch->kernelE; ++i) { for (int i=0; i < batch->kernelE; ++i) {
@ -182,9 +182,9 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
this->_E_IT.SetMarker(level, &E_IT[4*batch->kernelE]); this->_E_IT.SetMarker(level, &E_IT[4*batch->kernelE]);
this->_E_W.SetMarker(level, &E_W[2*batch->kernelE]); this->_E_W.SetMarker(level, &E_W[2*batch->kernelE]);
// Vertex vertices // Vertex vertices
batch->InitVertexKernels( factory._vertVertsList[level].size(), 0 ); batch->InitVertexKernels( (int)factory._vertVertsList[level].size(), 0 );
int offset = 0; int offset = 0;
int * V_ITa = this->_V_ITa[level-1]; int * V_ITa = this->_V_ITa[level-1];
@ -198,19 +198,19 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
assert(v and pv); assert(v and pv);
// Look at HbrCatmarkSubdivision<T>::Subdivide for more details about // Look at HbrCatmarkSubdivision<T>::Subdivide for more details about
// the multi-pass interpolation // the multi-pass interpolation
int masks[2], npasses; int masks[2], npasses;
float weights[2]; float weights[2];
masks[0] = pv->GetMask(false); masks[0] = pv->GetMask(false);
masks[1] = pv->GetMask(true); masks[1] = pv->GetMask(true);
// If the masks are identical, only a single pass is necessary. If the // If the masks are identical, only a single pass is necessary. If the
// vertex is transitionning to another rule, two passes are necessary, // vertex is transitioning to another rule, two passes are necessary,
// except when transitionning from k_Dart to k_Smooth : the same // except when transitioning from k_Dart to k_Smooth : the same
// compute kernel is applied twice. Combining this special case allows // compute kernel is applied twice. Combining this special case allows
// to batch the compute kernels into fewer calls. // to batch the compute kernels into fewer calls.
if (masks[0] != masks[1] and ( if (masks[0] != masks[1] and (
not (masks[0]==HbrVertex<T>::k_Smooth and not (masks[0]==HbrVertex<T>::k_Smooth and
masks[1]==HbrVertex<T>::k_Dart))) { masks[1]==HbrVertex<T>::k_Dart))) {
weights[1] = pv->GetFractionalMask(); weights[1] = pv->GetFractionalMask();
weights[0] = 1.0f - weights[1]; weights[0] = 1.0f - weights[1];
@ -241,7 +241,7 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
V_IT[offset++] = remap[ e->GetDestVertex()->GetID() ]; V_IT[offset++] = remap[ e->GetDestVertex()->GetID() ];
e = e->GetPrev()->GetOpposite(); e = e->GetPrev()->GetOpposite();
if (e==start) break; if (e==start) break;
} }
break; break;
@ -272,7 +272,7 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
V_ITa[5*i+3] = remap[op.eidx[0]]; V_ITa[5*i+3] = remap[op.eidx[0]];
V_ITa[5*i+4] = remap[op.eidx[1]]; V_ITa[5*i+4] = remap[op.eidx[1]];
break; break;
} }
case HbrVertex<T>::k_Corner : case HbrVertex<T>::k_Corner :
// in the case of a k_Crease / k_Corner pass combination, we // 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 // need to set the valence to -1 to tell the "B" Kernel to
@ -284,7 +284,7 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
} }
if (rank>7) if (rank>7)
// the k_Corner and k_Crease single-pass cases apply a weight of 1.0 // the k_Corner and k_Crease single-pass cases apply a weight of 1.0
// but this value is inverted in the kernel // but this value is inverted in the kernel
V_W[i] = 0.0; V_W[i] = 0.0;
else else
@ -302,11 +302,11 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
} }
} }
template <class T, class U> void template <class T, class U> void
FarLoopSubdivisionTables<T,U>::Refine( int level, void * clientdata ) const FarLoopSubdivisionTables<T,U>::Apply( int level, void * clientdata ) const
{ {
assert(this->_mesh and level>0); assert(this->_mesh and level>0);
typename FarSubdivisionTables<T,U>::VertexKernelBatch const * batch = & (this->_batches[level-1]); typename FarSubdivisionTables<T,U>::VertexKernelBatch const * batch = & (this->_batches[level-1]);
FarDispatcher<T,U> const * dispatch = this->_mesh->GetDispatcher(); FarDispatcher<T,U> const * dispatch = this->_mesh->GetDispatcher();
@ -323,42 +323,42 @@ FarLoopSubdivisionTables<T,U>::Refine( int level, void * clientdata ) const
dispatch->ApplyLoopVertexVerticesKernelA(this->_mesh, offset, false, level, batch->kernelA1.first, batch->kernelA1.second, clientdata); dispatch->ApplyLoopVertexVerticesKernelA(this->_mesh, offset, false, level, batch->kernelA1.first, batch->kernelA1.second, clientdata);
if (batch->kernelA2.first < batch->kernelA2.second) if (batch->kernelA2.first < batch->kernelA2.second)
dispatch->ApplyLoopVertexVerticesKernelA(this->_mesh, offset, true, level, batch->kernelA2.first, batch->kernelA2.second, clientdata); dispatch->ApplyLoopVertexVerticesKernelA(this->_mesh, offset, true, level, batch->kernelA2.first, batch->kernelA2.second, clientdata);
} }
// //
// Edge-vertices compute Kernel - completely re-entrant // Edge-vertices compute Kernel - completely re-entrant
// //
template <class T, class U> void template <class T, class U> void
FarLoopSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const { FarLoopSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh); assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0), U * vsrc = &this->_mesh->GetVertices().at(0),
* vdst = vsrc + offset + start; * vdst = vsrc + offset + start;
const unsigned int * E_IT = this->_E_IT[level-1]; const int * E_IT = this->_E_IT[level-1];
const float * E_W = this->_E_W[level-1]; const float * E_W = this->_E_W[level-1];
for (int i=start; i<end; ++i, ++vdst ) { for (int i=start; i<end; ++i, ++vdst ) {
vdst->Clear(clientdata); vdst->Clear(clientdata);
int eidx0 = E_IT[4*i+0], int eidx0 = E_IT[4*i+0],
eidx1 = E_IT[4*i+1], eidx1 = E_IT[4*i+1],
eidx2 = E_IT[4*i+2], eidx2 = E_IT[4*i+2],
eidx3 = E_IT[4*i+3]; eidx3 = E_IT[4*i+3];
float endPtWeight = E_W[i*2+0]; float endPtWeight = E_W[i*2+0];
// Fully sharp edge : endPtWeight = 0.5f // Fully sharp edge : endPtWeight = 0.5f
vdst->AddWithWeight( vsrc[eidx0], endPtWeight, clientdata ); vdst->AddWithWeight( vsrc[eidx0], endPtWeight, clientdata );
vdst->AddWithWeight( vsrc[eidx1], endPtWeight, clientdata ); vdst->AddWithWeight( vsrc[eidx1], endPtWeight, clientdata );
if (eidx2!=-1) { if (eidx2!=-1) {
// Apply fractional sharpness // Apply fractional sharpness
float oppPtWeight = E_W[i*2+1]; float oppPtWeight = E_W[i*2+1];
vdst->AddWithWeight( vsrc[eidx2], oppPtWeight, clientdata ); vdst->AddWithWeight( vsrc[eidx2], oppPtWeight, clientdata );
vdst->AddWithWeight( vsrc[eidx3], oppPtWeight, clientdata ); vdst->AddWithWeight( vsrc[eidx3], oppPtWeight, clientdata );
} }
@ -373,11 +373,11 @@ FarLoopSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int sta
// //
// multi-pass kernel handling k_Crease and k_Corner rules // multi-pass kernel handling k_Crease and k_Corner rules
template <class T, class U> void template <class T, class U> void
FarLoopSubdivisionTables<T,U>::computeVertexPointsA( int offset, bool pass, int level, int start, int end, void * clientdata ) const { FarLoopSubdivisionTables<T,U>::computeVertexPointsA( int offset, bool pass, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh); assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0), U * vsrc = &this->_mesh->GetVertices().at(0),
* vdst = vsrc + offset + start; * vdst = vsrc + offset + start;
@ -385,19 +385,19 @@ FarLoopSubdivisionTables<T,U>::computeVertexPointsA( int offset, bool pass, int
const float * V_W = this->_V_W[level-1]; const float * V_W = this->_V_W[level-1];
for (int i=start; i<end; ++i, ++vdst ) { for (int i=start; i<end; ++i, ++vdst ) {
if (not pass) if (not pass)
vdst->Clear(clientdata); vdst->Clear(clientdata);
int n=V_ITa[5*i+1], // number of vertices in the _VO_IT array (valence) int n=V_ITa[5*i+1], // number of vertices in the _VO_IT array (valence)
p=V_ITa[5*i+2], // index of the parent vertex p=V_ITa[5*i+2], // index of the parent vertex
eidx0=V_ITa[5*i+3], // index of the first crease rule edge eidx0=V_ITa[5*i+3], // index of the first crease rule edge
eidx1=V_ITa[5*i+4]; // index of the second crease rule edge eidx1=V_ITa[5*i+4]; // index of the second crease rule edge
float weight = pass ? V_W[i] : 1.0f - V_W[i]; float weight = pass ? V_W[i] : 1.0f - V_W[i];
// In the case of fractional weight, the weight must be inverted since // In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the // the value is shared with the k_Smooth kernel (statistically the
// k_Smooth kernel runs much more often than this one) // k_Smooth kernel runs much more often than this one)
if (weight>0.0f and weight<1.0f and n>0) if (weight>0.0f and weight<1.0f and n>0)
weight=1.0f-weight; weight=1.0f-weight;
@ -418,11 +418,11 @@ FarLoopSubdivisionTables<T,U>::computeVertexPointsA( int offset, bool pass, int
} }
// multi-pass kernel handling k_Dart and k_Smooth rules // multi-pass kernel handling k_Dart and k_Smooth rules
template <class T, class U> void template <class T, class U> void
FarLoopSubdivisionTables<T,U>::computeVertexPointsB( int offset, int level, int start, int end, void * clientdata ) const { FarLoopSubdivisionTables<T,U>::computeVertexPointsB( int offset, int level, int start, int end, void * clientdata ) const {
assert(this->_mesh); assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0), U * vsrc = &this->_mesh->GetVertices().at(0),
* vdst = vsrc + offset + start; * vdst = vsrc + offset + start;
@ -431,13 +431,13 @@ FarLoopSubdivisionTables<T,U>::computeVertexPointsB( int offset, int level, int
const float * V_W = this->_V_W[level-1]; const float * V_W = this->_V_W[level-1];
for (int i=start; i<end; ++i, ++vdst ) { for (int i=start; i<end; ++i, ++vdst ) {
vdst->Clear(clientdata); vdst->Clear(clientdata);
int h = V_ITa[5*i ], // offset of the vertices in the _V0_IT array int h = V_ITa[5*i ], // offset of the vertices in the _V0_IT array
n = V_ITa[5*i+1], // number of vertices in the _VO_IT array (valence) n = V_ITa[5*i+1], // number of vertices in the _VO_IT array (valence)
p = V_ITa[5*i+2]; // index of the parent vertex p = V_ITa[5*i+2]; // index of the parent vertex
float weight = V_W[i], float weight = V_W[i],
wp = 1.0f/n, wp = 1.0f/n,
beta = 0.25f * cosf((float)M_PI * 2.0f * wp) + 0.375f; beta = 0.25f * cosf((float)M_PI * 2.0f * wp) + 0.375f;
@ -445,12 +445,12 @@ FarLoopSubdivisionTables<T,U>::computeVertexPointsB( int offset, int level, int
beta = (0.625f-beta)*wp; beta = (0.625f-beta)*wp;
vdst->AddWithWeight( vsrc[p], weight * (1.0f-(beta*n)), clientdata); vdst->AddWithWeight( vsrc[p], weight * (1.0f-(beta*n)), clientdata);
for (int j=0; j<n; ++j) for (int j=0; j<n; ++j)
vdst->AddWithWeight( vsrc[V_IT[h+j]], weight * beta ); vdst->AddWithWeight( vsrc[V_IT[h+j]], weight * beta );
vdst->AddVaryingWithWeight( vsrc[p], 1.0f, clientdata ); vdst->AddVaryingWithWeight( vsrc[p], 1.0f, clientdata );
} }
} }
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION

View File

@ -68,6 +68,7 @@ namespace OPENSUBDIV_VERSION {
template <class T, class U> class FarMeshFactory; template <class T, class U> class FarMeshFactory;
template <class T, class U> class FarSubdivisionTables; template <class T, class U> class FarSubdivisionTables;
template <class T, class U> class FarDispatcher; template <class T, class U> class FarDispatcher;
template <class T, class U> class FarVertexEditTables;
// Core serialized subdivision mesh class. // Core serialized subdivision mesh class.
// //
@ -79,7 +80,7 @@ template <class T, class U> class FarDispatcher;
template <class T, class U=T> class FarMesh { template <class T, class U=T> class FarMesh {
public: public:
~FarMesh(); ~FarMesh();
// returns the subdivision method // returns the subdivision method
@ -93,18 +94,25 @@ public:
k_BilinearQuads, k_BilinearQuads,
k_Triangles, 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; } 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; } std::vector<U> & GetVertices() { return _vertices; }
U & GetVertex(int index) { return _vertices[index]; } 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; 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
std::vector<int> const & GetPtexCoordinates(int level) const;
// returns vertex edit tables
FarVertexEditTables<T,U> const * GetVertexEdit() const { return _vertexEdit; }
// returns the number of coarse vertices held at the beginning of the vertex // returns the number of coarse vertices held at the beginning of the vertex
// buffer. // buffer.
int GetNumCoarseVertices() const; int GetNumCoarseVertices() const;
@ -112,14 +120,14 @@ public:
// 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()); } int GetNumVertices() const { return (int)(_vertices.size()); }
// apply the subdivision tables to compute the positions of the vertices up // apply the subdivision tables to compute the positions of the vertices up
// to 'level' // to 'level'
void Subdivide(int level=-1); void Subdivide(int level=-1);
private: private:
friend class FarMeshFactory<T,U>; friend class FarMeshFactory<T,U>;
FarMesh() : _subdivision(0), _dispatcher(0) { } FarMesh() : _subdivision(0), _dispatcher(0), _vertexEdit(0) { }
// non-copyable, so these are not implemented: // non-copyable, so these are not implemented:
FarMesh(FarMesh<T,U> const &); FarMesh(FarMesh<T,U> const &);
@ -130,13 +138,19 @@ private:
// customizable compute dispatcher class // customizable compute dispatcher class
FarDispatcher<T,U> * _dispatcher; FarDispatcher<T,U> * _dispatcher;
// list of vertices (up to N levels of subdivision) // list of vertices (up to N levels of subdivision)
std::vector<U> _vertices; std::vector<U> _vertices;
// list of vertex indices for each face // list of vertex indices for each face
std::vector< std::vector<int> > _faceverts; std::vector< std::vector<int> > _faceverts;
// ptex coordinates for each face
std::vector< std::vector<int> > _ptexcoordinates;
// hierarchical vertex edit tables
FarVertexEditTables<T,U> * _vertexEdit;
// XXX stub for adaptive work // XXX stub for adaptive work
PatchType _patchtype; PatchType _patchtype;
@ -146,8 +160,9 @@ private:
template <class T, class U> template <class T, class U>
FarMesh<T,U>::~FarMesh() FarMesh<T,U>::~FarMesh()
{ {
delete _subdivision; delete _subdivision;
delete _vertexEdit;
} }
template <class T, class U> int template <class T, class U> int
@ -155,13 +170,21 @@ FarMesh<T,U>::GetNumCoarseVertices() const {
return _numCoarseVertices; return _numCoarseVertices;
} }
template <class T, class U> std::vector<int> const & template <class T, class U> std::vector<int> const &
FarMesh<T,U>::GetFaceVertices(int level) const { FarMesh<T,U>::GetFaceVertices(int level) const {
if ( (level>=0) and (level<(int)_faceverts.size()) ) if ( (level>=0) and (level<(int)_faceverts.size()) )
return _faceverts[level]; return _faceverts[level];
return _faceverts[0]; return _faceverts[0];
} }
template <class T, class U> std::vector<int> const &
FarMesh<T,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 template <class T, class U> void
FarMesh<T,U>::Subdivide(int maxlevel) { FarMesh<T,U>::Subdivide(int maxlevel) {
@ -172,8 +195,11 @@ FarMesh<T,U>::Subdivide(int maxlevel) {
else else
maxlevel = std::min(maxlevel, _subdivision->GetMaxLevel()); maxlevel = std::min(maxlevel, _subdivision->GetMaxLevel());
for (int i=1; i<maxlevel; ++i) for (int i=1; i<maxlevel; ++i) {
_subdivision->Refine(i); _subdivision->Apply(i);
if (_vertexEdit)
_vertexEdit->Apply(i);
}
} }
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION

View File

@ -95,7 +95,7 @@ public:
// Create a table-based mesh representation // Create a table-based mesh representation
// XXXX : this creator will take the options for adaptive patch meshes // XXXX : this creator will take the options for adaptive patch meshes
FarMesh<T,U> * Create( FarDispatcher<T,U> * dispatch=0 ); FarMesh<T,U> * Create( FarDispatcher<T,U> * dispatch=0 );
// Maximum level of subidivision supported by this factory // Maximum level of subidivision supported by this factory
int GetMaxLevel() const { return _maxlevel; } int GetMaxLevel() const { return _maxlevel; }
@ -103,12 +103,12 @@ public:
int GetNumFaceVerticesTotal(int level) const { int GetNumFaceVerticesTotal(int level) const {
return sumList<HbrVertex<T> *>(_faceVertsList, level); 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 { int GetNumEdgeVerticesTotal(int level) const {
return sumList<HbrVertex<T> *>(_edgeVertsList, level); 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 { int GetNumVertexVerticesTotal(int level) const {
return sumList<HbrVertex<T> *>(_vertVertsList, level); return sumList<HbrVertex<T> *>(_vertVertsList, level);
@ -116,12 +116,12 @@ public:
// Valence summation up to 'level' // Valence summation up to 'level'
int GetNumAdjacentVertVerticesTotal(int level) const; 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 { int GetNumFacesTotal(int level) const {
return sumList<HbrFace<T> *>(_facesList, level); 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 ); int GetVertexID( HbrVertex<T> * v );
@ -132,6 +132,7 @@ private:
friend class FarBilinearSubdivisionTables<T,U>; friend class FarBilinearSubdivisionTables<T,U>;
friend class FarCatmarkSubdivisionTables<T,U>; friend class FarCatmarkSubdivisionTables<T,U>;
friend class FarLoopSubdivisionTables<T,U>; friend class FarLoopSubdivisionTables<T,U>;
friend class FarVertexEditTables<T,U>;
// Non-copyable, so these are not implemented: // Non-copyable, so these are not implemented:
FarMeshFactory( FarMeshFactory const & ); FarMeshFactory( FarMeshFactory const & );
@ -144,23 +145,29 @@ private:
static bool isLoop(HbrMesh<T> * mesh); static bool isLoop(HbrMesh<T> * mesh);
void copyTopology( std::vector<int> & vec, int level ); void copyTopology( std::vector<int> & vec, int level );
void generatePtexCoordinates( std::vector<int> & vec, int level );
FarVertexEditTables<T,U> * createVertexEdit(FarMesh<T,U> * mesh);
static void refine( HbrMesh<T> * mesh, int maxlevel ); static void refine( HbrMesh<T> * mesh, int maxlevel );
template <class Type> static int sumList( std::vector<std::vector<Type> > const & list, int level ); 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);
HbrMesh<T> * _hbrMesh; HbrMesh<T> * _hbrMesh;
int _maxlevel, int _maxlevel,
_numVertices, _numVertices,
_numFaces; _numFaces;
// per-level counters and offsets for each type of vertex (face,edge,vert) // per-level counters and offsets for each type of vertex (face,edge,vert)
std::vector<int> _faceVertIdx, std::vector<int> _faceVertIdx,
_edgeVertIdx, _edgeVertIdx,
_vertVertIdx; _vertVertIdx;
// number of indices required for the vertex iteration table at each level // number of indices required for the vertex iteration table at each level
std::vector<int> _vertVertsListSize; std::vector<int> _vertVertsListSize;
// remapping table to translate vertex ID's between Hbr indices and the // remapping table to translate vertex ID's between Hbr indices and the
@ -168,7 +175,7 @@ private:
std::vector<int> _remapTable; std::vector<int> _remapTable;
// lists of vertices sorted by type and level // lists of vertices sorted by type and level
std::vector<std::vector< HbrVertex<T> *> > _faceVertsList, std::vector<std::vector< HbrVertex<T> *> > _faceVertsList,
_edgeVertsList, _edgeVertsList,
_vertVertsList; _vertVertsList;
@ -176,21 +183,21 @@ private:
std::vector<std::vector< HbrFace<T> *> > _facesList; std::vector<std::vector< HbrFace<T> *> > _facesList;
}; };
template <class T, class U> template <class T, class U>
template <class Type> int template <class Type> int
FarMeshFactory<T,U>::sumList( std::vector<std::vector<Type> > const & list, int level) { 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());
int total = 0; int total = 0;
for (int i=0; i<=level; ++i) for (int i=0; i<=level; ++i)
total += (int)list[i].size(); total += (int)list[i].size();
return total; return total;
} }
template <class T, class U> int template <class T, class U> int
FarMeshFactory<T,U>::GetNumAdjacentVertVerticesTotal(int level) const { FarMeshFactory<T,U>::GetNumAdjacentVertVerticesTotal(int level) const {
level = std::min(level, GetMaxLevel()); level = std::min(level, GetMaxLevel());
int total = 0; int total = 0;
for (int i=0; i<=level; ++i) for (int i=0; i<=level; ++i)
total += _vertVertsListSize[i]; total += _vertVertsListSize[i];
@ -214,17 +221,17 @@ FarMeshFactory<T,U>::refine( HbrMesh<T> * mesh, int maxlevel ) {
// Assumption : the order of the vertices in the HbrMesh could be set in any // 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 // random order, so the builder runs 2 passes over the entire vertex list to
// gather the counters needed to generate the indexing tables. // gather the counters needed to generate the indexing tables.
template <class T, class U> template <class T, class U>
FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel ) : FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel ) :
_hbrMesh(mesh), _hbrMesh(mesh),
_maxlevel(maxlevel), _maxlevel(maxlevel),
_numVertices(-1), _numVertices(-1),
_numFaces(-1), _numFaces(-1),
_faceVertIdx(maxlevel+1,0), _faceVertIdx(maxlevel+1,0),
_edgeVertIdx(maxlevel+1,0), _edgeVertIdx(maxlevel+1,0),
_vertVertIdx(maxlevel+1,0), _vertVertIdx(maxlevel+1,0),
_vertVertsListSize(maxlevel+1,0), _vertVertsListSize(maxlevel+1,0),
_faceVertsList(maxlevel+1), _faceVertsList(maxlevel+1),
_edgeVertsList(maxlevel+1), _edgeVertsList(maxlevel+1),
_vertVertsList(maxlevel+1), _vertVertsList(maxlevel+1),
_facesList(maxlevel+1) _facesList(maxlevel+1)
@ -235,11 +242,11 @@ FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel ) :
int numVertices = mesh->GetNumVertices(); int numVertices = mesh->GetNumVertices();
int numFaces = mesh->GetNumFaces(); int numFaces = mesh->GetNumFaces();
std::vector<int> faceCounts(maxlevel+1,0), std::vector<int> faceCounts(maxlevel+1,0),
edgeCounts(maxlevel+1,0), edgeCounts(maxlevel+1,0),
vertCounts(maxlevel+1,0); vertCounts(maxlevel+1,0);
// First pass (vertices) : count the vertices of each type for each depth // First pass (vertices) : count the vertices of each type for each depth
// up to maxlevel (values are dependent on topology). // up to maxlevel (values are dependent on topology).
int maxvertid=-1; int maxvertid=-1;
for (int i=0; i<numVertices; ++i) { for (int i=0; i<numVertices; ++i) {
@ -248,48 +255,48 @@ FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel ) :
assert(v); assert(v);
int depth = v->GetFace()->GetDepth(); int depth = v->GetFace()->GetDepth();
if (depth>maxlevel) if (depth>maxlevel)
continue; continue;
if (depth==0 ) if (depth==0 )
vertCounts[depth]++; vertCounts[depth]++;
if (v->GetID()>maxvertid) if (v->GetID()>maxvertid)
maxvertid = v->GetID(); maxvertid = v->GetID();
if (not v->OnBoundary()) if (not v->OnBoundary())
_vertVertsListSize[depth] += v->GetValence(); _vertVertsListSize[depth] += v->GetValence();
else if (v->GetValence()!=2) else if (v->GetValence()!=2)
_vertVertsListSize[depth] ++; _vertVertsListSize[depth] ++;
if (v->GetParentFace()) if (v->GetParentFace())
faceCounts[depth]++; faceCounts[depth]++;
else if (v->GetParentEdge()) else if (v->GetParentEdge())
edgeCounts[depth]++; edgeCounts[depth]++;
else if (v->GetParentVertex()) else if (v->GetParentVertex())
vertCounts[depth]++; vertCounts[depth]++;
} }
// Per-level offset to the first vertex of each type in the global vertex map // Per-level offset to the first vertex of each type in the global vertex map
_vertVertsList[0].reserve( vertCounts[0] ); _vertVertsList[0].reserve( vertCounts[0] );
for (int l=1; l<(maxlevel+1); ++l) { for (int l=1; l<(maxlevel+1); ++l) {
_faceVertIdx[l]= _vertVertIdx[l-1]+vertCounts[l-1]; _faceVertIdx[l]= _vertVertIdx[l-1]+vertCounts[l-1];
_edgeVertIdx[l]= _faceVertIdx[l]+faceCounts[l]; _edgeVertIdx[l]= _faceVertIdx[l]+faceCounts[l];
_vertVertIdx[l]= _edgeVertIdx[l]+edgeCounts[l]; _vertVertIdx[l]= _edgeVertIdx[l]+edgeCounts[l];
_faceVertsList[l].reserve( faceCounts[l] ); _faceVertsList[l].reserve( faceCounts[l] );
_edgeVertsList[l].reserve( edgeCounts[l] ); _edgeVertsList[l].reserve( edgeCounts[l] );
_vertVertsList[l].reserve( vertCounts[l] ); _vertVertsList[l].reserve( vertCounts[l] );
} }
// reset counters // reset counters
faceCounts.assign(maxlevel+1,0); faceCounts.assign(maxlevel+1,0);
edgeCounts.assign(maxlevel+1,0); edgeCounts.assign(maxlevel+1,0);
_remapTable.resize( maxvertid+1, -1); _remapTable.resize( maxvertid+1, -1);
// Second pass (vertices) : calculate the starting indices of the sub-tables // Second pass (vertices) : calculate the starting indices of the sub-tables
// (face, edge, verts...) and populate the remapping table. // (face, edge, verts...) and populate the remapping table.
for (int i=0; i<numVertices; ++i) { for (int i=0; i<numVertices; ++i) {
@ -297,13 +304,13 @@ FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel ) :
assert(v); assert(v);
int depth = v->GetFace()->GetDepth(); int depth = v->GetFace()->GetDepth();
if (depth>maxlevel) if (depth>maxlevel)
continue; continue;
assert( _remapTable[ v->GetID() ] = -1 ); assert( _remapTable[ v->GetID() ] = -1 );
if (depth==0) { if (depth==0) {
_vertVertsList[ depth ].push_back( v ); _vertVertsList[ depth ].push_back( v );
_remapTable[ v->GetID() ] = v->GetID(); _remapTable[ v->GetID() ] = v->GetID();
} else if (v->GetParentFace()) { } else if (v->GetParentFace()) {
@ -318,25 +325,25 @@ FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel ) :
_vertVertsList[ depth ].push_back( v ); _vertVertsList[ depth ].push_back( v );
} }
} }
// Sort the the vertices that are the child of a vertex based on their weight // 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 // mask. The masks combinations are ordered so as to minimize the compute
// kernel switching ( more information on this in the HbrVertex<T> comparison // kernel switching ( more information on this in the HbrVertex<T> comparison
// function 'FarSubdivisionTables<T>::compareVertices' ). // function 'FarSubdivisionTables<T>::compareVertices' ).
for (size_t i=1; i<_vertVertsList.size(); ++i) for (size_t i=1; i<_vertVertsList.size(); ++i)
std::sort(_vertVertsList[i].begin(), _vertVertsList[i].end(), std::sort(_vertVertsList[i].begin(), _vertVertsList[i].end(),
FarSubdivisionTables<T,U>::compareVertices); FarSubdivisionTables<T,U>::compareVertices);
// These vertices still need a remapped index // These vertices still need a remapped index
for (int l=1; l<(maxlevel+1); ++l) for (int l=1; l<(maxlevel+1); ++l)
for (size_t i=0; i<_vertVertsList[l].size(); ++i) for (size_t i=0; i<_vertVertsList[l].size(); ++i)
_remapTable[ _vertVertsList[l][i]->GetID() ]=_vertVertIdx[l]+i; _remapTable[ _vertVertsList[l][i]->GetID() ]=_vertVertIdx[l]+(int)i;
// Third pass (faces) : populate the face lists. // Third pass (faces) : populate the face lists.
int fsize=0; int fsize=0;
for (int i=0; i<numFaces; ++i) { for (int i=0; i<numFaces; ++i) {
HbrFace<T> * f = mesh->GetFace(i); HbrFace<T> * f = mesh->GetFace(i);
assert(f); assert(f);
if (f->GetDepth()==0) if (f->GetDepth()==0)
fsize += mesh->GetSubdivision()->GetFaceChildrenCount( f->GetNumVertices() ); fsize += mesh->GetSubdivision()->GetFaceChildrenCount( f->GetNumVertices() );
@ -359,12 +366,12 @@ FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel ) :
GetNumVertexVerticesTotal(maxlevel); GetNumVertexVerticesTotal(maxlevel);
} }
template <class T, class U> bool template <class T, class U> bool
FarMeshFactory<T,U>::isBilinear(HbrMesh<T> * mesh) { FarMeshFactory<T,U>::isBilinear(HbrMesh<T> * mesh) {
return typeid(*(mesh->GetSubdivision()))==typeid(HbrBilinearSubdivision<T>); return typeid(*(mesh->GetSubdivision()))==typeid(HbrBilinearSubdivision<T>);
} }
template <class T, class U> bool template <class T, class U> bool
FarMeshFactory<T,U>::isCatmark(HbrMesh<T> * mesh) { FarMeshFactory<T,U>::isCatmark(HbrMesh<T> * mesh) {
return typeid(*(mesh->GetSubdivision()))==typeid(HbrCatmarkSubdivision<T>); return typeid(*(mesh->GetSubdivision()))==typeid(HbrCatmarkSubdivision<T>);
} }
@ -378,17 +385,17 @@ template <class T, class U> void
FarMeshFactory<T,U>::copyTopology( std::vector<int> & vec, int level ) { FarMeshFactory<T,U>::copyTopology( std::vector<int> & vec, int level ) {
assert( _hbrMesh ); assert( _hbrMesh );
int nv=-1; int nv=-1;
if ( isCatmark(_hbrMesh) or isBilinear(_hbrMesh) ) if ( isCatmark(_hbrMesh) or isBilinear(_hbrMesh) )
nv=4; nv=4;
else if ( isLoop(_hbrMesh) ) else if ( isLoop(_hbrMesh) )
nv=3; nv=3;
assert(nv>0); assert(nv>0);
vec.resize( nv * _facesList[level].size(), -1 ); vec.resize( nv * _facesList[level].size(), -1 );
for (int i=0; i<(int)_facesList[level].size(); ++i) { for (int i=0; i<(int)_facesList[level].size(); ++i) {
HbrFace<T> * f = _facesList[level][i]; HbrFace<T> * f = _facesList[level][i];
assert( f and f->GetNumVertices()==nv); assert( f and f->GetNumVertices()==nv);
@ -396,7 +403,6 @@ FarMeshFactory<T,U>::copyTopology( std::vector<int> & vec, int level ) {
vec[nv*i+j]=_remapTable[f->GetVertex(j)->GetID()]; vec[nv*i+j]=_remapTable[f->GetVertex(j)->GetID()];
} }
} }
template <class T, class U> void template <class T, class U> void
copyVertex( T & dest, U const & src ) { copyVertex( T & dest, U const & src ) {
} }
@ -406,14 +412,193 @@ copyVertex( T & dest, T const & src ) {
dest = src; dest = src;
} }
template <class T, class U> FarMesh<T,U> * // XXX : this currently only supports Catmark / Bilinear schemes.
template <class T, class U> void
FarMeshFactory<T,U>::generatePtexCoordinates( std::vector<int> & vec, int level ) {
assert( _hbrMesh );
if (_facesList[level][0]->GetPtexIndex() == -1) return;
vec.resize( _facesList[level].size()*2, -1 );
for (int i=0; i<(int)_facesList[level].size(); ++i) {
HbrFace<T> const * f = _facesList[level][i];
assert(f);
short u,v;
unsigned short ofs = 1, depth;
bool quad = true;
// track upwards towards coarse face, accumulating u,v indices
HbrFace<T> const * p = f->GetParent();
for ( u=v=depth=0; p!=NULL; depth++ ) {
int nverts = p->GetNumVertices();
if ( nverts != 4 ) { // non-quad coarse face : stop accumulating offsets
quad = false; // invert the coarse face index
break;
}
for (unsigned char i=0; i<nverts; ++i)
if ( p->GetChild( i )==f ) {
switch ( i ) {
case 0 : break;
case 1 : { u+=ofs; } break;
case 2 : { u+=ofs; v+=ofs; } break;
case 3 : { v+=ofs; } break;
}
break;
}
ofs = ofs << 1;
f = p;
p = f->GetParent();
}
vec[2*i] = quad ? f->GetPtexIndex() : -f->GetPtexIndex();
vec[2*i+1] = (int)u << 16;
vec[2*i+1] += v;
}
}
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 ) { FarMeshFactory<T,U>::Create( FarDispatcher<T,U> * dispatch ) {
assert( _hbrMesh ); assert( _hbrMesh );
if (_maxlevel<1) if (_maxlevel<1)
return 0; return 0;
FarMesh<T,U> * result = new FarMesh<T,U>(); FarMesh<T,U> * result = new FarMesh<T,U>();
if (dispatch) if (dispatch)
@ -422,19 +607,19 @@ FarMeshFactory<T,U>::Create( FarDispatcher<T,U> * dispatch ) {
result->_dispatcher = & FarDispatcher<T,U>::_DefaultDispatcher; result->_dispatcher = & FarDispatcher<T,U>::_DefaultDispatcher;
if ( isBilinear( _hbrMesh ) ) { if ( isBilinear( _hbrMesh ) ) {
result->_subdivision = result->_subdivision =
new FarBilinearSubdivisionTables<T,U>( *this, result, _maxlevel ); new FarBilinearSubdivisionTables<T,U>( *this, result, _maxlevel );
} else if ( isCatmark( _hbrMesh ) ) { } else if ( isCatmark( _hbrMesh ) ) {
result->_subdivision = result->_subdivision =
new FarCatmarkSubdivisionTables<T,U>( *this, result, _maxlevel ); new FarCatmarkSubdivisionTables<T,U>( *this, result, _maxlevel );
} else if ( isLoop(_hbrMesh) ) { } else if ( isLoop(_hbrMesh) ) {
result->_subdivision = result->_subdivision =
new FarLoopSubdivisionTables<T,U>( *this, result, _maxlevel ); new FarLoopSubdivisionTables<T,U>( *this, result, _maxlevel );
} else } else
assert(0); assert(0);
result->_numCoarseVertices = (int)_vertVertsList[0].size(); result->_numCoarseVertices = (int)_vertVertsList[0].size();
// Copy the data of the coarse vertices into the vertex buffer. // Copy the data of the coarse vertices into the vertex buffer.
// XXXX : we should figure out a test to make sure that the vertex // XXXX : we should figure out a test to make sure that the vertex
// class is not an empty placeholder (ex. non-interleaved data) // class is not an empty placeholder (ex. non-interleaved data)
@ -445,13 +630,21 @@ FarMeshFactory<T,U>::Create( FarDispatcher<T,U> * dispatch ) {
// Populate topology (face verts indices) // Populate topology (face verts indices)
// XXXX : only k_BilinearQuads support for now - adaptive bicubic patches to come // XXXX : only k_BilinearQuads support for now - adaptive bicubic patches to come
result->_patchtype = FarMesh<T,U>::k_BilinearQuads; result->_patchtype = FarMesh<T,U>::k_BilinearQuads;
// XXXX : we should let the client decide which levels to copy, // XXXX : we should let the client control what to copy, most of this may be irrelevant
// they may only want vertices...
result->_faceverts.resize(_maxlevel+1); result->_faceverts.resize(_maxlevel+1);
for (int l=1; l<=_maxlevel; ++l) for (int l=1; l<=_maxlevel; ++l)
copyTopology(result->_faceverts[l], l); copyTopology(result->_faceverts[l], l);
result->_ptexcoordinates.resize(_maxlevel+1);
for (int l=1; l<=_maxlevel; ++l)
generatePtexCoordinates(result->_ptexcoordinates[l], l);
// Create VertexEditTables if necessary
if (_hbrMesh->HasVertexEdits()) {
result->_vertexEdit = createVertexEdit(result);
}
return result; return result;
} }

View File

@ -62,6 +62,7 @@
#include <vector> #include <vector>
#include "../version.h" #include "../version.h"
#include "../far/table.h"
template <class T> class HbrFace; template <class T> class HbrFace;
template <class T> class HbrHalfedge; template <class T> class HbrHalfedge;
@ -89,7 +90,7 @@ template <class T, class U> class FarMeshFactory;
// _<T>_W : fractional weight of the vertex (based on sharpness & topology) // _<T>_W : fractional weight of the vertex (based on sharpness & topology)
// _<T>_ITa : codex for the two previous tables // _<T>_ITa : codex for the two previous tables
// For more details see : "Feature Adaptive GPU Rendering of Catmull-Clark // For more details see : "Feature Adaptive GPU Rendering of Catmull-Clark
// Subdivision Surfaces" p.3 - par. 3.2 // Subdivision Surfaces" p.3 - par. 3.2
template <class T, class U=T> class FarSubdivisionTables { template <class T, class U=T> class FarSubdivisionTables {
public: public:
@ -102,17 +103,17 @@ public:
// Memory required to store the indexing tables // Memory required to store the indexing tables
virtual int GetMemoryUsed() const; 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 Refine( int level, void * clientdata=0 ) const=0; virtual void Apply( int level, void * clientdata=0 ) const=0;
// Pointer back to the mesh owning the table // Pointer back to the mesh owning the table
FarMesh<T,U> * GetMesh() { return _mesh; } FarMesh<T,U> * GetMesh() { return _mesh; }
// The index of the first vertex that belongs to the level of subdivision // The index of the first vertex that belongs to the level of subdivision
// represented by this set of FarCatmarkSubdivisionTables // represented by this set of FarCatmarkSubdivisionTables
int GetFirstVertexOffset( int level ) const; 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; int GetNumFaceVertices( int level ) const;
@ -121,70 +122,27 @@ public:
// 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; int GetNumVertexVertices( int level ) const;
// Total number of vertices at a given level // Total number of vertices at a given level
int GetNumVertices( int level ) const; int GetNumVertices( int level ) const;
// Indexing tables accessors // Indexing tables accessors
// 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)
template <typename Type> class Table {
std::vector<Type> _data; // table data
std::vector<Type *> _markers; // pointers to the first datum at each level
public:
Table(int maxlevel) : _markers(maxlevel) { }
// Returns the memory required to store the data in this table.
int GetMemoryUsed() const {
return (int)_data.size() * sizeof(Type);
}
// 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)
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
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
const Type * operator[](int level) const {
return const_cast<Table *>(this)->operator[](level);
}
};
// Returns the edge vertices indexing table // Returns the edge vertices indexing table
Table<unsigned int> const & Get_E_IT() const { return _E_IT; } FarTable<int> const & Get_E_IT() const { return _E_IT; }
// Returns the edge vertices weights table // Returns the edge vertices weights table
Table<float> const & Get_E_W() const { return _E_W; } FarTable<float> const & Get_E_W() const { return _E_W; }
// Returns the vertex vertices codex table // Returns the vertex vertices codex table
Table<int> const & Get_V_ITa() const { return _V_ITa; } FarTable<int> const & Get_V_ITa() const { return _V_ITa; }
// Returns the vertex vertices indexing table // Returns the vertex vertices indexing table
Table<unsigned int> const & Get_V_IT() const { return _V_IT; } FarTable<unsigned int> const & Get_V_IT() const { return _V_IT; }
// Returns the vertex vertices weights table // Returns the vertex vertices weights table
Table<float> const & Get_V_W() const { return _V_W; } FarTable<float> const & Get_V_W() const { return _V_W; }
// Returns the number of indexing tables needed to represent this particular // Returns the number of indexing tables needed to represent this particular
// subdivision scheme. // subdivision scheme.
virtual int GetNumTables() const { return 5; } virtual int GetNumTables() const { return 5; }
@ -196,7 +154,7 @@ protected:
// Returns an integer based on the order in which the kernels are applied // Returns an integer based on the order in which the kernels are applied
static int getMaskRanking( unsigned char mask0, unsigned char mask1 ); static int getMaskRanking( unsigned char mask0, unsigned char mask1 );
// Compares to vertices based on the ranking of their hbr masks combination // Compares to vertices based on the ranking of their hbr masks combination
static bool compareVertices( HbrVertex<T> const * x, HbrVertex<T> const * y ); static bool compareVertices( HbrVertex<T> const * x, HbrVertex<T> const * y );
@ -207,10 +165,10 @@ protected:
std::pair<int,int> kernelB; // first / last vertex vertex batch (kernel B) std::pair<int,int> kernelB; // first / last vertex vertex batch (kernel B)
std::pair<int,int> kernelA1; // first / last vertex vertex batch (kernel A pass 1) std::pair<int,int> kernelA1; // first / last vertex vertex batch (kernel A pass 1)
std::pair<int,int> kernelA2; // first / last vertex vertex batch (kernel A pass 2) std::pair<int,int> kernelA2; // first / last vertex vertex batch (kernel A pass 2)
VertexKernelBatch() : kernelF(0), kernelE(0) { } VertexKernelBatch() : kernelF(0), kernelE(0) { }
void InitVertexKernels(int a, int b) { void InitVertexKernels(int a, int b) {
kernelB.first = kernelA1.first = kernelA2.first = a; kernelB.first = kernelA1.first = kernelA2.first = a;
kernelB.second = kernelA1.second = kernelA2.second = b; kernelB.second = kernelA1.second = kernelA2.second = b;
} }
@ -218,21 +176,21 @@ protected:
void AddVertex( int index, int rank ) { void AddVertex( int index, int rank ) {
// expand the range of kernel batches based on vertex index and rank // expand the range of kernel batches based on vertex index and rank
if (rank<7) { if (rank<7) {
if (index < kernelB.first) if (index < kernelB.first)
kernelB.first=index; kernelB.first=index;
if (index > kernelB.second) if (index > kernelB.second)
kernelB.second=index; kernelB.second=index;
} }
if ((rank>2) and (rank<8)) { if ((rank>2) and (rank<8)) {
if (index < kernelA2.first) if (index < kernelA2.first)
kernelA2.first=index; kernelA2.first=index;
if (index > kernelA2.second) if (index > kernelA2.second)
kernelA2.second=index; kernelA2.second=index;
} }
if (rank>6) { if (rank>6) {
if (index < kernelA1.first) if (index < kernelA1.first)
kernelA1.first=index; kernelA1.first=index;
if (index > kernelA1.second) if (index > kernelA1.second)
kernelA1.second=index; kernelA1.second=index;
} }
} }
@ -244,23 +202,23 @@ protected:
protected: protected:
// mesh that owns this subdivisionTable // mesh that owns this subdivisionTable
FarMesh<T,U> * _mesh; FarMesh<T,U> * _mesh;
Table<unsigned int> _E_IT; // vertices from edge refinement FarTable<int> _E_IT; // vertices from edge refinement
Table<float> _E_W; // weigths FarTable<float> _E_W; // weigths
Table<int> _V_ITa; // vertices from vertex refinement FarTable<int> _V_ITa; // vertices from vertex refinement
Table<unsigned int> _V_IT; // indices of adjacent vertices FarTable<unsigned int> _V_IT; // indices of adjacent vertices
Table<float> _V_W; // weights FarTable<float> _V_W; // weights
std::vector<VertexKernelBatch> _batches; // batches of vertices for kernel execution std::vector<VertexKernelBatch> _batches; // batches of vertices for kernel execution
std::vector<int> _vertsOffsets; // offset to the first vertex of each level std::vector<int> _vertsOffsets; // offset to the first vertex of each level
private: private:
}; };
template <class T, class U> template <class T, class U>
FarSubdivisionTables<T,U>::FarSubdivisionTables( FarMesh<T,U> * mesh, int maxlevel ) : FarSubdivisionTables<T,U>::FarSubdivisionTables( FarMesh<T,U> * mesh, int maxlevel ) :
_mesh(mesh), _mesh(mesh),
_E_IT(maxlevel+1), _E_IT(maxlevel+1),
_E_W(maxlevel+1), _E_W(maxlevel+1),
@ -277,7 +235,7 @@ FarSubdivisionTables<T,U>::FarSubdivisionTables( FarMesh<T,U> * mesh, int maxlev
// of Corner, Crease, Dart and Smooth topological configurations. This matrix is // of Corner, Crease, Dart and Smooth topological configurations. This matrix is
// somewhat arbitrary as it is possible to perform some permutations in the // somewhat arbitrary as it is possible to perform some permutations in the
// ordering without adverse effects, but it does try to minimize kernel switching // ordering without adverse effects, but it does try to minimize kernel switching
// during the exececution of Refine(). This table is identical for both the Loop // during the exececution of Apply(). This table is identical for both the Loop
// and Catmull-Clark schemes. // and Catmull-Clark schemes.
// //
// The matrix is derived from this table : // The matrix is derived from this table :
@ -290,10 +248,10 @@ FarSubdivisionTables<T,U>::FarSubdivisionTables( FarMesh<T,U> * mesh, int maxlev
// +----+----+----+----+----+----+----+----+----+----+ // +----+----+----+----+----+----+----+----+----+----+
// Rank | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | // Rank | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
// +----+----+----+----+----+----+----+----+----+----+ // +----+----+----+----+----+----+----+----+----+----+
// with : // with :
// - A : compute kernel applying k_Crease / k_Corner rules // - A : compute kernel applying k_Crease / k_Corner rules
// - B : compute kernel applying k_Smooth / k_Dart rules // - B : compute kernel applying k_Smooth / k_Dart rules
template <class T, class U> int template <class T, class U> int
FarSubdivisionTables<T,U>::getMaskRanking( unsigned char mask0, unsigned char mask1 ) { FarSubdivisionTables<T,U>::getMaskRanking( unsigned char mask0, unsigned char mask1 ) {
static short masks[4][4] = { { 0, 1, 6, 4 }, static short masks[4][4] = { { 0, 1, 6, 4 },
{ 0xFF, 2, 5, 3 }, { 0xFF, 2, 5, 3 },
@ -313,46 +271,46 @@ template <class T, class U> bool
FarSubdivisionTables<T,U>::compareVertices( HbrVertex<T> const * x, HbrVertex<T> const * y ) { FarSubdivisionTables<T,U>::compareVertices( HbrVertex<T> const * x, HbrVertex<T> const * y ) {
// Masks of the parent vertex decide for the current vertex. // Masks of the parent vertex decide for the current vertex.
HbrVertex<T> * px=x->GetParentVertex(), HbrVertex<T> * px=x->GetParentVertex(),
* py=y->GetParentVertex(); * py=y->GetParentVertex();
assert( (getMaskRanking(px->GetMask(false), px->GetMask(true) )!=0xFF) and assert( (getMaskRanking(px->GetMask(false), px->GetMask(true) )!=0xFF) and
(getMaskRanking(py->GetMask(false), py->GetMask(true) )!=0xFF) ); (getMaskRanking(py->GetMask(false), py->GetMask(true) )!=0xFF) );
return getMaskRanking(px->GetMask(false), px->GetMask(true) ) < return getMaskRanking(px->GetMask(false), px->GetMask(true) ) <
getMaskRanking(py->GetMask(false), py->GetMask(true) ); getMaskRanking(py->GetMask(false), py->GetMask(true) );
} }
template <class T, class U> int template <class T, class U> int
FarSubdivisionTables<T,U>::GetFirstVertexOffset( int level ) const { FarSubdivisionTables<T,U>::GetFirstVertexOffset( int level ) const {
assert(level>=0 and level<=(int)_vertsOffsets.size()); assert(level>=0 and level<=(int)_vertsOffsets.size());
return _vertsOffsets[level]; return _vertsOffsets[level];
} }
template <class T, class U> int template <class T, class U> int
FarSubdivisionTables<T,U>::GetNumFaceVertices( int level ) const { FarSubdivisionTables<T,U>::GetNumFaceVertices( int level ) const {
assert(level>=0 and level<=(int)_batches.size()); assert(level>=0 and level<=(int)_batches.size());
return _batches[level-1].kernelF; return _batches[level-1].kernelF;
} }
template <class T, class U> int template <class T, class U> int
FarSubdivisionTables<T,U>::GetNumEdgeVertices( int level ) const { FarSubdivisionTables<T,U>::GetNumEdgeVertices( int level ) const {
assert(level>=0 and level<=(int)_batches.size()); assert(level>=0 and level<=(int)_batches.size());
return _batches[level-1].kernelE; return _batches[level-1].kernelE;
} }
template <class T, class U> int template <class T, class U> int
FarSubdivisionTables<T,U>::GetNumVertexVertices( int level ) const { FarSubdivisionTables<T,U>::GetNumVertexVertices( int level ) const {
assert(level>=0 and level<=(int)_batches.size()); assert(level>=0 and level<=(int)_batches.size());
if (level==0) if (level==0)
return _mesh->GetNumCoarseVertices(); return _mesh->GetNumCoarseVertices();
else else
return std::max( _batches[level-1].kernelB.second, return std::max( _batches[level-1].kernelB.second,
std::max(_batches[level-1].kernelA1.second, std::max(_batches[level-1].kernelA1.second,
_batches[level-1].kernelA2.second)); _batches[level-1].kernelA2.second));
} }
template <class T, class U> int template <class T, class U> int
FarSubdivisionTables<T,U>::GetNumVertices( int level ) const { FarSubdivisionTables<T,U>::GetNumVertices( int level ) const {
assert(level>=0 and level<=(int)_batches.size()); assert(level>=0 and level<=(int)_batches.size());
if (level==0) if (level==0)

127
opensubdiv/far/table.h Normal file
View File

@ -0,0 +1,127 @@
//
// 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_TABLE_H
#define FAR_TABLE_H
#include "../version.h"
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)
template <typename Type> class FarTable {
std::vector<Type> _data; // table data
std::vector<Type *> _markers; // pointers to the first datum at each level
public:
FarTable() { }
FarTable(int maxlevel) : _markers(maxlevel) { }
// 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.
int GetMemoryUsed() const {
return (int)_data.size() * sizeof(Type);
}
// 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
void SetMarker(int level, Type * marker) {
_markers[level] = marker;
}
// 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
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
const Type * operator[](int level) const {
return const_cast<FarTable *>(this)->operator[](level);
}
};
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* FAR_TABLE_H */

View File

@ -0,0 +1,215 @@
//
// 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_H
#define FAR_VERTEX_EDIT_TABLES_H
#include <assert.h>
#include <utility>
#include <vector>
#include "../version.h"
#include "../far/table.h"
#include "../far/dispatcher.h"
#include "../hbr/hierarchicalEdit.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 T, class U=T> class FarVertexEditTables {
public:
FarVertexEditTables( FarMesh<T,U> * mesh, int maxlevel);
// type of edit operation. This enum matches to HbrHiearachicalEdit<T>::Operation
enum Operation {
Set,
Add
};
// Compute the positions of edited vertices
void Apply(int level, void * clientdata=0) const;
int GetNumBatches() const {
return (int)_batches.size();
}
// this class holds a batch for vertex edit. each batch has unique index/width/operation
class VertexEdit {
public:
VertexEdit(int index, int width, 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;
// Edit tables accessors
// Returns the edit offset table
FarTable<unsigned int> const & Get_Offsets() const { return _offsets; }
// Returns the edit values table
FarTable<float> const & Get_Values() const { return _values; }
Operation GetOperation() const { return _operation; }
int GetPrimvarOffset() const { return _index; }
int GetPrimvarWidth() const { return _width; }
private:
friend class FarMeshFactory<T,U>;
FarTable<unsigned int> _offsets; // absolute vertex index array for edits
FarTable<float> _values; // edit values array
int _index; // primvar offset in vertex
int _width; // numElements per vertex in values
Operation _operation; // edit operation (Set, Add)
};
VertexEdit const & GetBatch(int index) const {
return _batches[index];
}
protected:
friend class FarMeshFactory<T,U>;
friend class FarDispatcher<T,U>;
// Compute-kernel applied to vertices
void editVertex(int level, void *clientdata) const;
// mesh that owns this vertexEditTable
FarMesh<T,U> * _mesh;
std::vector<VertexEdit> _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 T, class U>
void
FarVertexEditTables<T,U>::VertexEdit::ApplyVertexEdit(U * vsrc, int level) const
{
int n = _offsets.GetNumElements(level-1);
const unsigned int * offsets = _offsets[level-1];
const float * values = _values[level-1];
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<U> vedit(0, 0, 0, 0, 0, _width, false, HbrVertexEdit<U>::Set, const_cast<float*>(&values[i*_width]));
vdst->ApplyVertexEdit(vedit);
} else {
HbrVertexEdit<U> vedit(0, 0, 0, 0, 0, _width, false, HbrVertexEdit<U>::Add, const_cast<float*>(&values[i*_width]));
vdst->ApplyVertexEdit(vedit);
}
}
}
template <class T, class U>
FarVertexEditTables<T,U>::FarVertexEditTables( FarMesh<T,U> * mesh, int maxlevel) :
_mesh(mesh) {
}
template <class T, class U> void
FarVertexEditTables<T,U>::Apply( int level, void * clientdata ) const {
assert(this->_mesh and level>0);
FarDispatcher<T,U> const * dispatch = this->_mesh->GetDispatcher();
assert(dispatch);
dispatch->ApplyVertexEdit(this->_mesh, 0, level, clientdata);
}
template <class T, class U> void
FarVertexEditTables<T,U>::editVertex(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);
}
}
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* FAR_VERTEX_EDIT_TABLES_H */

View File

@ -73,8 +73,8 @@ set(H_FILES
subdivision.h subdivision.h
vertexEdit.h vertexEdit.h
vertex.h vertex.h
) )
install( FILES ${H_FILES} install( FILES ${H_FILES}
DESTINATION include/hbr DESTINATION include/hbr
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ ) PERMISSIONS OWNER_READ GROUP_READ WORLD_READ )

View File

@ -90,7 +90,7 @@ public:
void SetMemStatsIncrement(void (*increment)(unsigned long bytes)) { m_increment = increment; } void SetMemStatsIncrement(void (*increment)(unsigned long bytes)) { m_increment = increment; }
void SetMemStatsDecrement(void (*decrement)(unsigned long bytes)) { m_decrement = decrement; } void SetMemStatsDecrement(void (*decrement)(unsigned long bytes)) { m_decrement = decrement; }
private: private:
size_t *m_memorystat; size_t *m_memorystat;
const int m_blocksize; const int m_blocksize;
@ -111,10 +111,10 @@ private:
HbrMemStatFunction m_increment; HbrMemStatFunction m_increment;
HbrMemStatFunction m_decrement; HbrMemStatFunction m_decrement;
}; };
template <typename T> template <typename T>
HbrAllocator<T>::HbrAllocator(size_t *memorystat, int blocksize, void (*increment)(unsigned long bytes), void (*decrement)(unsigned long bytes), size_t elemsize) HbrAllocator<T>::HbrAllocator(size_t *memorystat, int blocksize, void (*increment)(unsigned long bytes), void (*decrement)(unsigned long bytes), size_t elemsize)
: m_memorystat(memorystat), m_blocksize(blocksize), m_elemsize(elemsize), m_blocks(0), m_nblocks(0), m_blockCapacity(0), m_freecount(0), m_increment(increment), m_decrement(decrement) { : m_memorystat(memorystat), m_blocksize(blocksize), m_elemsize((int)elemsize), m_blocks(0), m_nblocks(0), m_blockCapacity(0), m_freecount(0), m_increment(increment), m_decrement(decrement) {
} }
template <typename T> template <typename T>
@ -125,15 +125,15 @@ HbrAllocator<T>::~HbrAllocator() {
template <typename T> template <typename T>
void HbrAllocator<T>::Clear() { void HbrAllocator<T>::Clear() {
for (int i = 0; i < m_nblocks; ++i) { for (int i = 0; i < m_nblocks; ++i) {
// Run the destructors (placement) // Run the destructors (placement)
T* blockptr = m_blocks[i]; T* blockptr = m_blocks[i];
T* startblock = blockptr; T* startblock = blockptr;
for (int j = 0; j < m_blocksize; ++j) { for (int j = 0; j < m_blocksize; ++j) {
blockptr->~T(); blockptr->~T();
blockptr = (T*) ((char*) blockptr + m_elemsize); blockptr = (T*) ((char*) blockptr + m_elemsize);
} }
free(startblock); free(startblock);
if (m_decrement) m_decrement(m_blocksize * m_elemsize); if (m_decrement) m_decrement(m_blocksize * m_elemsize);
*m_memorystat -= m_blocksize * m_elemsize; *m_memorystat -= m_blocksize * m_elemsize;
} }
free(m_blocks); free(m_blocks);
@ -145,40 +145,40 @@ void HbrAllocator<T>::Clear() {
} }
template <typename T> template <typename T>
T* T*
HbrAllocator<T>::Allocate() { HbrAllocator<T>::Allocate() {
if (!m_freecount) { if (!m_freecount) {
// Allocate a new block // Allocate a new block
T* block = (T*) malloc(m_blocksize * m_elemsize); T* block = (T*) malloc(m_blocksize * m_elemsize);
T* blockptr = block; T* blockptr = block;
// Run the constructors on each element using placement new // Run the constructors on each element using placement new
for (int i = 0; i < m_blocksize; ++i) { for (int i = 0; i < m_blocksize; ++i) {
new (blockptr) T(); new (blockptr) T();
blockptr = (T*) ((char*) blockptr + m_elemsize); blockptr = (T*) ((char*) blockptr + m_elemsize);
} }
if (m_increment) m_increment(m_blocksize * m_elemsize); if (m_increment) m_increment(m_blocksize * m_elemsize);
*m_memorystat += m_blocksize * m_elemsize; *m_memorystat += m_blocksize * m_elemsize;
// Put the block's entries on the free list
blockptr = block;
for (int i = 0; i < m_blocksize - 1; ++i) {
T* next = (T*) ((char*) blockptr + m_elemsize);
blockptr->GetNext() = next;
blockptr = next;
}
blockptr->GetNext() = 0;
m_freelist = block;
// Keep track of the newly allocated block // Put the block's entries on the free list
if (m_nblocks + 1 >= m_blockCapacity) { blockptr = block;
m_blockCapacity = m_blockCapacity * 2; for (int i = 0; i < m_blocksize - 1; ++i) {
if (m_blockCapacity < 1) m_blockCapacity = 1; T* next = (T*) ((char*) blockptr + m_elemsize);
m_blocks = (T**) realloc(m_blocks, m_blockCapacity * sizeof(T*)); blockptr->GetNext() = next;
} blockptr = next;
m_blocks[m_nblocks] = block; }
m_nblocks++; blockptr->GetNext() = 0;
m_freecount += m_blocksize; m_freelist = block;
// Keep track of the newly allocated block
if (m_nblocks + 1 >= m_blockCapacity) {
m_blockCapacity = m_blockCapacity * 2;
if (m_blockCapacity < 1) m_blockCapacity = 1;
m_blocks = (T**) realloc(m_blocks, m_blockCapacity * sizeof(T*));
}
m_blocks[m_nblocks] = block;
m_nblocks++;
m_freecount += m_blocksize;
} }
T* obj = m_freelist; T* obj = m_freelist;
m_freelist = obj->GetNext(); m_freelist = obj->GetNext();

View File

@ -69,29 +69,30 @@ template <class T>
class HbrBilinearSubdivision : public HbrSubdivision<T> { class HbrBilinearSubdivision : public HbrSubdivision<T> {
public: public:
HbrBilinearSubdivision<T>() HbrBilinearSubdivision<T>()
: HbrSubdivision<T>() {} : HbrSubdivision<T>() {}
virtual HbrSubdivision<T>* Clone() const { virtual HbrSubdivision<T>* Clone() const {
return new HbrBilinearSubdivision<T>(); return new HbrBilinearSubdivision<T>();
} }
virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face); virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face);
virtual HbrFace<T>* RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex); virtual HbrFace<T>* RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex);
virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge); virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
virtual void GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex); virtual void GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
virtual bool HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face); virtual bool HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face);
virtual bool HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge); virtual bool HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
virtual bool HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex); virtual bool HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face); virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face);
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge); virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex); virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
virtual bool VertexIsExtraordinary(HbrMesh<T>* /* mesh */, HbrVertex<T>* vertex) { return vertex->GetValence() != 4; } virtual bool VertexIsExtraordinary(HbrMesh<T>* /* mesh */, HbrVertex<T>* vertex) { return vertex->GetValence() != 4; }
virtual bool FaceIsExtraordinary(HbrMesh<T>* /* mesh */, HbrFace<T>* face) { return face->GetNumVertices() != 4; }
virtual int GetFaceChildrenCount(int nvertices) const { return nvertices; } virtual int GetFaceChildrenCount(int nvertices) const { return nvertices; }
private: private:
// Transfers facevarying data from a parent face to a child face // Transfers facevarying data from a parent face to a child face
@ -143,14 +144,14 @@ HbrBilinearSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* fac
// allocate a new block of facevarying storage specific to the // allocate a new block of facevarying storage specific to the
// child face. // child face.
bool fv0IsSmooth, fv1IsSmooth, fv3IsSmooth; bool fv0IsSmooth, fv1IsSmooth, fv3IsSmooth;
childVertex = child->GetVertex(extraordinary ? 0 : (index+0)%4); childVertex = child->GetVertex(extraordinary ? 0 : (index+0)%4);
fv0IsSmooth = v->IsFVarAllSmooth(); fv0IsSmooth = v->IsFVarAllSmooth();
if (!fv0IsSmooth) { if (!fv0IsSmooth) {
childVertex->NewFVarData(child); childVertex->NewFVarData(child);
} }
HbrFVarData<T>& fv0 = childVertex->GetFVarData(child); HbrFVarData<T>& fv0 = childVertex->GetFVarData(child);
edge = face->GetEdge(index); edge = face->GetEdge(index);
GuaranteeNeighbor(mesh, edge); GuaranteeNeighbor(mesh, edge);
assert(edge->GetOrgVertex() == v); assert(edge->GetOrgVertex() == v);
@ -162,7 +163,7 @@ HbrBilinearSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* fac
HbrFVarData<T>& fv1 = childVertex->GetFVarData(child); HbrFVarData<T>& fv1 = childVertex->GetFVarData(child);
edge = edge->GetPrev(); edge = edge->GetPrev();
GuaranteeNeighbor(mesh, edge); GuaranteeNeighbor(mesh, edge);
assert(edge == face->GetEdge((index + nv - 1) % nv)); assert(edge == face->GetEdge((index + nv - 1) % nv));
assert(edge->GetDestVertex() == v); assert(edge->GetDestVertex() == v);
childVertex = child->GetVertex(extraordinary ? 3 : (index+3)%4); childVertex = child->GetVertex(extraordinary ? 3 : (index+3)%4);
@ -314,7 +315,7 @@ HbrBilinearSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* fac
starte = bestedge; starte = bestedge;
w = 0; w = 0;
if (HbrHalfedge<T>* e = starte) { if (HbrHalfedge<T>* e = starte) {
assert(starte->GetOrgVertex() == v); assert(starte->GetOrgVertex() == v);
do { do {
if (e->GetFVarSharpness(fvaritem) || !e->GetRightFace()) { if (e->GetFVarSharpness(fvaritem) || !e->GetRightFace()) {
bestface = e->GetLeftFace(); bestface = e->GetLeftFace();
@ -331,7 +332,7 @@ HbrBilinearSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* fac
} }
assert(j != bestface->GetNumVertices()); assert(j != bestface->GetNumVertices());
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f); fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
} }
// Smooth rule. Here, we can take a shortcut if we know that // Smooth rule. Here, we can take a shortcut if we know that
// the vertex is smooth and some other vertex has completely // the vertex is smooth and some other vertex has completely
@ -388,7 +389,7 @@ HbrBilinearSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* fac
fv1.AddWithWeight(oppFace->GetFVarData(j), fvarindex, fvarwidth, weight); fv1.AddWithWeight(oppFace->GetFVarData(j), fvarindex, fvarwidth, weight);
} }
} }
// Edge subdivision rule // Edge subdivision rule
edge = edge->GetPrev(); edge = edge->GetPrev();
@ -396,11 +397,11 @@ HbrBilinearSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* fac
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone || if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) { edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) {
// Sharp edge rule // Sharp edge rule
fv3.SetWithWeight(face->GetFVarData((index + nv - 1) % nv), fvarindex, fvarwidth, 0.5f); fv3.SetWithWeight(face->GetFVarData((index + nv - 1) % nv), fvarindex, fvarwidth, 0.5f);
fv3.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f); fv3.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f);
} else if (!fv3IsSmooth || !fv3.IsInitialized()) { } else if (!fv3IsSmooth || !fv3.IsInitialized()) {
// Smooth edge subdivision. Add 0.25 of adjacent vertices // Smooth edge subdivision. Add 0.25 of adjacent vertices
fv3.SetWithWeight(face->GetFVarData((index + nv - 1) % nv), fvarindex, fvarwidth, 0.25f); fv3.SetWithWeight(face->GetFVarData((index + nv - 1) % nv), fvarindex, fvarwidth, 0.25f);
fv3.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.25f); fv3.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.25f);
// Local subdivided face vertex // Local subdivided face vertex
@ -418,13 +419,6 @@ HbrBilinearSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* fac
fv0.SetInitialized(); fv0.SetInitialized();
fv1.SetInitialized(); fv1.SetInitialized();
fv3.SetInitialized(); fv3.SetInitialized();
// Special handling of ptex index for extraordinary faces: make
// sure the children get their indices reassigned to be
// consecutive within the block reserved for the parent.
if (face->GetNumVertices() != 4 && face->GetPtexIndex() != -1) {
child->SetPtexIndex(face->GetPtexIndex() + index);
}
} }
template <class T> template <class T>
@ -433,15 +427,15 @@ HbrBilinearSubdivision<T>::transferEditsToChild(HbrFace<T>* face, HbrFace<T>* ch
// Hand down pointers to hierarchical edits // Hand down pointers to hierarchical edits
if (HbrHierarchicalEdit<T>** edits = face->GetHierarchicalEdits()) { if (HbrHierarchicalEdit<T>** edits = face->GetHierarchicalEdits()) {
while (HbrHierarchicalEdit<T>* edit = *edits) { while (HbrHierarchicalEdit<T>* edit = *edits) {
if (!edit->IsRelevantToFace(face)) break; if (!edit->IsRelevantToFace(face)) break;
if (edit->GetNSubfaces() > face->GetDepth() && if (edit->GetNSubfaces() > face->GetDepth() &&
(edit->GetSubface(face->GetDepth()) == index)) { (edit->GetSubface(face->GetDepth()) == index)) {
child->SetHierarchicalEdits(edits); child->SetHierarchicalEdits(edits);
break; break;
} }
edits++; edits++;
} }
} }
} }
@ -464,50 +458,57 @@ HbrBilinearSubdivision<T>::Refine(HbrMesh<T>* mesh, HbrFace<T>* face) {
// parametric space through the refinement. If we split an // parametric space through the refinement. If we split an
// extraordinary face then it doesn't matter. // extraordinary face then it doesn't matter.
for (int i = 0; i < nv; ++i) { for (int i = 0; i < nv; ++i) {
if (!face->GetChild(i)) { if (!face->GetChild(i)) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Kid " << i << "\n"; std::cerr << "Kid " << i << "\n";
#endif #endif
HbrVertex<T>* vertex = edge->GetOrgVertex(); HbrVertex<T>* vertex = edge->GetOrgVertex();
if (extraordinary) { if (extraordinary) {
vertices[0] = vertex->Subdivide(); vertices[0] = vertex->Subdivide();
vertices[1] = edge->Subdivide(); vertices[1] = edge->Subdivide();
vertices[2] = face->Subdivide(); vertices[2] = face->Subdivide();
vertices[3] = prevedge->Subdivide(); vertices[3] = prevedge->Subdivide();
} else { } else {
vertices[i] = vertex->Subdivide(); vertices[i] = vertex->Subdivide();
vertices[(i+1)%4] = edge->Subdivide(); vertices[(i+1)%4] = edge->Subdivide();
vertices[(i+2)%4] = face->Subdivide(); vertices[(i+2)%4] = face->Subdivide();
vertices[(i+3)%4] = prevedge->Subdivide(); vertices[(i+3)%4] = prevedge->Subdivide();
} }
child = mesh->NewFace(4, vertices, face, i); child = mesh->NewFace(4, vertices, face, i);
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Creating face " << *child << " during refine\n"; std::cerr << "Creating face " << *child << " during refine\n";
#endif #endif
// Hand down edge sharpnesses // Hand down edge sharpnesses
childedge = vertex->Subdivide()->GetEdge(edge->Subdivide()); childedge = vertex->Subdivide()->GetEdge(edge->Subdivide());
assert(childedge); assert(childedge);
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) { if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
SubdivideCreaseWeight(edge, edge->GetDestVertex(), childedge); HbrSubdivision<T>::SubdivideCreaseWeight(edge, edge->GetDestVertex(), childedge);
} }
childedge->CopyFVarInfiniteSharpness(edge); childedge->CopyFVarInfiniteSharpness(edge);
childedge = prevedge->Subdivide()->GetEdge(vertex->Subdivide()); childedge = prevedge->Subdivide()->GetEdge(vertex->Subdivide());
assert(childedge); assert(childedge);
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) { if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
SubdivideCreaseWeight(prevedge, prevedge->GetOrgVertex(), childedge); HbrSubdivision<T>::SubdivideCreaseWeight(prevedge, prevedge->GetOrgVertex(), childedge);
} }
childedge->CopyFVarInfiniteSharpness(prevedge); childedge->CopyFVarInfiniteSharpness(prevedge);
if (mesh->GetTotalFVarWidth()) { if (mesh->GetTotalFVarWidth()) {
transferFVarToChild(mesh, face, child, i); transferFVarToChild(mesh, face, child, i);
} }
transferEditsToChild(face, child, i); // Special handling of ptex index for extraordinary faces: make
} // sure the children get their indices reassigned to be
prevedge = edge; // consecutive within the block reserved for the parent.
edge = edge->GetNext(); if (face->GetNumVertices() != 4 && face->GetPtexIndex() != -1) {
child->SetPtexIndex(face->GetPtexIndex() + i);
}
transferEditsToChild(face, child, i);
}
prevedge = edge;
edge = edge->GetNext();
} }
} }
@ -518,72 +519,79 @@ HbrBilinearSubdivision<T>::RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << " forcing refine on " << *face << " at " << *vertex << '\n'; std::cerr << " forcing refine on " << *face << " at " << *vertex << '\n';
#endif #endif
// Create new quadrilateral children faces from this face // Create new quadrilateral children faces from this face
HbrHalfedge<T>* edge = face->GetFirstEdge(); HbrHalfedge<T>* edge = face->GetFirstEdge();
HbrHalfedge<T>* prevedge = edge->GetPrev(); HbrHalfedge<T>* prevedge = edge->GetPrev();
HbrHalfedge<T>* childedge; HbrHalfedge<T>* childedge;
int nv = face->GetNumVertices(); int nv = face->GetNumVertices();
float sharpness; float sharpness;
bool extraordinary = (nv != 4); bool extraordinary = (nv != 4);
// The funny indexing on vertices is done only for // The funny indexing on vertices is done only for
// non-extraordinary faces in order to correctly preserve // non-extraordinary faces in order to correctly preserve
// parametric space through the refinement. If we split an // parametric space through the refinement. If we split an
// extraordinary face then it doesn't matter. // extraordinary face then it doesn't matter.
for (int i = 0; i < nv; ++i) { for (int i = 0; i < nv; ++i) {
if (edge->GetOrgVertex() == vertex) { if (edge->GetOrgVertex() == vertex) {
if (!face->GetChild(i)) { if (!face->GetChild(i)) {
HbrFace<T>* child; HbrFace<T>* child;
HbrVertex<T>* vertices[4]; HbrVertex<T>* vertices[4];
if (extraordinary) { if (extraordinary) {
vertices[0] = vertex->Subdivide(); vertices[0] = vertex->Subdivide();
vertices[1] = edge->Subdivide(); vertices[1] = edge->Subdivide();
vertices[2] = face->Subdivide(); vertices[2] = face->Subdivide();
vertices[3] = prevedge->Subdivide(); vertices[3] = prevedge->Subdivide();
} else { } else {
vertices[i] = vertex->Subdivide(); vertices[i] = vertex->Subdivide();
vertices[(i+1)%4] = edge->Subdivide(); vertices[(i+1)%4] = edge->Subdivide();
vertices[(i+2)%4] = face->Subdivide(); vertices[(i+2)%4] = face->Subdivide();
vertices[(i+3)%4] = prevedge->Subdivide(); vertices[(i+3)%4] = prevedge->Subdivide();
} }
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Kid " << i << "\n"; std::cerr << "Kid " << i << "\n";
std::cerr << " subdivision created " << *vertices[0] << '\n'; std::cerr << " subdivision created " << *vertices[0] << '\n';
std::cerr << " subdivision created " << *vertices[1] << '\n'; std::cerr << " subdivision created " << *vertices[1] << '\n';
std::cerr << " subdivision created " << *vertices[2] << '\n'; std::cerr << " subdivision created " << *vertices[2] << '\n';
std::cerr << " subdivision created " << *vertices[3] << '\n'; std::cerr << " subdivision created " << *vertices[3] << '\n';
#endif #endif
child = mesh->NewFace(4, vertices, face, i); child = mesh->NewFace(4, vertices, face, i);
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Creating face " << *child << " during refine\n"; std::cerr << "Creating face " << *child << " during refine\n";
#endif #endif
// Hand down edge sharpness // Hand down edge sharpness
childedge = vertex->Subdivide()->GetEdge(edge->Subdivide()); childedge = vertex->Subdivide()->GetEdge(edge->Subdivide());
assert(childedge); assert(childedge);
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) { if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
SubdivideCreaseWeight(edge, edge->GetDestVertex(), childedge); HbrSubdivision<T>::SubdivideCreaseWeight(edge, edge->GetDestVertex(), childedge);
} }
childedge->CopyFVarInfiniteSharpness(edge); childedge->CopyFVarInfiniteSharpness(edge);
childedge = prevedge->Subdivide()->GetEdge(vertex->Subdivide()); childedge = prevedge->Subdivide()->GetEdge(vertex->Subdivide());
assert(childedge); assert(childedge);
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) { if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
SubdivideCreaseWeight(prevedge, prevedge->GetOrgVertex(), childedge); HbrSubdivision<T>::SubdivideCreaseWeight(prevedge, prevedge->GetOrgVertex(), childedge);
} }
childedge->CopyFVarInfiniteSharpness(prevedge); childedge->CopyFVarInfiniteSharpness(prevedge);
if (mesh->GetTotalFVarWidth()) { if (mesh->GetTotalFVarWidth()) {
transferFVarToChild(mesh, face, child, i); transferFVarToChild(mesh, face, child, i);
} }
transferEditsToChild(face, child, i); // Special handling of ptex index for extraordinary faces: make
return child; // sure the children get their indices reassigned to be
} else { // consecutive within the block reserved for the parent.
return face->GetChild(i); if (face->GetNumVertices() != 4 && face->GetPtexIndex() != -1) {
} child->SetPtexIndex(face->GetPtexIndex() + i);
} }
prevedge = edge;
edge = edge->GetNext(); transferEditsToChild(face, child, i);
return child;
} else {
return face->GetChild(i);
}
}
prevedge = edge;
edge = edge->GetNext();
} }
return 0; return 0;
} }
@ -592,7 +600,7 @@ template <class T>
void void
HbrBilinearSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) { HbrBilinearSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
if (edge->GetOpposite()) { if (edge->GetOpposite()) {
return; return;
} }
// For the given edge: if the parent of either of its incident // For the given edge: if the parent of either of its incident
@ -604,83 +612,83 @@ HbrBilinearSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* e
HbrFace<T>* parentFace = edge->GetOrgVertex()->GetParentFace(); HbrFace<T>* parentFace = edge->GetOrgVertex()->GetParentFace();
HbrHalfedge<T>* parentEdge = edge->GetDestVertex()->GetParentEdge(); HbrHalfedge<T>* parentEdge = edge->GetDestVertex()->GetParentEdge();
if (!parentFace) { if (!parentFace) {
destParentWasEdge = false; destParentWasEdge = false;
parentFace = edge->GetDestVertex()->GetParentFace(); parentFace = edge->GetDestVertex()->GetParentFace();
parentEdge = edge->GetOrgVertex()->GetParentEdge(); parentEdge = edge->GetOrgVertex()->GetParentEdge();
} }
if (parentFace) { if (parentFace) {
// Make sure we deal with a parent halfedge which is // Make sure we deal with a parent halfedge which is
// associated with the parent face // associated with the parent face
if (parentEdge->GetFace() != parentFace) { if (parentEdge->GetFace() != parentFace) {
parentEdge = parentEdge->GetOpposite(); parentEdge = parentEdge->GetOpposite();
} }
// If one of the vertices had a parent face, the other one MUST // If one of the vertices had a parent face, the other one MUST
// have been a child of an edge // have been a child of an edge
assert(parentEdge && parentEdge->GetFace() == parentFace); assert(parentEdge && parentEdge->GetFace() == parentFace);
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "\nparent edge is " << *parentEdge << "\n"; std::cerr << "\nparent edge is " << *parentEdge << "\n";
#endif #endif
// The vertex to refine at depends on whether the // The vertex to refine at depends on whether the
// destination or origin vertex of this edge had a parent // destination or origin vertex of this edge had a parent
// edge // edge
if (destParentWasEdge) { if (destParentWasEdge) {
RefineFaceAtVertex(mesh, parentFace, parentEdge->GetOrgVertex()); RefineFaceAtVertex(mesh, parentFace, parentEdge->GetOrgVertex());
} else { } else {
RefineFaceAtVertex(mesh, parentFace, parentEdge->GetDestVertex()); RefineFaceAtVertex(mesh, parentFace, parentEdge->GetDestVertex());
} }
// It should always be the case that the opposite now exists - // It should always be the case that the opposite now exists -
// we can't have a boundary case here // we can't have a boundary case here
assert(edge->GetOpposite()); assert(edge->GetOpposite());
} else { } else {
HbrVertex<T>* parentVertex = edge->GetOrgVertex()->GetParentVertex(); HbrVertex<T>* parentVertex = edge->GetOrgVertex()->GetParentVertex();
parentEdge = edge->GetDestVertex()->GetParentEdge(); parentEdge = edge->GetDestVertex()->GetParentEdge();
if (!parentVertex) { if (!parentVertex) {
parentVertex = edge->GetDestVertex()->GetParentVertex(); parentVertex = edge->GetDestVertex()->GetParentVertex();
parentEdge = edge->GetOrgVertex()->GetParentEdge(); parentEdge = edge->GetOrgVertex()->GetParentEdge();
} }
if (parentVertex) { if (parentVertex) {
assert(parentEdge); assert(parentEdge);
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "\nparent edge is " << *parentEdge << "\n"; std::cerr << "\nparent edge is " << *parentEdge << "\n";
#endif #endif
// 1. Go up to the parent of my face
parentFace = edge->GetFace()->GetParent(); // 1. Go up to the parent of my face
parentFace = edge->GetFace()->GetParent();
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "\nparent face is " << *parentFace << "\n"; std::cerr << "\nparent face is " << *parentFace << "\n";
#endif #endif
// 2. Ask the opposite face (if it exists) to refine // 2. Ask the opposite face (if it exists) to refine
if (parentFace) { if (parentFace) {
// A vertex can be associated with either of two // A vertex can be associated with either of two
// parent halfedges. If the parent edge that we're // parent halfedges. If the parent edge that we're
// interested in doesn't match then we should look at // interested in doesn't match then we should look at
// its opposite // its opposite
if (parentEdge->GetFace() != parentFace) if (parentEdge->GetFace() != parentFace)
parentEdge = parentEdge->GetOpposite(); parentEdge = parentEdge->GetOpposite();
assert(parentEdge->GetFace() == parentFace); assert(parentEdge->GetFace() == parentFace);
// Make sure the parent edge has its neighbor as well // Make sure the parent edge has its neighbor as well
GuaranteeNeighbor(mesh, parentEdge); GuaranteeNeighbor(mesh, parentEdge);
// Now access that neighbor and refine it // Now access that neighbor and refine it
if (parentEdge->GetRightFace()) { if (parentEdge->GetRightFace()) {
RefineFaceAtVertex(mesh, parentEdge->GetRightFace(), parentVertex); RefineFaceAtVertex(mesh, parentEdge->GetRightFace(), parentVertex);
// FIXME: assertion? // FIXME: assertion?
assert(edge->GetOpposite()); assert(edge->GetOpposite());
} }
} }
} }
} }
} }
@ -699,10 +707,10 @@ HbrBilinearSubdivision<T>::GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* ve
if (parentFace) { if (parentFace) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << " forcing full refine on parent face\n"; std::cerr << " forcing full refine on parent face\n";
#endif #endif
Refine(mesh, parentFace); Refine(mesh, parentFace);
return; return;
} }
// Otherwise if the vertex is a child of an edge, we need to // Otherwise if the vertex is a child of an edge, we need to
@ -713,29 +721,29 @@ HbrBilinearSubdivision<T>::GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* ve
if (parentEdge) { if (parentEdge) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << " forcing full refine on adjacent faces of parent edge\n"; std::cerr << " forcing full refine on adjacent faces of parent edge\n";
#endif #endif
HbrVertex<T>* dest = parentEdge->GetDestVertex(); HbrVertex<T>* dest = parentEdge->GetDestVertex();
HbrVertex<T>* org = parentEdge->GetOrgVertex(); HbrVertex<T>* org = parentEdge->GetOrgVertex();
GuaranteeNeighbor(mesh, parentEdge); GuaranteeNeighbor(mesh, parentEdge);
parentFace = parentEdge->GetLeftFace(); parentFace = parentEdge->GetLeftFace();
RefineFaceAtVertex(mesh, parentFace, dest); RefineFaceAtVertex(mesh, parentFace, dest);
RefineFaceAtVertex(mesh, parentFace, org); RefineFaceAtVertex(mesh, parentFace, org);
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << " on the right face?\n"; std::cerr << " on the right face?\n";
#endif #endif
parentFace = parentEdge->GetRightFace(); parentFace = parentEdge->GetRightFace();
// The right face may not necessarily exist even after // The right face may not necessarily exist even after
// GuaranteeNeighbor // GuaranteeNeighbor
if (parentFace) { if (parentFace) {
RefineFaceAtVertex(mesh, parentFace, dest); RefineFaceAtVertex(mesh, parentFace, dest);
RefineFaceAtVertex(mesh, parentFace, org); RefineFaceAtVertex(mesh, parentFace, org);
} }
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << " end force\n"; std::cerr << " end force\n";
#endif #endif
return; return;
} }
// The last case: the vertex is a child of a vertex. In this case // The last case: the vertex is a child of a vertex. In this case
@ -745,20 +753,20 @@ HbrBilinearSubdivision<T>::GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* ve
if (parentVertex) { if (parentVertex) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << " recursive parent vertex guarantee call\n"; std::cerr << " recursive parent vertex guarantee call\n";
#endif #endif
parentVertex->GuaranteeNeighbors(); parentVertex->GuaranteeNeighbors();
// And then we refine all the face neighbors of the // And then we refine all the face neighbors of the
// parentVertex // parentVertex
HbrHalfedge<T>* start = parentVertex->GetIncidentEdge(), *edge; HbrHalfedge<T>* start = parentVertex->GetIncidentEdge(), *edge;
edge = start; edge = start;
while (edge) { while (edge) {
HbrFace<T>* f = edge->GetLeftFace(); HbrFace<T>* f = edge->GetLeftFace();
RefineFaceAtVertex(mesh, f, parentVertex); RefineFaceAtVertex(mesh, f, parentVertex);
edge = parentVertex->GetNextEdge(edge); edge = parentVertex->GetNextEdge(edge);
if (edge == start) break; if (edge == start) break;
} }
} }
} }
@ -769,9 +777,9 @@ HbrBilinearSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face) {
if (face->IsHole()) return false; if (face->IsHole()) return false;
// A limit face exists if all the bounding edges have limit curves // A limit face exists if all the bounding edges have limit curves
for (int i = 0; i < face->GetNumVertices(); ++i) { for (int i = 0; i < face->GetNumVertices(); ++i) {
if (!HasLimit(mesh, face->GetEdge(i))) { if (!HasLimit(mesh, face->GetEdge(i))) {
return false; return false;
} }
} }
return true; return true;
} }
@ -787,14 +795,14 @@ bool
HbrBilinearSubdivision<T>::HasLimit(HbrMesh<T>* /* mesh */, HbrVertex<T>* vertex) { HbrBilinearSubdivision<T>::HasLimit(HbrMesh<T>* /* mesh */, HbrVertex<T>* vertex) {
vertex->GuaranteeNeighbors(); vertex->GuaranteeNeighbors();
switch (vertex->GetMask(false)) { switch (vertex->GetMask(false)) {
case HbrVertex<T>::k_Smooth: case HbrVertex<T>::k_Smooth:
case HbrVertex<T>::k_Dart: case HbrVertex<T>::k_Dart:
return !vertex->OnBoundary(); return !vertex->OnBoundary();
break; break;
case HbrVertex<T>::k_Crease: case HbrVertex<T>::k_Crease:
case HbrVertex<T>::k_Corner: case HbrVertex<T>::k_Corner:
default: default:
return true; return true;
} }
} }
@ -803,22 +811,22 @@ HbrVertex<T>*
HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) { HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) {
// Face rule: simply average all vertices on the face // Face rule: simply average all vertices on the face
HbrVertex<T>* v = mesh->NewVertex(); HbrVertex<T>* v = mesh->NewVertex();
T& data = v->GetData(); T& data = v->GetData();
int nv = face->GetNumVertices(); int nv = face->GetNumVertices();
float weight = 1.0f / nv; float weight = 1.0f / nv;
HbrHalfedge<T>* edge = face->GetFirstEdge(); HbrHalfedge<T>* edge = face->GetFirstEdge();
for (int i = 0; i < face->GetNumVertices(); ++i) { for (int i = 0; i < face->GetNumVertices(); ++i) {
HbrVertex<T>* w = edge->GetOrgVertex(); HbrVertex<T>* w = edge->GetOrgVertex();
// If there are vertex edits we have to make sure the edit // If there are vertex edits we have to make sure the edit
// has been applied // has been applied
if (mesh->HasVertexEdits()) { if (mesh->HasVertexEdits()) {
w->GuaranteeNeighbors(); w->GuaranteeNeighbors();
} }
data.AddWithWeight(w->GetData(), weight); data.AddWithWeight(w->GetData(), weight);
data.AddVaryingWithWeight(w->GetData(), weight); data.AddVaryingWithWeight(w->GetData(), weight);
edge = edge->GetNext(); edge = edge->GetNext();
} }
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Subdividing at " << *face << "\n"; std::cerr << "Subdividing at " << *face << "\n";
@ -827,7 +835,7 @@ HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) {
// Set the extraordinary flag if the face had anything other than // Set the extraordinary flag if the face had anything other than
// 4 vertices // 4 vertices
if (nv != 4) v->SetExtraordinary(); if (nv != 4) v->SetExtraordinary();
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << " created " << *v << "\n"; std::cerr << " created " << *v << "\n";
#endif #endif
@ -842,7 +850,7 @@ HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
float esharp = edge->GetSharpness(); float esharp = edge->GetSharpness();
std::cerr << "Subdividing at " << *edge << " (sharpness = " << esharp << ")"; std::cerr << "Subdividing at " << *edge << " (sharpness = " << esharp << ")";
#endif #endif
HbrVertex<T>* v = mesh->NewVertex(); HbrVertex<T>* v = mesh->NewVertex();
T& data = v->GetData(); T& data = v->GetData();
@ -852,14 +860,14 @@ HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
if (mesh->HasCreaseEdits()) { if (mesh->HasCreaseEdits()) {
edge->GuaranteeNeighbor(); edge->GuaranteeNeighbor();
} }
// If there's the possibility of vertex edits on either vertex, we // If there's the possibility of vertex edits on either vertex, we
// have to make sure the edit has been applied // have to make sure the edit has been applied
if (mesh->HasVertexEdits()) { if (mesh->HasVertexEdits()) {
edge->GetOrgVertex()->GuaranteeNeighbors(); edge->GetOrgVertex()->GuaranteeNeighbors();
edge->GetDestVertex()->GuaranteeNeighbors(); edge->GetDestVertex()->GuaranteeNeighbors();
} }
// Average the two end points // Average the two end points
data.AddWithWeight(edge->GetOrgVertex()->GetData(), 0.5f); data.AddWithWeight(edge->GetOrgVertex()->GetData(), 0.5f);
data.AddWithWeight(edge->GetDestVertex()->GetData(), 0.5f); data.AddWithWeight(edge->GetDestVertex()->GetData(), 0.5f);
@ -879,7 +887,7 @@ HbrVertex<T>*
HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) { HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
HbrVertex<T>* v; HbrVertex<T>* v;
// If there are vertex edits we have to make sure the edit has // If there are vertex edits we have to make sure the edit has
// been applied by guaranteeing the neighbors of the // been applied by guaranteeing the neighbors of the
// vertex. Unfortunately in this case, we can't share the data // vertex. Unfortunately in this case, we can't share the data
@ -889,37 +897,37 @@ HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
v = mesh->NewVertex(); v = mesh->NewVertex();
T& data = v->GetData(); T& data = v->GetData();
// Just copy the old value // Just copy the old value
data.AddWithWeight(vertex->GetData(), 1.0f); data.AddWithWeight(vertex->GetData(), 1.0f);
// Varying data is always just propogated down // Varying data is always just propagated down
data.AddVaryingWithWeight(vertex->GetData(), 1.0f); data.AddVaryingWithWeight(vertex->GetData(), 1.0f);
} else { } else {
// Create a new vertex that just shares the same data // Create a new vertex that just shares the same data
v = mesh->NewVertex(vertex->GetData()); v = mesh->NewVertex(vertex->GetData());
} }
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Subdividing at " << *vertex << "\n"; std::cerr << "Subdividing at " << *vertex << "\n";
std::cerr << " created " << *v << "\n"; std::cerr << " created " << *v << "\n";
#endif #endif
// Inherit extraordinary flag and sharpness // Inherit extraordinary flag and sharpness
if (vertex->IsExtraordinary()) v->SetExtraordinary(); if (vertex->IsExtraordinary()) v->SetExtraordinary();
float sharp = vertex->GetSharpness(); float sharp = vertex->GetSharpness();
if (sharp >= HbrVertex<T>::k_InfinitelySharp) { if (sharp >= HbrVertex<T>::k_InfinitelySharp) {
v->SetSharpness(HbrVertex<T>::k_InfinitelySharp); v->SetSharpness(HbrVertex<T>::k_InfinitelySharp);
} else if (sharp > HbrVertex<T>::k_Smooth) { } else if (sharp > HbrVertex<T>::k_Smooth) {
sharp -= 1.0f; sharp -= 1.0f;
if (sharp < (float) HbrVertex<T>::k_Smooth) { if (sharp < (float) HbrVertex<T>::k_Smooth) {
sharp = (float) HbrVertex<T>::k_Smooth; sharp = (float) HbrVertex<T>::k_Smooth;
} }
v->SetSharpness(sharp); v->SetSharpness(sharp);
} else { } else {
v->SetSharpness(HbrVertex<T>::k_Smooth); v->SetSharpness(HbrVertex<T>::k_Smooth);
} }
return v; return v;
} }
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION

View File

@ -69,29 +69,30 @@ template <class T>
class HbrCatmarkSubdivision : public HbrSubdivision<T> { class HbrCatmarkSubdivision : public HbrSubdivision<T> {
public: public:
HbrCatmarkSubdivision<T>() HbrCatmarkSubdivision<T>()
: HbrSubdivision<T>(), triangleSubdivision(k_Normal) {} : HbrSubdivision<T>(), triangleSubdivision(k_Normal) {}
HbrCatmarkSubdivision<T>(const HbrCatmarkSubdivision<T> &old) HbrCatmarkSubdivision<T>(const HbrCatmarkSubdivision<T> &old)
: HbrSubdivision<T>(), triangleSubdivision(old.triangleSubdivision) {} : HbrSubdivision<T>(), triangleSubdivision(old.triangleSubdivision) {}
virtual HbrSubdivision<T>* Clone() const { virtual HbrSubdivision<T>* Clone() const {
return new HbrCatmarkSubdivision<T>(*this); return new HbrCatmarkSubdivision<T>(*this);
} }
virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face); virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face);
virtual HbrFace<T>* RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex); virtual HbrFace<T>* RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex);
virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge); virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
virtual void GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex); virtual void GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
virtual bool HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face); virtual bool HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face);
virtual bool HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge); virtual bool HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
virtual bool HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex); virtual bool HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face); virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face);
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge); virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex); virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
virtual bool VertexIsExtraordinary(HbrMesh<T>* /* mesh */, HbrVertex<T>* vertex) { return vertex->GetValence() != 4; } virtual bool VertexIsExtraordinary(HbrMesh<T>* /* mesh */, HbrVertex<T>* vertex) { return vertex->GetValence() != 4; }
virtual bool FaceIsExtraordinary(HbrMesh<T>* /* mesh */, HbrFace<T>* face) { return face->GetNumVertices() != 4; }
// Triangle subdivision rules, which modifies the rules for // Triangle subdivision rules, which modifies the rules for
// triangular faces in order to make them smoother. The "normal" // triangular faces in order to make them smoother. The "normal"
@ -103,15 +104,15 @@ public:
// triangular; after one level of refinement everything becomes // triangular; after one level of refinement everything becomes
// quads. // quads.
enum TriangleSubdivision { enum TriangleSubdivision {
k_Normal, k_Normal,
k_Old, k_Old,
k_New k_New
}; };
TriangleSubdivision GetTriangleSubdivisionMethod() const { return triangleSubdivision; } TriangleSubdivision GetTriangleSubdivisionMethod() const { return triangleSubdivision; }
void SetTriangleSubdivisionMethod(TriangleSubdivision method) { triangleSubdivision = method; } void SetTriangleSubdivisionMethod(TriangleSubdivision method) { triangleSubdivision = method; }
virtual int GetFaceChildrenCount(int nvertices) const { return nvertices; } virtual int GetFaceChildrenCount(int nvertices) const { return nvertices; }
private: private:
// Transfers facevarying data from a parent face to a child face // Transfers facevarying data from a parent face to a child face
@ -119,7 +120,7 @@ private:
// Transfers vertex and edge edits from a parent face to a child face // Transfers vertex and edge edits from a parent face to a child face
void transferEditsToChild(HbrFace<T>* face, HbrFace<T>* child, int index); void transferEditsToChild(HbrFace<T>* face, HbrFace<T>* child, int index);
TriangleSubdivision triangleSubdivision; TriangleSubdivision triangleSubdivision;
}; };
@ -164,14 +165,14 @@ HbrCatmarkSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face
// allocate a new block of facevarying storage specific to the // allocate a new block of facevarying storage specific to the
// child face. // child face.
bool fv0IsSmooth, fv1IsSmooth, fv3IsSmooth; bool fv0IsSmooth, fv1IsSmooth, fv3IsSmooth;
childVertex = child->GetVertex(extraordinary ? 0 : (index+0)%4); childVertex = child->GetVertex(extraordinary ? 0 : (index+0)%4);
fv0IsSmooth = v->IsFVarAllSmooth(); fv0IsSmooth = v->IsFVarAllSmooth();
if (!fv0IsSmooth) { if (!fv0IsSmooth) {
childVertex->NewFVarData(child); childVertex->NewFVarData(child);
} }
HbrFVarData<T>& fv0 = childVertex->GetFVarData(child); HbrFVarData<T>& fv0 = childVertex->GetFVarData(child);
edge = face->GetEdge(index); edge = face->GetEdge(index);
GuaranteeNeighbor(mesh, edge); GuaranteeNeighbor(mesh, edge);
assert(edge->GetOrgVertex() == v); assert(edge->GetOrgVertex() == v);
@ -183,7 +184,7 @@ HbrCatmarkSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face
HbrFVarData<T>& fv1 = childVertex->GetFVarData(child); HbrFVarData<T>& fv1 = childVertex->GetFVarData(child);
edge = edge->GetPrev(); edge = edge->GetPrev();
GuaranteeNeighbor(mesh, edge); GuaranteeNeighbor(mesh, edge);
assert(edge == face->GetEdge((index + nv - 1) % nv)); assert(edge == face->GetEdge((index + nv - 1) % nv));
assert(edge->GetDestVertex() == v); assert(edge->GetDestVertex() == v);
childVertex = child->GetVertex(extraordinary ? 3 : (index+3)%4); childVertex = child->GetVertex(extraordinary ? 3 : (index+3)%4);
@ -335,7 +336,7 @@ HbrCatmarkSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face
starte = bestedge; starte = bestedge;
w = 0; w = 0;
if (HbrHalfedge<T>* e = starte) { if (HbrHalfedge<T>* e = starte) {
assert(starte->GetOrgVertex() == v); assert(starte->GetOrgVertex() == v);
do { do {
if (e->GetFVarSharpness(fvaritem) || !e->GetRightFace()) { if (e->GetFVarSharpness(fvaritem) || !e->GetRightFace()) {
bestface = e->GetLeftFace(); bestface = e->GetLeftFace();
@ -352,7 +353,7 @@ HbrCatmarkSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face
} }
assert(j != bestface->GetNumVertices()); assert(j != bestface->GetNumVertices());
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f); fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
} }
// Smooth rule. Here, we can take a shortcut if we know that // Smooth rule. Here, we can take a shortcut if we know that
// the vertex is smooth and some other vertex has completely // the vertex is smooth and some other vertex has completely
@ -409,7 +410,7 @@ HbrCatmarkSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face
fv1.AddWithWeight(oppFace->GetFVarData(j), fvarindex, fvarwidth, weight); fv1.AddWithWeight(oppFace->GetFVarData(j), fvarindex, fvarwidth, weight);
} }
} }
// Edge subdivision rule // Edge subdivision rule
edge = edge->GetPrev(); edge = edge->GetPrev();
@ -417,11 +418,11 @@ HbrCatmarkSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone || if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) { edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) {
// Sharp edge rule // Sharp edge rule
fv3.SetWithWeight(face->GetFVarData((index + nv - 1) % nv), fvarindex, fvarwidth, 0.5f); fv3.SetWithWeight(face->GetFVarData((index + nv - 1) % nv), fvarindex, fvarwidth, 0.5f);
fv3.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f); fv3.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f);
} else if (!fv3IsSmooth || !fv3.IsInitialized()) { } else if (!fv3IsSmooth || !fv3.IsInitialized()) {
// Smooth edge subdivision. Add 0.25 of adjacent vertices // Smooth edge subdivision. Add 0.25 of adjacent vertices
fv3.SetWithWeight(face->GetFVarData((index + nv - 1) % nv), fvarindex, fvarwidth, 0.25f); fv3.SetWithWeight(face->GetFVarData((index + nv - 1) % nv), fvarindex, fvarwidth, 0.25f);
fv3.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.25f); fv3.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.25f);
// Local subdivided face vertex // Local subdivided face vertex
@ -440,12 +441,6 @@ HbrCatmarkSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face
fv1.SetInitialized(); fv1.SetInitialized();
fv3.SetInitialized(); fv3.SetInitialized();
// Special handling of ptex index for extraordinary faces: make
// sure the children get their indices reassigned to be
// consecutive within the block reserved for the parent.
if (face->GetNumVertices() != 4 && face->GetPtexIndex() != -1) {
child->SetPtexIndex(face->GetPtexIndex() + index);
}
} }
template <class T> template <class T>
@ -454,15 +449,15 @@ HbrCatmarkSubdivision<T>::transferEditsToChild(HbrFace<T>* face, HbrFace<T>* chi
// Hand down pointers to hierarchical edits // Hand down pointers to hierarchical edits
if (HbrHierarchicalEdit<T>** edits = face->GetHierarchicalEdits()) { if (HbrHierarchicalEdit<T>** edits = face->GetHierarchicalEdits()) {
while (HbrHierarchicalEdit<T>* edit = *edits) { while (HbrHierarchicalEdit<T>* edit = *edits) {
if (!edit->IsRelevantToFace(face)) break; if (!edit->IsRelevantToFace(face)) break;
if (edit->GetNSubfaces() > face->GetDepth() && if (edit->GetNSubfaces() > face->GetDepth() &&
(edit->GetSubface(face->GetDepth()) == index)) { (edit->GetSubface(face->GetDepth()) == index)) {
child->SetHierarchicalEdits(edits); child->SetHierarchicalEdits(edits);
break; break;
} }
edits++; edits++;
} }
} }
} }
@ -485,52 +480,59 @@ HbrCatmarkSubdivision<T>::Refine(HbrMesh<T>* mesh, HbrFace<T>* face) {
// parametric space through the refinement. If we split an // parametric space through the refinement. If we split an
// extraordinary face then it doesn't matter. // extraordinary face then it doesn't matter.
for (int i = 0; i < nv; ++i) { for (int i = 0; i < nv; ++i) {
if (!face->GetChild(i)) { if (!face->GetChild(i)) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Kid " << i << "\n"; std::cerr << "Kid " << i << "\n";
#endif #endif
HbrVertex<T>* vertex = edge->GetOrgVertex(); HbrVertex<T>* vertex = edge->GetOrgVertex();
if (extraordinary) { if (extraordinary) {
vertices[0] = vertex->Subdivide(); vertices[0] = vertex->Subdivide();
vertices[1] = edge->Subdivide(); vertices[1] = edge->Subdivide();
vertices[2] = face->Subdivide(); vertices[2] = face->Subdivide();
vertices[3] = prevedge->Subdivide(); vertices[3] = prevedge->Subdivide();
} else { } else {
vertices[i] = vertex->Subdivide(); vertices[i] = vertex->Subdivide();
vertices[(i+1)%4] = edge->Subdivide(); vertices[(i+1)%4] = edge->Subdivide();
vertices[(i+2)%4] = face->Subdivide(); vertices[(i+2)%4] = face->Subdivide();
vertices[(i+3)%4] = prevedge->Subdivide(); vertices[(i+3)%4] = prevedge->Subdivide();
} }
child = mesh->NewFace(4, vertices, face, i); child = mesh->NewFace(4, vertices, face, i);
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Creating face " << *child << " during refine\n"; std::cerr << "Creating face " << *child << " during refine\n";
#endif #endif
// Hand down edge sharpnesses // Hand down edge sharpnesses
childedge = vertex->Subdivide()->GetEdge(edge->Subdivide()); childedge = vertex->Subdivide()->GetEdge(edge->Subdivide());
assert(childedge); assert(childedge);
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) { if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight( HbrSubdivision<T>::SubdivideCreaseWeight(
edge, edge->GetDestVertex(), childedge); edge, edge->GetDestVertex(), childedge);
} }
childedge->CopyFVarInfiniteSharpness(edge); childedge->CopyFVarInfiniteSharpness(edge);
childedge = prevedge->Subdivide()->GetEdge(vertex->Subdivide()); childedge = prevedge->Subdivide()->GetEdge(vertex->Subdivide());
assert(childedge); assert(childedge);
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) { if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight( HbrSubdivision<T>::SubdivideCreaseWeight(
prevedge, prevedge->GetOrgVertex(), childedge); prevedge, prevedge->GetOrgVertex(), childedge);
} }
childedge->CopyFVarInfiniteSharpness(prevedge); childedge->CopyFVarInfiniteSharpness(prevedge);
if (mesh->GetTotalFVarWidth()) { if (mesh->GetTotalFVarWidth()) {
transferFVarToChild(mesh, face, child, i); transferFVarToChild(mesh, face, child, i);
} }
transferEditsToChild(face, child, i); // Special handling of ptex index for extraordinary faces: make
} // sure the children get their indices reassigned to be
prevedge = edge; // consecutive within the block reserved for the parent.
edge = edge->GetNext(); if (face->GetNumVertices() != 4 && face->GetPtexIndex() != -1) {
child->SetPtexIndex(face->GetPtexIndex() + i);
}
transferEditsToChild(face, child, i);
}
prevedge = edge;
edge = edge->GetNext();
} }
} }
@ -541,74 +543,81 @@ HbrCatmarkSubdivision<T>::RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face,
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << " forcing refine on " << *face << " at " << *vertex << '\n'; std::cerr << " forcing refine on " << *face << " at " << *vertex << '\n';
#endif #endif
// Create new quadrilateral children faces from this face // Create new quadrilateral children faces from this face
HbrHalfedge<T>* edge = face->GetFirstEdge(); HbrHalfedge<T>* edge = face->GetFirstEdge();
HbrHalfedge<T>* prevedge = edge->GetPrev(); HbrHalfedge<T>* prevedge = edge->GetPrev();
HbrHalfedge<T>* childedge; HbrHalfedge<T>* childedge;
int nv = face->GetNumVertices(); int nv = face->GetNumVertices();
float sharpness; float sharpness;
bool extraordinary = (nv != 4); bool extraordinary = (nv != 4);
// The funny indexing on vertices is done only for // The funny indexing on vertices is done only for
// non-extraordinary faces in order to correctly preserve // non-extraordinary faces in order to correctly preserve
// parametric space through the refinement. If we split an // parametric space through the refinement. If we split an
// extraordinary face then it doesn't matter. // extraordinary face then it doesn't matter.
for (int i = 0; i < nv; ++i) { for (int i = 0; i < nv; ++i) {
if (edge->GetOrgVertex() == vertex) { if (edge->GetOrgVertex() == vertex) {
if (!face->GetChild(i)) { if (!face->GetChild(i)) {
HbrFace<T>* child; HbrFace<T>* child;
HbrVertex<T>* vertices[4]; HbrVertex<T>* vertices[4];
if (extraordinary) { if (extraordinary) {
vertices[0] = vertex->Subdivide(); vertices[0] = vertex->Subdivide();
vertices[1] = edge->Subdivide(); vertices[1] = edge->Subdivide();
vertices[2] = face->Subdivide(); vertices[2] = face->Subdivide();
vertices[3] = prevedge->Subdivide(); vertices[3] = prevedge->Subdivide();
} else { } else {
vertices[i] = vertex->Subdivide(); vertices[i] = vertex->Subdivide();
vertices[(i+1)%4] = edge->Subdivide(); vertices[(i+1)%4] = edge->Subdivide();
vertices[(i+2)%4] = face->Subdivide(); vertices[(i+2)%4] = face->Subdivide();
vertices[(i+3)%4] = prevedge->Subdivide(); vertices[(i+3)%4] = prevedge->Subdivide();
} }
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Kid " << i << "\n"; std::cerr << "Kid " << i << "\n";
std::cerr << " subdivision created " << *vertices[0] << '\n'; std::cerr << " subdivision created " << *vertices[0] << '\n';
std::cerr << " subdivision created " << *vertices[1] << '\n'; std::cerr << " subdivision created " << *vertices[1] << '\n';
std::cerr << " subdivision created " << *vertices[2] << '\n'; std::cerr << " subdivision created " << *vertices[2] << '\n';
std::cerr << " subdivision created " << *vertices[3] << '\n'; std::cerr << " subdivision created " << *vertices[3] << '\n';
#endif #endif
child = mesh->NewFace(4, vertices, face, i); child = mesh->NewFace(4, vertices, face, i);
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Creating face " << *child << " during refine\n"; std::cerr << "Creating face " << *child << " during refine\n";
#endif #endif
// Hand down edge sharpness // Hand down edge sharpness
childedge = vertex->Subdivide()->GetEdge(edge->Subdivide()); childedge = vertex->Subdivide()->GetEdge(edge->Subdivide());
assert(childedge); assert(childedge);
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) { if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight( HbrSubdivision<T>::SubdivideCreaseWeight(
edge, edge->GetDestVertex(), childedge); edge, edge->GetDestVertex(), childedge);
} }
childedge->CopyFVarInfiniteSharpness(edge); childedge->CopyFVarInfiniteSharpness(edge);
childedge = prevedge->Subdivide()->GetEdge(vertex->Subdivide()); childedge = prevedge->Subdivide()->GetEdge(vertex->Subdivide());
assert(childedge); assert(childedge);
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) { if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight( HbrSubdivision<T>::SubdivideCreaseWeight(
prevedge, prevedge->GetOrgVertex(), childedge); prevedge, prevedge->GetOrgVertex(), childedge);
} }
childedge->CopyFVarInfiniteSharpness(prevedge); childedge->CopyFVarInfiniteSharpness(prevedge);
if (mesh->GetTotalFVarWidth()) { if (mesh->GetTotalFVarWidth()) {
transferFVarToChild(mesh, face, child, i); transferFVarToChild(mesh, face, child, i);
} }
transferEditsToChild(face, child, i); // Special handling of ptex index for extraordinary faces: make
return child; // sure the children get their indices reassigned to be
} else { // consecutive within the block reserved for the parent.
return face->GetChild(i); if (face->GetNumVertices() != 4 && face->GetPtexIndex() != -1) {
} child->SetPtexIndex(face->GetPtexIndex() + i);
} }
prevedge = edge;
edge = edge->GetNext(); transferEditsToChild(face, child, i);
return child;
} else {
return face->GetChild(i);
}
}
prevedge = edge;
edge = edge->GetNext();
} }
return 0; return 0;
} }
@ -617,7 +626,7 @@ template <class T>
void void
HbrCatmarkSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) { HbrCatmarkSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
if (edge->GetOpposite()) { if (edge->GetOpposite()) {
return; return;
} }
// For the given edge: if the parent of either of its incident // For the given edge: if the parent of either of its incident
@ -629,83 +638,83 @@ HbrCatmarkSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* ed
HbrFace<T>* parentFace = edge->GetOrgVertex()->GetParentFace(); HbrFace<T>* parentFace = edge->GetOrgVertex()->GetParentFace();
HbrHalfedge<T>* parentEdge = edge->GetDestVertex()->GetParentEdge(); HbrHalfedge<T>* parentEdge = edge->GetDestVertex()->GetParentEdge();
if (!parentFace) { if (!parentFace) {
destParentWasEdge = false; destParentWasEdge = false;
parentFace = edge->GetDestVertex()->GetParentFace(); parentFace = edge->GetDestVertex()->GetParentFace();
parentEdge = edge->GetOrgVertex()->GetParentEdge(); parentEdge = edge->GetOrgVertex()->GetParentEdge();
} }
if (parentFace) { if (parentFace) {
// Make sure we deal with a parent halfedge which is // Make sure we deal with a parent halfedge which is
// associated with the parent face // associated with the parent face
if (parentEdge->GetFace() != parentFace) { if (parentEdge->GetFace() != parentFace) {
parentEdge = parentEdge->GetOpposite(); parentEdge = parentEdge->GetOpposite();
} }
// If one of the vertices had a parent face, the other one MUST // If one of the vertices had a parent face, the other one MUST
// have been a child of an edge // have been a child of an edge
assert(parentEdge && parentEdge->GetFace() == parentFace); assert(parentEdge && parentEdge->GetFace() == parentFace);
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "\nparent edge is " << *parentEdge << "\n"; std::cerr << "\nparent edge is " << *parentEdge << "\n";
#endif #endif
// The vertex to refine at depends on whether the // The vertex to refine at depends on whether the
// destination or origin vertex of this edge had a parent // destination or origin vertex of this edge had a parent
// edge // edge
if (destParentWasEdge) { if (destParentWasEdge) {
RefineFaceAtVertex(mesh, parentFace, parentEdge->GetOrgVertex()); RefineFaceAtVertex(mesh, parentFace, parentEdge->GetOrgVertex());
} else { } else {
RefineFaceAtVertex(mesh, parentFace, parentEdge->GetDestVertex()); RefineFaceAtVertex(mesh, parentFace, parentEdge->GetDestVertex());
} }
// It should always be the case that the opposite now exists - // It should always be the case that the opposite now exists -
// we can't have a boundary case here // we can't have a boundary case here
assert(edge->GetOpposite()); assert(edge->GetOpposite());
} else { } else {
HbrVertex<T>* parentVertex = edge->GetOrgVertex()->GetParentVertex(); HbrVertex<T>* parentVertex = edge->GetOrgVertex()->GetParentVertex();
parentEdge = edge->GetDestVertex()->GetParentEdge(); parentEdge = edge->GetDestVertex()->GetParentEdge();
if (!parentVertex) { if (!parentVertex) {
parentVertex = edge->GetDestVertex()->GetParentVertex(); parentVertex = edge->GetDestVertex()->GetParentVertex();
parentEdge = edge->GetOrgVertex()->GetParentEdge(); parentEdge = edge->GetOrgVertex()->GetParentEdge();
} }
if (parentVertex) { if (parentVertex) {
assert(parentEdge); assert(parentEdge);
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "\nparent edge is " << *parentEdge << "\n"; std::cerr << "\nparent edge is " << *parentEdge << "\n";
#endif #endif
// 1. Go up to the parent of my face
parentFace = edge->GetFace()->GetParent(); // 1. Go up to the parent of my face
parentFace = edge->GetFace()->GetParent();
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "\nparent face is " << *parentFace << "\n"; std::cerr << "\nparent face is " << *parentFace << "\n";
#endif #endif
// 2. Ask the opposite face (if it exists) to refine // 2. Ask the opposite face (if it exists) to refine
if (parentFace) { if (parentFace) {
// A vertex can be associated with either of two // A vertex can be associated with either of two
// parent halfedges. If the parent edge that we're // parent halfedges. If the parent edge that we're
// interested in doesn't match then we should look at // interested in doesn't match then we should look at
// its opposite // its opposite
if (parentEdge->GetFace() != parentFace) if (parentEdge->GetFace() != parentFace)
parentEdge = parentEdge->GetOpposite(); parentEdge = parentEdge->GetOpposite();
assert(parentEdge->GetFace() == parentFace); assert(parentEdge->GetFace() == parentFace);
// Make sure the parent edge has its neighbor as well // Make sure the parent edge has its neighbor as well
GuaranteeNeighbor(mesh, parentEdge); GuaranteeNeighbor(mesh, parentEdge);
// Now access that neighbor and refine it // Now access that neighbor and refine it
if (parentEdge->GetRightFace()) { if (parentEdge->GetRightFace()) {
RefineFaceAtVertex(mesh, parentEdge->GetRightFace(), parentVertex); RefineFaceAtVertex(mesh, parentEdge->GetRightFace(), parentVertex);
// FIXME: assertion? // FIXME: assertion?
assert(edge->GetOpposite()); assert(edge->GetOpposite());
} }
} }
} }
} }
} }
@ -724,10 +733,10 @@ HbrCatmarkSubdivision<T>::GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* ver
if (parentFace) { if (parentFace) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << " forcing full refine on parent face\n"; std::cerr << " forcing full refine on parent face\n";
#endif #endif
Refine(mesh, parentFace); Refine(mesh, parentFace);
return; return;
} }
// Otherwise if the vertex is a child of an edge, we need to // Otherwise if the vertex is a child of an edge, we need to
@ -738,29 +747,29 @@ HbrCatmarkSubdivision<T>::GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* ver
if (parentEdge) { if (parentEdge) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << " forcing full refine on adjacent faces of parent edge\n"; std::cerr << " forcing full refine on adjacent faces of parent edge\n";
#endif #endif
HbrVertex<T>* dest = parentEdge->GetDestVertex(); HbrVertex<T>* dest = parentEdge->GetDestVertex();
HbrVertex<T>* org = parentEdge->GetOrgVertex(); HbrVertex<T>* org = parentEdge->GetOrgVertex();
GuaranteeNeighbor(mesh, parentEdge); GuaranteeNeighbor(mesh, parentEdge);
parentFace = parentEdge->GetLeftFace(); parentFace = parentEdge->GetLeftFace();
RefineFaceAtVertex(mesh, parentFace, dest); RefineFaceAtVertex(mesh, parentFace, dest);
RefineFaceAtVertex(mesh, parentFace, org); RefineFaceAtVertex(mesh, parentFace, org);
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << " on the right face?\n"; std::cerr << " on the right face?\n";
#endif #endif
parentFace = parentEdge->GetRightFace(); parentFace = parentEdge->GetRightFace();
// The right face may not necessarily exist even after // The right face may not necessarily exist even after
// GuaranteeNeighbor // GuaranteeNeighbor
if (parentFace) { if (parentFace) {
RefineFaceAtVertex(mesh, parentFace, dest); RefineFaceAtVertex(mesh, parentFace, dest);
RefineFaceAtVertex(mesh, parentFace, org); RefineFaceAtVertex(mesh, parentFace, org);
} }
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << " end force\n"; std::cerr << " end force\n";
#endif #endif
return; return;
} }
// The last case: the vertex is a child of a vertex. In this case // The last case: the vertex is a child of a vertex. In this case
@ -770,20 +779,20 @@ HbrCatmarkSubdivision<T>::GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* ver
if (parentVertex) { if (parentVertex) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << " recursive parent vertex guarantee call\n"; std::cerr << " recursive parent vertex guarantee call\n";
#endif #endif
parentVertex->GuaranteeNeighbors(); parentVertex->GuaranteeNeighbors();
// And then we refine all the face neighbors of the // And then we refine all the face neighbors of the
// parentVertex // parentVertex
HbrHalfedge<T>* start = parentVertex->GetIncidentEdge(), *edge; HbrHalfedge<T>* start = parentVertex->GetIncidentEdge(), *edge;
edge = start; edge = start;
while (edge) { while (edge) {
HbrFace<T>* f = edge->GetLeftFace(); HbrFace<T>* f = edge->GetLeftFace();
RefineFaceAtVertex(mesh, f, parentVertex); RefineFaceAtVertex(mesh, f, parentVertex);
edge = parentVertex->GetNextEdge(edge); edge = parentVertex->GetNextEdge(edge);
if (edge == start) break; if (edge == start) break;
} }
} }
} }
@ -794,9 +803,9 @@ HbrCatmarkSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face) {
if (face->IsHole()) return false; if (face->IsHole()) return false;
// A limit face exists if all the bounding edges have limit curves // A limit face exists if all the bounding edges have limit curves
for (int i = 0; i < face->GetNumVertices(); ++i) { for (int i = 0; i < face->GetNumVertices(); ++i) {
if (!HasLimit(mesh, face->GetEdge(i))) { if (!HasLimit(mesh, face->GetEdge(i))) {
return false; return false;
} }
} }
return true; return true;
} }
@ -804,14 +813,14 @@ HbrCatmarkSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face) {
template <class T> template <class T>
bool bool
HbrCatmarkSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) { HbrCatmarkSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
// A sharp edge has a limit curve if both endpoints have limits. // A sharp edge has a limit curve if both endpoints have limits.
// A smooth edge has a limit if both endpoints have limits and // A smooth edge has a limit if both endpoints have limits and
// the edge isn't on the boundary. // the edge isn't on the boundary.
if (edge->GetSharpness() >= HbrHalfedge<T>::k_InfinitelySharp) return true; if (edge->GetSharpness() >= HbrHalfedge<T>::k_InfinitelySharp) return true;
if (!HasLimit(mesh, edge->GetOrgVertex()) || !HasLimit(mesh, edge->GetDestVertex())) return false; if (!HasLimit(mesh, edge->GetOrgVertex()) || !HasLimit(mesh, edge->GetDestVertex())) return false;
return !edge->IsBoundary(); return !edge->IsBoundary();
} }
@ -820,21 +829,21 @@ bool
HbrCatmarkSubdivision<T>::HasLimit(HbrMesh<T>* /* mesh */, HbrVertex<T>* vertex) { HbrCatmarkSubdivision<T>::HasLimit(HbrMesh<T>* /* mesh */, HbrVertex<T>* vertex) {
vertex->GuaranteeNeighbors(); vertex->GuaranteeNeighbors();
switch (vertex->GetMask(false)) { switch (vertex->GetMask(false)) {
case HbrVertex<T>::k_Smooth: case HbrVertex<T>::k_Smooth:
case HbrVertex<T>::k_Dart: case HbrVertex<T>::k_Dart:
return !vertex->OnBoundary(); return !vertex->OnBoundary();
break; break;
case HbrVertex<T>::k_Crease: case HbrVertex<T>::k_Crease:
case HbrVertex<T>::k_Corner: case HbrVertex<T>::k_Corner:
default: default:
if (vertex->IsVolatile()) { if (vertex->IsVolatile()) {
// Search for any incident semisharp boundary edge // Search for any incident semisharp boundary edge
HbrHalfedge<T>* start = vertex->GetIncidentEdge(), *edge, *next; HbrHalfedge<T>* start = vertex->GetIncidentEdge(), *edge, *next;
edge = start; edge = start;
while (edge) { while (edge) {
if (edge->IsBoundary() && edge->GetSharpness() < HbrHalfedge<T>::k_InfinitelySharp) { if (edge->IsBoundary() && edge->GetSharpness() < HbrHalfedge<T>::k_InfinitelySharp) {
return false; return false;
} }
next = vertex->GetNextEdge(edge); next = vertex->GetNextEdge(edge);
if (next == start) { if (next == start) {
break; break;
@ -847,9 +856,9 @@ HbrCatmarkSubdivision<T>::HasLimit(HbrMesh<T>* /* mesh */, HbrVertex<T>* vertex)
} else { } else {
edge = next; edge = next;
} }
} }
} }
return true; return true;
} }
} }
@ -858,22 +867,22 @@ HbrVertex<T>*
HbrCatmarkSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) { HbrCatmarkSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) {
// Face rule: simply average all vertices on the face // Face rule: simply average all vertices on the face
HbrVertex<T>* v = mesh->NewVertex(); HbrVertex<T>* v = mesh->NewVertex();
T& data = v->GetData(); T& data = v->GetData();
int nv = face->GetNumVertices(); int nv = face->GetNumVertices();
float weight = 1.0f / nv; float weight = 1.0f / nv;
HbrHalfedge<T>* edge = face->GetFirstEdge(); HbrHalfedge<T>* edge = face->GetFirstEdge();
for (int i = 0; i < face->GetNumVertices(); ++i) { for (int i = 0; i < face->GetNumVertices(); ++i) {
HbrVertex<T>* w = edge->GetOrgVertex(); HbrVertex<T>* w = edge->GetOrgVertex();
// If there are vertex edits we have to make sure the edit // If there are vertex edits we have to make sure the edit
// has been applied // has been applied
if (mesh->HasVertexEdits()) { if (mesh->HasVertexEdits()) {
w->GuaranteeNeighbors(); w->GuaranteeNeighbors();
} }
data.AddWithWeight(w->GetData(), weight); data.AddWithWeight(w->GetData(), weight);
data.AddVaryingWithWeight(w->GetData(), weight); data.AddVaryingWithWeight(w->GetData(), weight);
edge = edge->GetNext(); edge = edge->GetNext();
} }
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Subdividing at " << *face << "\n"; std::cerr << "Subdividing at " << *face << "\n";
@ -882,7 +891,7 @@ HbrCatmarkSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) {
// Set the extraordinary flag if the face had anything other than // Set the extraordinary flag if the face had anything other than
// 4 vertices // 4 vertices
if (nv != 4) v->SetExtraordinary(); if (nv != 4) v->SetExtraordinary();
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << " created " << *v << "\n"; std::cerr << " created " << *v << "\n";
#endif #endif
@ -907,12 +916,12 @@ HbrCatmarkSubdivision<T>::OldTriangleSubdivide(HbrMesh<T>* mesh, HbrFace<T>* fac
data.Clear(); data.Clear();
float weight = 1.0f / 6.0f; float weight = 1.0f / 6.0f;
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
HbrVertex<T>* w = face->GetVertex(i); HbrVertex<T>* w = face->GetVertex(i);
HbrHalfedge<T>* e = face->GetEdge(i); HbrHalfedge<T>* e = face->GetEdge(i);
data.AddWithWeight(w->Subdivide()->GetData(), weight); data.AddWithWeight(w->Subdivide()->GetData(), weight);
data.AddWithWeight(e->Subdivide()->GetData(), weight); data.AddWithWeight(e->Subdivide()->GetData(), weight);
} }
} }
#endif #endif
@ -958,7 +967,7 @@ HbrCatmarkSubdivision<T>::OldTriangleSubdivide(HbrMesh<T>* mesh, HbrFace<T>* fac
If there is a mixture of triangular and non-triangular faces, the If there is a mixture of triangular and non-triangular faces, the
weights are interpolated. */ weights are interpolated. */
#define HBR_SMOOTH_TRI_EDGE_WEIGHT 0.470f /* from Mathematica */ #define HBR_SMOOTH_TRI_EDGE_WEIGHT 0.470f /* from Mathematica */
template <class T> template <class T>
HbrVertex<T>* HbrVertex<T>*
@ -972,66 +981,66 @@ HbrCatmarkSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Subdividing at " << *edge << " (sharpness = " << esharp << ")"; std::cerr << "Subdividing at " << *edge << " (sharpness = " << esharp << ")";
#endif #endif
HbrVertex<T>* v = mesh->NewVertex(); HbrVertex<T>* v = mesh->NewVertex();
T& data = v->GetData(); T& data = v->GetData();
// If there's the possibility of vertex edits on either vertex, we // If there's the possibility of vertex edits on either vertex, we
// have to make sure the edit has been applied // have to make sure the edit has been applied
if (mesh->HasVertexEdits()) { if (mesh->HasVertexEdits()) {
edge->GetOrgVertex()->GuaranteeNeighbors(); edge->GetOrgVertex()->GuaranteeNeighbors();
edge->GetDestVertex()->GuaranteeNeighbors(); edge->GetDestVertex()->GuaranteeNeighbors();
} }
if (!edge->IsBoundary() && esharp <= 1.0f) { if (!edge->IsBoundary() && esharp <= 1.0f) {
// Of the two half-edges, pick one of them consistently such // Of the two half-edges, pick one of them consistently such
// that the left and right faces are also consistent through // that the left and right faces are also consistent through
// multi-threading. It doesn't matter as far as the // multi-threading. It doesn't matter as far as the
// theoretical calculation is concerned, but it is desirable // theoretical calculation is concerned, but it is desirable
// to be consistent about it in the face of the limitations of // to be consistent about it in the face of the limitations of
// floating point commutativity. So we always pick the // floating point commutativity. So we always pick the
// half-edge such that its incident face is the smallest of // half-edge such that its incident face is the smallest of
// the two faces, as far as the face paths are concerned. // the two faces, as far as the face paths are concerned.
if (edge->GetOpposite() && edge->GetOpposite()->GetFace()->GetPath() < edge->GetFace()->GetPath()) { if (edge->GetOpposite() && edge->GetOpposite()->GetFace()->GetPath() < edge->GetFace()->GetPath()) {
edge = edge->GetOpposite(); edge = edge->GetOpposite();
} }
// Handle both the smooth and fractional sharpness cases. We
// lerp between the sharp case (average of the two end points)
// and the unsharp case (average of two end points plus two
// face averages).
float leftWeight, rightWeight, faceWeight, vertWeight; // Handle both the smooth and fractional sharpness cases. We
HbrFace<T>* rf = edge->GetRightFace(); // lerp between the sharp case (average of the two end points)
HbrFace<T>* lf = edge->GetLeftFace(); // and the unsharp case (average of two end points plus two
// face averages).
// The standard catmull-clark rule for face weights is 0.25. float leftWeight, rightWeight, faceWeight, vertWeight;
// The modified, new triangle subdivision rule uses a value of HbrFace<T>* rf = edge->GetRightFace();
// SMOOTH_TRI_EDGE_WEIGHT as defined above. We lerp between HbrFace<T>* lf = edge->GetLeftFace();
// the right and left weights as needed.
leftWeight = (triangleSubdivision == k_New && lf->GetNumVertices() == 3) ? HBR_SMOOTH_TRI_EDGE_WEIGHT : 0.25f;
rightWeight = (triangleSubdivision == 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);
// Lerp the face weight between non sharp contribution and // The standard catmull-clark rule for face weights is 0.25.
// sharp contribution (which is zero) // The modified, new triangle subdivision rule uses a value of
faceWeight *= (1.0f - esharp); // SMOOTH_TRI_EDGE_WEIGHT as defined above. We lerp between
// the right and left weights as needed.
// Lerp the vert weight between non sharp contribution and leftWeight = (triangleSubdivision == k_New && lf->GetNumVertices() == 3) ? HBR_SMOOTH_TRI_EDGE_WEIGHT : 0.25f;
// sharp contribution of 0.5f rightWeight = (triangleSubdivision == k_New && rf->GetNumVertices() == 3) ? HBR_SMOOTH_TRI_EDGE_WEIGHT : 0.25f;
vertWeight = 0.5f * esharp + (1.0f - esharp) * vertWeight; faceWeight = 0.5f * (leftWeight + rightWeight);
vertWeight = 0.5f * (1.0f - 2.0f * faceWeight);
data.AddWithWeight(edge->GetOrgVertex()->GetData(), vertWeight);
data.AddWithWeight(edge->GetDestVertex()->GetData(), vertWeight);
data.AddWithWeight(lf->Subdivide()->GetData(), faceWeight); // Lerp the face weight between non sharp contribution and
data.AddWithWeight(rf->Subdivide()->GetData(), faceWeight); // sharp contribution (which is zero)
faceWeight *= (1.0f - esharp);
// Lerp the vert weight between non sharp contribution and
// sharp contribution of 0.5f
vertWeight = 0.5f * esharp + (1.0f - esharp) * vertWeight;
data.AddWithWeight(edge->GetOrgVertex()->GetData(), vertWeight);
data.AddWithWeight(edge->GetDestVertex()->GetData(), vertWeight);
data.AddWithWeight(lf->Subdivide()->GetData(), faceWeight);
data.AddWithWeight(rf->Subdivide()->GetData(), faceWeight);
} else { } else {
// Fully sharp edge, just average the two end points // Fully sharp edge, just average the two end points
data.AddWithWeight(edge->GetOrgVertex()->GetData(), 0.5f); data.AddWithWeight(edge->GetOrgVertex()->GetData(), 0.5f);
data.AddWithWeight(edge->GetDestVertex()->GetData(), 0.5f); data.AddWithWeight(edge->GetDestVertex()->GetData(), 0.5f);
} }
// Varying data is always the average of two end points // Varying data is always the average of two end points
@ -1051,7 +1060,7 @@ HbrCatmarkSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
// Ensure the ring of faces around this vertex exists before // Ensure the ring of faces around this vertex exists before
// we compute the valence // we compute the valence
vertex->GuaranteeNeighbors(); vertex->GuaranteeNeighbors();
float valence = static_cast<float>(vertex->GetValence()); float valence = static_cast<float>(vertex->GetValence());
float invvalencesquared = 1.0f / (valence * valence); float invvalencesquared = 1.0f / (valence * valence);
@ -1071,76 +1080,76 @@ HbrCatmarkSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
// subdivision, then use fractional mask weights to weigh // subdivision, then use fractional mask weights to weigh
// each weighing // each weighing
if (masks[0] != masks[1]) { if (masks[0] != masks[1]) {
weights[1] = vertex->GetFractionalMask(); weights[1] = vertex->GetFractionalMask();
weights[0] = 1.0f - weights[1]; weights[0] = 1.0f - weights[1];
passes = 2; passes = 2;
} else { } else {
weights[0] = 1.0f; weights[0] = 1.0f;
weights[1] = 0.0f; weights[1] = 0.0f;
passes = 1; passes = 1;
} }
for (int i = 0; i < passes; ++i) { for (int i = 0; i < passes; ++i) {
switch (masks[i]) { switch (masks[i]) {
case HbrVertex<T>::k_Smooth: case HbrVertex<T>::k_Smooth:
case HbrVertex<T>::k_Dart: { case HbrVertex<T>::k_Dart: {
// Compute n-2/n of the old vertex value // Compute n-2/n of the old vertex value
data.AddWithWeight(vertex->GetData(), weights[i] * invvalencesquared * valence * (valence - 2)); data.AddWithWeight(vertex->GetData(), weights[i] * invvalencesquared * valence * (valence - 2));
// Add 1 / n^2 * surrounding edge vertices and surrounding face // Add 1 / n^2 * surrounding edge vertices and surrounding face
// subdivided vertices // subdivided vertices
HbrSubdivision<T>::AddSurroundingVerticesWithWeight( HbrSubdivision<T>::AddSurroundingVerticesWithWeight(
mesh, vertex, weights[i] * invvalencesquared, &data); mesh, vertex, weights[i] * invvalencesquared, &data);
HbrHalfedge<T>* start = vertex->GetIncidentEdge(), *edge; HbrHalfedge<T>* start = vertex->GetIncidentEdge(), *edge;
edge = start; edge = start;
while (edge) { while (edge) {
HbrFace<T>* f = edge->GetLeftFace(); HbrFace<T>* f = edge->GetLeftFace();
data.AddWithWeight(f->Subdivide()->GetData(), weights[i] * invvalencesquared); data.AddWithWeight(f->Subdivide()->GetData(), weights[i] * invvalencesquared);
edge = vertex->GetNextEdge(edge); edge = vertex->GetNextEdge(edge);
if (edge == start) break; if (edge == start) break;
} }
break; break;
} }
case HbrVertex<T>::k_Crease: { case HbrVertex<T>::k_Crease: {
// Compute 3/4 of old vertex value // Compute 3/4 of old vertex value
data.AddWithWeight(vertex->GetData(), weights[i] * 0.75f); data.AddWithWeight(vertex->GetData(), weights[i] * 0.75f);
// Add 0.125f of the (hopefully only two!) neighbouring // Add 0.125f of the (hopefully only two!) neighbouring
// sharp edges // sharp edges
HbrSubdivision<T>::AddCreaseEdgesWithWeight( HbrSubdivision<T>::AddCreaseEdgesWithWeight(
mesh, vertex, i == 1, weights[i] * 0.125f, &data); mesh, vertex, i == 1, weights[i] * 0.125f, &data);
break; break;
} }
case HbrVertex<T>::k_Corner: case HbrVertex<T>::k_Corner:
default: { default: {
// Just copy the old value // Just copy the old value
data.AddWithWeight(vertex->GetData(), weights[i]); data.AddWithWeight(vertex->GetData(), weights[i]);
break; break;
} }
} }
} }
// Varying data is always just propogated down // Varying data is always just propagated down
data.AddVaryingWithWeight(vertex->GetData(), 1.0f); data.AddVaryingWithWeight(vertex->GetData(), 1.0f);
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Subdividing at " << *vertex << "\n"; std::cerr << "Subdividing at " << *vertex << "\n";
std::cerr << " created " << *v << "\n"; std::cerr << " created " << *v << "\n";
#endif #endif
// Inherit extraordinary flag and sharpness // Inherit extraordinary flag and sharpness
if (vertex->IsExtraordinary()) v->SetExtraordinary(); if (vertex->IsExtraordinary()) v->SetExtraordinary();
float sharp = vertex->GetSharpness(); float sharp = vertex->GetSharpness();
if (sharp >= HbrVertex<T>::k_InfinitelySharp) { if (sharp >= HbrVertex<T>::k_InfinitelySharp) {
v->SetSharpness(HbrVertex<T>::k_InfinitelySharp); v->SetSharpness(HbrVertex<T>::k_InfinitelySharp);
} else if (sharp > HbrVertex<T>::k_Smooth) { } else if (sharp > HbrVertex<T>::k_Smooth) {
sharp -= 1.0f; sharp -= 1.0f;
if (sharp < (float) HbrVertex<T>::k_Smooth) { if (sharp < (float) HbrVertex<T>::k_Smooth) {
sharp = (float) HbrVertex<T>::k_Smooth; sharp = (float) HbrVertex<T>::k_Smooth;
} }
v->SetSharpness(sharp); v->SetSharpness(sharp);
} else { } else {
v->SetSharpness(HbrVertex<T>::k_Smooth); v->SetSharpness(HbrVertex<T>::k_Smooth);
} }
return v; return v;
} }
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION

View File

@ -68,7 +68,7 @@ template <class T>
std::ostream& operator<<(std::ostream& out, const HbrCornerEdit<T>& path) { std::ostream& operator<<(std::ostream& out, const HbrCornerEdit<T>& path) {
out << "vertex path = (" << path.faceid << ' '; out << "vertex path = (" << path.faceid << ' ';
for (int i = 0; i < path.nsubfaces; ++i) { for (int i = 0; i < path.nsubfaces; ++i) {
out << static_cast<int>(path.subfaces[i]) << ' '; out << static_cast<int>(path.subfaces[i]) << ' ';
} }
return out << static_cast<int>(path.vertexid) << "), sharpness = " << path.sharpness; return out << static_cast<int>(path.vertexid) << "), sharpness = " << path.sharpness;
} }
@ -79,39 +79,39 @@ class HbrCornerEdit : public HbrHierarchicalEdit<T> {
public: public:
HbrCornerEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _vertexid, typename HbrHierarchicalEdit<T>::Operation _op, float _sharpness) HbrCornerEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _vertexid, typename HbrHierarchicalEdit<T>::Operation _op, float _sharpness)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), op(_op), sharpness(_sharpness) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), op(_op), sharpness(_sharpness) {
} }
HbrCornerEdit(int _faceid, int _nsubfaces, int *_subfaces, int _vertexid, typename HbrHierarchicalEdit<T>::Operation _op, float _sharpness) HbrCornerEdit(int _faceid, int _nsubfaces, int *_subfaces, int _vertexid, typename HbrHierarchicalEdit<T>::Operation _op, float _sharpness)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), op(_op), sharpness(_sharpness) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), op(_op), sharpness(_sharpness) {
} }
virtual ~HbrCornerEdit() {} virtual ~HbrCornerEdit() {}
friend std::ostream& operator<< <T> (std::ostream& out, const HbrCornerEdit<T>& path); friend std::ostream& operator<< <T> (std::ostream& out, const HbrCornerEdit<T>& path);
virtual void ApplyEditToFace(HbrFace<T>* face) { virtual void ApplyEditToFace(HbrFace<T>* face) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) { if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
// Modify vertex sharpness. Note that we could actually do // Modify vertex sharpness. Note that we could actually do
// this in ApplyEditToVertex as well! // this in ApplyEditToVertex as well!
float sharp; float sharp;
if (op == HbrHierarchicalEdit<T>::Set) { if (op == HbrHierarchicalEdit<T>::Set) {
sharp = sharpness; sharp = sharpness;
} else if (op == HbrHierarchicalEdit<T>::Add) { } else if (op == HbrHierarchicalEdit<T>::Add) {
sharp = face->GetVertex(vertexid)->GetSharpness() + sharpness; sharp = face->GetVertex(vertexid)->GetSharpness() + sharpness;
} else if (op == HbrHierarchicalEdit<T>::Subtract) { } else if (op == HbrHierarchicalEdit<T>::Subtract) {
sharp = face->GetVertex(vertexid)->GetSharpness() - sharpness; sharp = face->GetVertex(vertexid)->GetSharpness() - sharpness;
} }
if (sharp < HbrVertex<T>::k_Smooth) { if (sharp < HbrVertex<T>::k_Smooth) {
sharp = HbrVertex<T>::k_Smooth; sharp = HbrVertex<T>::k_Smooth;
} }
if (sharp > HbrVertex<T>::k_InfinitelySharp) { if (sharp > HbrVertex<T>::k_InfinitelySharp) {
sharp = HbrVertex<T>::k_InfinitelySharp; sharp = HbrVertex<T>::k_InfinitelySharp;
} }
face->GetVertex(vertexid)->SetSharpness(sharp); face->GetVertex(vertexid)->SetSharpness(sharp);
} }
} }
private: private:
// ID of the edge (you can think of this also as the id of the // ID of the edge (you can think of this also as the id of the
// origin vertex of the two-vertex length edge) // origin vertex of the two-vertex length edge)

View File

@ -68,7 +68,7 @@ template <class T>
std::ostream& operator<<(std::ostream& out, const HbrCreaseEdit<T>& path) { std::ostream& operator<<(std::ostream& out, const HbrCreaseEdit<T>& path) {
out << "edge path = (" << path.faceid << ' '; out << "edge path = (" << path.faceid << ' ';
for (int i = 0; i < path.nsubfaces; ++i) { for (int i = 0; i < path.nsubfaces; ++i) {
out << static_cast<int>(path.subfaces[i]) << ' '; out << static_cast<int>(path.subfaces[i]) << ' ';
} }
return out << static_cast<int>(path.edgeid) << "), sharpness = " << path.sharpness; return out << static_cast<int>(path.edgeid) << "), sharpness = " << path.sharpness;
} }
@ -79,41 +79,41 @@ class HbrCreaseEdit : public HbrHierarchicalEdit<T> {
public: public:
HbrCreaseEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _edgeid, typename HbrHierarchicalEdit<T>::Operation _op, float _sharpness) HbrCreaseEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _edgeid, typename HbrHierarchicalEdit<T>::Operation _op, float _sharpness)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), edgeid(_edgeid), op(_op), sharpness(_sharpness) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), edgeid(_edgeid), op(_op), sharpness(_sharpness) {
} }
HbrCreaseEdit(int _faceid, int _nsubfaces, int *_subfaces, int _edgeid, typename HbrHierarchicalEdit<T>::Operation _op, float _sharpness) HbrCreaseEdit(int _faceid, int _nsubfaces, int *_subfaces, int _edgeid, typename HbrHierarchicalEdit<T>::Operation _op, float _sharpness)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), edgeid(_edgeid), op(_op), sharpness(_sharpness) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), edgeid(_edgeid), op(_op), sharpness(_sharpness) {
} }
virtual ~HbrCreaseEdit() {} virtual ~HbrCreaseEdit() {}
friend std::ostream& operator<< <T> (std::ostream& out, const HbrCreaseEdit<T>& path); friend std::ostream& operator<< <T> (std::ostream& out, const HbrCreaseEdit<T>& path);
virtual void ApplyEditToFace(HbrFace<T>* face) { virtual void ApplyEditToFace(HbrFace<T>* face) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) { if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
// Modify edge sharpness // Modify edge sharpness
float sharp; float sharp;
if (op == HbrHierarchicalEdit<T>::Set) { if (op == HbrHierarchicalEdit<T>::Set) {
sharp = sharpness; sharp = sharpness;
} else if (op == HbrHierarchicalEdit<T>::Add) { } else if (op == HbrHierarchicalEdit<T>::Add) {
sharp = face->GetEdge(edgeid)->GetSharpness() + sharpness; sharp = face->GetEdge(edgeid)->GetSharpness() + sharpness;
} else if (op == HbrHierarchicalEdit<T>::Subtract) { } else if (op == HbrHierarchicalEdit<T>::Subtract) {
sharp = face->GetEdge(edgeid)->GetSharpness() - sharpness; sharp = face->GetEdge(edgeid)->GetSharpness() - sharpness;
} }
if (sharp < HbrHalfedge<T>::k_Smooth) if (sharp < HbrHalfedge<T>::k_Smooth)
sharp = HbrHalfedge<T>::k_Smooth; sharp = HbrHalfedge<T>::k_Smooth;
if (sharp > HbrHalfedge<T>::k_InfinitelySharp) if (sharp > HbrHalfedge<T>::k_InfinitelySharp)
sharp = HbrHalfedge<T>::k_InfinitelySharp; sharp = HbrHalfedge<T>::k_InfinitelySharp;
// We have to make sure the neighbor of the edge exists at // We have to make sure the neighbor of the edge exists at
// this point. Otherwise, if it comes into being late, it // this point. Otherwise, if it comes into being late, it
// will clobber the overriden sharpness and we will lose // will clobber the overriden sharpness and we will lose
// the edit. // the edit.
face->GetEdge(edgeid)->GuaranteeNeighbor(); face->GetEdge(edgeid)->GuaranteeNeighbor();
face->GetEdge(edgeid)->SetSharpness(sharp); face->GetEdge(edgeid)->SetSharpness(sharp);
} }
} }
private: private:
// ID of the edge (you can think of this also as the id of the // ID of the edge (you can think of this also as the id of the
// origin vertex of the two-vertex length edge) // origin vertex of the two-vertex length edge)

View File

@ -62,7 +62,7 @@
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#include <list> #include <vector>
#include "../hbr/fvarData.h" #include "../hbr/fvarData.h"
#include "../hbr/allocator.h" #include "../hbr/allocator.h"
@ -87,30 +87,31 @@ template <class T> std::ostream& operator<<(std::ostream& out, const HbrFace<T>&
// A descriptor for a path to a face // A descriptor for a path to a face
struct HbrFacePath { struct HbrFacePath {
void Print() const { void Print() const {
printf("%d", topface); printf("%d", topface);
for (std::list<int>::const_iterator i = remainder.begin(); i != remainder.end(); ++i) { for (std::vector<int>::const_reverse_iterator i = remainder.rbegin(); i != remainder.rend(); ++i) {
printf(" %d", *i); printf(" %d", *i);
} }
printf("\n"); printf("\n");
} }
int topface; int topface;
std::list<int> remainder; // Note that the elements in remainder are stored in reverse order.
std::vector<int> remainder;
friend bool operator< (const HbrFacePath& x, const HbrFacePath& y); friend bool operator< (const HbrFacePath& x, const HbrFacePath& y);
}; };
inline bool operator< (const HbrFacePath& x, const HbrFacePath& y) { inline bool operator< (const HbrFacePath& x, const HbrFacePath& y) {
if (x.topface != y.topface) { if (x.topface != y.topface) {
return x.topface < y.topface; return x.topface < y.topface;
} else if (x.remainder.size() != y.remainder.size()) { } else if (x.remainder.size() != y.remainder.size()) {
return x.remainder.size() < y.remainder.size(); return x.remainder.size() < y.remainder.size();
} else { } else {
std::list<int>::const_iterator i = x.remainder.begin(); std::vector<int>::const_reverse_iterator i = x.remainder.rbegin();
std::list<int>::const_iterator j = y.remainder.begin(); std::vector<int>::const_reverse_iterator j = y.remainder.rbegin();
for ( ; i != x.remainder.end(); ++i, ++j) { for ( ; i != x.remainder.rend(); ++i, ++j) {
if (*i != *j) return (*i < *j); if (*i != *j) return (*i < *j);
} }
return true; return true;
} }
} }
@ -129,7 +130,7 @@ public:
// Returns the mesh to which this face belongs // Returns the mesh to which this face belongs
HbrMesh<T>* GetMesh() const { return mesh; } HbrMesh<T>* GetMesh() const { return mesh; }
// Return number of vertices // Return number of vertices
int GetNumVertices() const { return nvertices; } int GetNumVertices() const { return nvertices; }
@ -139,7 +140,7 @@ public:
// Return the first halfedge of the face // Return the first halfedge of the face
HbrHalfedge<T>* GetFirstEdge() const { HbrHalfedge<T>* GetFirstEdge() const {
if (nvertices > 4) { if (nvertices > 4) {
return const_cast<HbrHalfedge<T>*>(&extraedges[0]); return const_cast<HbrHalfedge<T>*>(&extraedges[0]);
} else { } else {
return const_cast<HbrHalfedge<T>*>(&edges[0]); return const_cast<HbrHalfedge<T>*>(&edges[0]);
} }
@ -154,17 +155,17 @@ public:
// Return the parent of this face // Return the parent of this face
HbrFace<T>* GetParent() const { return parent; } HbrFace<T>* GetParent() const { return parent; }
// Set the child // Set the child
void SetChild(int index, HbrFace<T>* face); void SetChild(int index, HbrFace<T>* face);
// Return the child with the indicated index // Return the child with the indicated index
HbrFace<T>* GetChild(int index) const { HbrFace<T>* GetChild(int index) const {
if (!children || index < 0 || index >= mesh->GetSubdivision()->GetFaceChildrenCount(nvertices)) return 0; if (!children || index < 0 || index >= mesh->GetSubdivision()->GetFaceChildrenCount(nvertices)) return 0;
return children[index]; return children[index];
} }
// Subdivide the face into a vertex if needed and return // Subdivide the face into a vertex if needed and return
HbrVertex<T>* Subdivide(); HbrVertex<T>* Subdivide();
// Remove the reference to subdivided vertex // Remove the reference to subdivided vertex
@ -259,26 +260,27 @@ public:
HbrFace<T>*& GetNext() { return parent; } HbrFace<T>*& GetNext() { return parent; }
HbrFacePath GetPath() const { HbrFacePath GetPath() const {
HbrFacePath path; HbrFacePath path;
const HbrFace<T>* f = this, *p = GetParent(); path.remainder.reserve(GetDepth());
while (p) { const HbrFace<T>* f = this, *p = GetParent();
while (p) {
int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(p->nvertices); int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(p->nvertices);
for (int i = 0; i < nchildren; ++i) { for (int i = 0; i < nchildren; ++i) {
if (p->children[i] == f) { if (p->children[i] == f) {
path.remainder.push_front(i); path.remainder.push_back(i);
break; break;
} }
} }
f = p; f = p;
p = f->GetParent(); p = f->GetParent();
} }
path.topface = f->GetID(); path.topface = f->GetID();
assert(GetDepth() == 0 || static_cast<int>(path.remainder.size()) == GetDepth()); assert(GetDepth() == 0 || static_cast<int>(path.remainder.size()) == GetDepth());
return path; return path;
} }
void PrintPath() const { void PrintPath() const {
GetPath().Print(); GetPath().Print();
} }
// Returns the blind pointer to client data // Returns the blind pointer to client data
@ -290,8 +292,8 @@ public:
void SetClientData(void *data) { void SetClientData(void *data) {
clientData = data; clientData = data;
} }
private: private:
// Mesh to which this face belongs // Mesh to which this face belongs
@ -305,12 +307,12 @@ private:
// Ptex index // Ptex index
int ptexindex; int ptexindex;
// Number of vertices (and number of edges) // Number of vertices (and number of edges)
int nvertices; int nvertices;
// Halfedge array for this face // Halfedge array for this face
// HbrHalfedge::GetIndex() relies on this being size 4 // HbrHalfedge::GetIndex() relies on this being size 4
HbrHalfedge<T> edges[4]; HbrHalfedge<T> edges[4];
// Edge storage if this face is not a triangle or quad // Edge storage if this face is not a triangle or quad
@ -333,18 +335,18 @@ private:
StitchEdge **stitchEdges; StitchEdge **stitchEdges;
void **stitchDatas; void **stitchDatas;
#endif #endif
// Pointer to a list of hierarchical edits applicable to this face // Pointer to a list of hierarchical edits applicable to this face
HbrHierarchicalEdit<T>** edits; HbrHierarchicalEdit<T>** edits;
// Blind client data pointer // Blind client data pointer
void * clientData; void * clientData;
// Depth of the face in the mesh hierarchy - coarse faces are // Depth of the face in the mesh hierarchy - coarse faces are
// level 0. (Hmmm.. is it safe to assume that we'll never // level 0. (Hmmm.. is it safe to assume that we'll never
// subdivide to greater than 255?) // subdivide to greater than 255?)
unsigned char depth; unsigned char depth;
unsigned short hole:1; unsigned short hole:1;
unsigned short coarse:1; unsigned short coarse:1;
unsigned short protect:1; unsigned short protect:1;
@ -406,12 +408,12 @@ HbrFace<T>::Initialize(HbrMesh<T>* m, HbrFace<T>* _parent, int childindex, int f
int fvarbitsSizePerEdge = ((fvarcount + 15) / 16); int fvarbitsSizePerEdge = ((fvarcount + 15) / 16);
if (nv > 4) { if (nv > 4) {
// If we have more than four vertices, we ignore the // If we have more than four vertices, we ignore the
// overallocation and allocate our own buffers for stitch // overallocation and allocate our own buffers for stitch
// edges and facevarying data. // edges and facevarying data.
#ifdef HBRSTITCH #ifdef HBRSTITCH
if (mesh->GetStitchCount()) { if (mesh->GetStitchCount()) {
stitchEdges = new StitchEdge*[mesh->GetStitchCount() * nv]; stitchEdges = new StitchEdge*[mesh->GetStitchCount() * nv];
stitchDatas = new void*[nv]; stitchDatas = new void*[nv];
for (i = 0; i < mesh->GetStitchCount() * nv; ++i) { for (i = 0; i < mesh->GetStitchCount() * nv; ++i) {
@ -433,8 +435,8 @@ HbrFace<T>::Initialize(HbrMesh<T>* m, HbrFace<T>* _parent, int childindex, int f
// We also ignore the edge array and allocate extra storage - // We also ignore the edge array and allocate extra storage -
// this simplifies GetNext and GetPrev math in HbrHalfede // this simplifies GetNext and GetPrev math in HbrHalfede
extraedges = new HbrHalfedge<T>[nv]; extraedges = new HbrHalfedge<T>[nv];
} else { } else {
// Under four vertices: upstream allocation for the class has // Under four vertices: upstream allocation for the class has
// been over allocated to include storage for stitchEdges // been over allocated to include storage for stitchEdges
@ -458,12 +460,12 @@ HbrFace<T>::Initialize(HbrMesh<T>* m, HbrFace<T>* _parent, int childindex, int f
fvarbits = (unsigned int*) buffer; fvarbits = (unsigned int*) buffer;
} }
} }
// Must do this before we create edges // Must do this before we create edges
if (_parent) { if (_parent) {
_parent->SetChild(childindex, this); _parent->SetChild(childindex, this);
} }
// Edges must be constructed in this two part approach: we must // Edges must be constructed in this two part approach: we must
// ensure that opposite/next/previous ptrs are all set up // ensure that opposite/next/previous ptrs are all set up
// correctly, before we can begin adding incident edges to // correctly, before we can begin adding incident edges to
@ -471,16 +473,16 @@ HbrFace<T>::Initialize(HbrMesh<T>* m, HbrFace<T>* _parent, int childindex, int f
int next; int next;
unsigned int *curfvarbits = fvarbits; unsigned int *curfvarbits = fvarbits;
for (i = 0, next = 1; i < nv; ++i, ++next) { for (i = 0, next = 1; i < nv; ++i, ++next) {
if (next == nv) next = 0; if (next == nv) next = 0;
HbrHalfedge<T>* opposite = vertices[next]->GetEdge(vertices[i]); HbrHalfedge<T>* opposite = vertices[next]->GetEdge(vertices[i]);
GetEdge(i)->Initialize(opposite, i, vertices[i], curfvarbits, this); GetEdge(i)->Initialize(opposite, i, vertices[i], curfvarbits, this);
if (opposite) opposite->SetOpposite(GetEdge(i)); if (opposite) opposite->SetOpposite(GetEdge(i));
if (fvarbits) { if (fvarbits) {
curfvarbits = curfvarbits + fvarbitsSizePerEdge; curfvarbits = curfvarbits + fvarbitsSizePerEdge;
} }
} }
for (i = 0; i < nv; ++i) { for (i = 0; i < nv; ++i) {
vertices[i]->AddIncidentEdge(GetEdge(i)); vertices[i]->AddIncidentEdge(GetEdge(i));
} }
} }
@ -493,80 +495,80 @@ template <class T>
void void
HbrFace<T>::Destroy() { HbrFace<T>::Destroy() {
if (initialized && !destroyed) { if (initialized && !destroyed) {
int i; int i;
#ifdef HBRSTITCH #ifdef HBRSTITCH
const int stitchCount = mesh->GetStitchCount(); const int stitchCount = mesh->GetStitchCount();
#endif #endif
// Remove children's references to self // Remove children's references to self
if (children) { if (children) {
int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices); int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices);
for (i = 0; i < nchildren; ++i) { for (i = 0; i < nchildren; ++i) {
if (children[i]) { if (children[i]) {
children[i]->parent = 0; children[i]->parent = 0;
children[i] = 0; children[i] = 0;
} }
} }
delete[] children; delete[] children;
children = 0; children = 0;
} }
// Deleting the incident edges from the vertices in this way is // Deleting the incident edges from the vertices in this way is
// the safest way of doing things. Doing it in the halfedge // the safest way of doing things. Doing it in the halfedge
// destructor will not work well because it disrupts cycle // destructor will not work well because it disrupts cycle
// finding/incident edge replacement in the vertex code. // finding/incident edge replacement in the vertex code.
// We also take this time to clean up any orphaned stitches // We also take this time to clean up any orphaned stitches
// still belonging to the edges. // still belonging to the edges.
for (i = 0; i < nvertices; ++i) { for (i = 0; i < nvertices; ++i) {
HbrHalfedge<T> *edge = GetEdge(i); HbrHalfedge<T> *edge = GetEdge(i);
#ifdef HBRSTITCH #ifdef HBRSTITCH
edge->DestroyStitchEdges(stitchCount); edge->DestroyStitchEdges(stitchCount);
#endif #endif
HbrVertex<T>* vertex = edge->GetOrgVertex(); HbrVertex<T>* vertex = edge->GetOrgVertex();
if (fvarbits) { if (fvarbits) {
HbrFVarData<T>& fvt = vertex->GetFVarData(this); HbrFVarData<T>& fvt = vertex->GetFVarData(this);
if (fvt.GetFace() == this) { if (fvt.GetFace() == this) {
fvt.SetFace(0); fvt.SetFace(0);
} }
} }
vertex->RemoveIncidentEdge(edge); vertex->RemoveIncidentEdge(edge);
vertex->UnGuaranteeNeighbors(); vertex->UnGuaranteeNeighbors();
} }
if (extraedges) { if (extraedges) {
delete[] extraedges; delete[] extraedges;
extraedges = 0; extraedges = 0;
} }
// Remove parent's reference to self // Remove parent's reference to self
if (parent) { if (parent) {
bool parentHasOtherKids = false; bool parentHasOtherKids = false;
assert(parent->children); assert(parent->children);
int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(parent->nvertices); int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(parent->nvertices);
for (i = 0; i < nchildren; ++i) { for (i = 0; i < nchildren; ++i) {
if (parent->children[i] == this) { if (parent->children[i] == this) {
parent->children[i] = 0; parent->children[i] = 0;
} else if (parent->children[i]) parentHasOtherKids = true; } else if (parent->children[i]) parentHasOtherKids = true;
} }
// After cleaning the parent's reference to self, the parent // After cleaning the parent's reference to self, the parent
// may be able to clean itself up // may be able to clean itself up
if (!parentHasOtherKids) { if (!parentHasOtherKids) {
delete[] parent->children; delete[] parent->children;
parent->children = 0; parent->children = 0;
if (parent->GarbageCollectable()) { if (parent->GarbageCollectable()) {
mesh->DeleteFace(parent); mesh->DeleteFace(parent);
} }
} }
parent = 0; parent = 0;
} }
// Orphan the child vertex // Orphan the child vertex
if (vchild) { if (vchild) {
vchild->SetParent(static_cast<HbrFace*>(0)); vchild->SetParent(static_cast<HbrFace*>(0));
vchild = 0; vchild = 0;
} }
if (nvertices > 4 && fvarbits) { if (nvertices > 4 && fvarbits) {
free(fvarbits); free(fvarbits);
#ifdef HBRSTITCH #ifdef HBRSTITCH
if (stitchEdges) { if (stitchEdges) {
delete[] stitchEdges; delete[] stitchEdges;
@ -582,16 +584,16 @@ HbrFace<T>::Destroy() {
stitchDatas = 0; stitchDatas = 0;
#endif #endif
// Make sure the four edges intrinsic to face are properly cleared // Make sure the four edges intrinsic to face are properly cleared
// if they were used // if they were used
if (nvertices <= 4) { if (nvertices <= 4) {
for (i = 0; i < nvertices; ++i) { for (i = 0; i < nvertices; ++i) {
GetEdge(i)->Clear(); GetEdge(i)->Clear();
} }
} }
nvertices = 0; nvertices = 0;
initialized = 0; initialized = 0;
destroyed = 1; destroyed = 1;
} }
} }
@ -600,36 +602,36 @@ HbrHalfedge<T>*
HbrFace<T>::GetEdge(int index) const { HbrFace<T>::GetEdge(int index) const {
assert(index >= 0 && index < nvertices); assert(index >= 0 && index < nvertices);
if (nvertices > 4) { if (nvertices > 4) {
return extraedges + index; return extraedges + index;
} else { } else {
return const_cast<HbrHalfedge<T>*>(edges + index); return const_cast<HbrHalfedge<T>*>(edges + index);
} }
} }
template <class T> template <class T>
HbrVertex<T>* HbrVertex<T>*
HbrFace<T>::GetVertex(int index) const { HbrFace<T>::GetVertex(int index) const {
assert(index >= 0 && index < nvertices); assert(index >= 0 && index < nvertices);
if (nvertices > 4) { if (nvertices > 4) {
return extraedges[index].GetOrgVertex(); return extraedges[index].GetOrgVertex();
} else { } else {
return edges[index].GetOrgVertex(); return edges[index].GetOrgVertex();
} }
} }
template <class T> template <class T>
void void
HbrFace<T>::SetChild(int index, HbrFace<T>* face) { HbrFace<T>::SetChild(int index, HbrFace<T>* face) {
// Construct the children array if it doesn't already exist // Construct the children array if it doesn't already exist
int i; int i;
if (!children) { if (!children) {
int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices); int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices);
children = new HbrFace<T>*[nchildren]; children = new HbrFace<T>*[nchildren];
for (i = 0; i < nchildren; ++i) { for (i = 0; i < nchildren; ++i) {
children[i] = 0; children[i] = 0;
} }
} }
children[index] = face; children[index] = face;
face->parent = this; face->parent = this;
} }
@ -655,11 +657,11 @@ HbrFace<T>::Unrefine() {
// references to the children) // references to the children)
if (children) { if (children) {
int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices); int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices);
for (int i = 0; i < nchildren; ++i) { for (int i = 0; i < nchildren; ++i) {
if (children[i]) mesh->DeleteFace(children[i]); if (children[i]) mesh->DeleteFace(children[i]);
} }
delete[] children; delete[] children;
children = 0; children = 0;
} }
} }
@ -680,24 +682,24 @@ void
HbrFace<T>::MarkUsage() { HbrFace<T>::MarkUsage() {
// Must increment the usage on all vertices which are in the // Must increment the usage on all vertices which are in the
// support for this face // support for this face
HbrVertex<T>* v; HbrVertex<T>* v;
HbrHalfedge<T>* e = GetFirstEdge(), *ee, *eee, *start; HbrHalfedge<T>* e = GetFirstEdge(), *ee, *eee, *start;
for (int i = 0; i < nvertices; ++i) { for (int i = 0; i < nvertices; ++i) {
v = e->GetOrgVertex(); v = e->GetOrgVertex();
v->GuaranteeNeighbors(); v->GuaranteeNeighbors();
start = v->GetIncidentEdge(); start = v->GetIncidentEdge();
ee = start; ee = start;
do { do {
HbrFace<T>* f = ee->GetLeftFace(); HbrFace<T>* f = ee->GetLeftFace();
eee = f->GetFirstEdge(); eee = f->GetFirstEdge();
for (int j = 0; j < f->GetNumVertices(); ++j) { for (int j = 0; j < f->GetNumVertices(); ++j) {
eee->GetOrgVertex()->IncrementUsage(); eee->GetOrgVertex()->IncrementUsage();
eee = eee->GetNext(); eee = eee->GetNext();
} }
ee = v->GetNextEdge(ee); ee = v->GetNextEdge(ee);
if (ee == start) break; if (ee == start) break;
} while (ee); } while (ee);
e = e->GetNext(); e = e->GetNext();
} }
} }
@ -707,28 +709,28 @@ HbrFace<T>::ClearUsage() {
bool gc = false; bool gc = false;
// Must mark all vertices which may affect this face // Must mark all vertices which may affect this face
HbrVertex<T>* v, *vv; HbrVertex<T>* v, *vv;
HbrHalfedge<T>* e = GetFirstEdge(), *ee, *eee, *start; HbrHalfedge<T>* e = GetFirstEdge(), *ee, *eee, *start;
for (int i = 0; i < nvertices; ++i) { for (int i = 0; i < nvertices; ++i) {
v = e->GetOrgVertex(); v = e->GetOrgVertex();
start = v->GetIncidentEdge(); start = v->GetIncidentEdge();
ee = start; ee = start;
do { do {
HbrFace<T>* f = ee->GetLeftFace(); HbrFace<T>* f = ee->GetLeftFace();
eee = f->GetFirstEdge(); eee = f->GetFirstEdge();
for (int j = 0; j < f->GetNumVertices(); ++j) { for (int j = 0; j < f->GetNumVertices(); ++j) {
vv = eee->GetOrgVertex(); vv = eee->GetOrgVertex();
vv->DecrementUsage(); vv->DecrementUsage();
if (!vv->IsUsed()) { if (!vv->IsUsed()) {
mesh->AddGarbageCollectableVertex(vv); mesh->AddGarbageCollectableVertex(vv);
gc = true; gc = true;
} }
eee = eee->GetNext(); eee = eee->GetNext();
} }
ee = v->GetNextEdge(ee); ee = v->GetNextEdge(ee);
if (ee == start) break; if (ee == start) break;
} while (ee); } while (ee);
e = e->GetNext(); e = e->GetNext();
} }
if (gc) mesh->GarbageCollect(); if (gc) mesh->GarbageCollect();
} }
@ -738,12 +740,12 @@ bool
HbrFace<T>::GarbageCollectable() const { HbrFace<T>::GarbageCollectable() const {
if (children || protect) return false; if (children || protect) return false;
for (int i = 0; i < nvertices; ++i) { for (int i = 0; i < nvertices; ++i) {
HbrHalfedge<T>* edge = GetEdge(i); HbrHalfedge<T>* edge = GetEdge(i);
HbrVertex<T>* vertex = edge->GetOrgVertex(); HbrVertex<T>* vertex = edge->GetOrgVertex();
if (vertex->IsUsed()) return false; if (vertex->IsUsed()) return false;
if (!GetParent() && vertex->EdgeRemovalWillMakeSingular(edge)) { if (!GetParent() && vertex->EdgeRemovalWillMakeSingular(edge)) {
return false; return false;
} }
} }
return true; return true;
} }
@ -755,9 +757,9 @@ HbrFace<T>::SetHierarchicalEdits(HbrHierarchicalEdit<T>** _edits) {
// Walk the list of edits and look for any which apply locally. // Walk the list of edits and look for any which apply locally.
while (HbrHierarchicalEdit<T>* edit = *_edits) { while (HbrHierarchicalEdit<T>* edit = *_edits) {
if (!edit->IsRelevantToFace(this)) break; if (!edit->IsRelevantToFace(this)) break;
edit->ApplyEditToFace(this); edit->ApplyEditToFace(this);
_edits++; _edits++;
} }
} }
@ -765,13 +767,13 @@ template <class T>
std::ostream& operator<<(std::ostream& out, const HbrFace<T>& face) { std::ostream& operator<<(std::ostream& out, const HbrFace<T>& face) {
out << "face " << face.GetID() << ", " << face.GetNumVertices() << " vertices ("; out << "face " << face.GetID() << ", " << face.GetNumVertices() << " vertices (";
for (int i = 0; i < face.GetNumVertices(); ++i) { for (int i = 0; i < face.GetNumVertices(); ++i) {
HbrHalfedge<T>* e = face.GetEdge(i); HbrHalfedge<T>* e = face.GetEdge(i);
out << *(e->GetOrgVertex()); out << *(e->GetOrgVertex());
if (e->IsBoundary()) { if (e->IsBoundary()) {
out << " -/-> "; out << " -/-> ";
} else { } else {
out << " ---> "; out << " ---> ";
} }
} }
out << ")"; out << ")";
return out; return out;

View File

@ -70,7 +70,7 @@ template <class T>
std::ostream& operator<<(std::ostream& out, const HbrFaceEdit<T>& path) { std::ostream& operator<<(std::ostream& out, const HbrFaceEdit<T>& path) {
out << "face path = (" << path.faceid << ' '; out << "face path = (" << path.faceid << ' ';
for (int i = 0; i < path.nsubfaces; ++i) { for (int i = 0; i < path.nsubfaces; ++i) {
out << static_cast<int>(path.subfaces[i]) << ' '; out << static_cast<int>(path.subfaces[i]) << ' ';
} }
return out << ")"; return out << ")";
} }
@ -81,35 +81,35 @@ class HbrFaceEdit : public HbrHierarchicalEdit<T> {
public: public:
HbrFaceEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, int _index, int _width, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit) HbrFaceEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, int _index, int _width, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), index(_index), width(_width), op(_op) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), index(_index), width(_width), op(_op) {
edit = new float[width]; edit = new float[width];
memcpy(edit, _edit, width * sizeof(float)); memcpy(edit, _edit, width * sizeof(float));
} }
HbrFaceEdit(int _faceid, int _nsubfaces, int *_subfaces, int _index, int _width, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit) HbrFaceEdit(int _faceid, int _nsubfaces, int *_subfaces, int _index, int _width, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), index(_index), width(_width), op(_op) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), index(_index), width(_width), op(_op) {
edit = new float[width]; edit = new float[width];
memcpy(edit, _edit, width * sizeof(float)); memcpy(edit, _edit, width * sizeof(float));
} }
#ifdef PRMAN #ifdef PRMAN
HbrFaceEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, int _index, int _width, typename HbrHierarchicalEdit<T>::Operation _op, RtToken _edit) HbrFaceEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, int _index, int _width, typename HbrHierarchicalEdit<T>::Operation _op, RtToken _edit)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), index(_index), width(_width), op(_op) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), index(_index), width(_width), op(_op) {
edit = new float[width]; edit = new float[width];
RtString* sedit = (RtString*) edit; RtString* sedit = (RtString*) edit;
*sedit = _edit; *sedit = _edit;
} }
HbrFaceEdit(int _faceid, int _nsubfaces, int *_subfaces, int _index, int _width, typename HbrHierarchicalEdit<T>::Operation _op, RtToken _edit) HbrFaceEdit(int _faceid, int _nsubfaces, int *_subfaces, int _index, int _width, typename HbrHierarchicalEdit<T>::Operation _op, RtToken _edit)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), index(_index), width(_width), op(_op) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), index(_index), width(_width), op(_op) {
edit = new float[width]; edit = new float[width];
RtString* sedit = (RtString*) edit; RtString* sedit = (RtString*) edit;
*sedit = _edit; *sedit = _edit;
} }
#endif #endif
virtual ~HbrFaceEdit() { virtual ~HbrFaceEdit() {
delete[] edit; delete[] edit;
} }
friend std::ostream& operator<< <T> (std::ostream& out, const HbrFaceEdit<T>& path); friend std::ostream& operator<< <T> (std::ostream& out, const HbrFaceEdit<T>& path);
@ -125,17 +125,17 @@ public:
// Get the type of operation // Get the type of operation
typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; } typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; }
virtual void ApplyEditToFace(HbrFace<T>* face) { virtual void ApplyEditToFace(HbrFace<T>* face) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) { if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
int oldUniformIndex = face->GetUniformIndex(); int oldUniformIndex = face->GetUniformIndex();
// Change the face's uniform index // Change the face's uniform index
face->SetUniformIndex(face->GetMesh()->NewUniformIndex()); face->SetUniformIndex(face->GetMesh()->NewUniformIndex());
// Apply edit // Apply edit
face->GetVertex(0)->GetData().ApplyFaceEdit(oldUniformIndex, face->GetUniformIndex(), *const_cast<const HbrFaceEdit<T>*>(this)); face->GetVertex(0)->GetData().ApplyFaceEdit(oldUniformIndex, face->GetUniformIndex(), *const_cast<const HbrFaceEdit<T>*>(this));
} }
} }
private: private:

View File

@ -76,7 +76,7 @@ template <class T> class HbrFVarData {
public: public:
HbrFVarData(float *dataptr) HbrFVarData(float *dataptr)
: initialized(false), face(0), data(dataptr) { : initialized(false), face(0), data(dataptr) {
} }
~HbrFVarData() { ~HbrFVarData() {
@ -92,7 +92,7 @@ public:
const HbrFace<T> * GetFace() const { const HbrFace<T> * GetFace() const {
return face; return face;
} }
// Clears the initialized flag // Clears the initialized flag
void Uninitialize() { void Uninitialize() {
initialized = false; initialized = false;
@ -108,7 +108,7 @@ public:
void SetInitialized() { void SetInitialized() {
initialized = true; initialized = true;
} }
// Return the data from the NgpFVVector // Return the data from the NgpFVVector
float* GetData(int item) const { return &data[item]; } float* GetData(int item) const { return &data[item]; }
@ -116,8 +116,8 @@ public:
void Clear(int startindex, int width) { void Clear(int startindex, int width) {
memset(data + startindex, 0, width * sizeof(float)); memset(data + startindex, 0, width * sizeof(float));
} }
// Clears all values of this item // Clears all values of this item
void ClearAll(int width) { void ClearAll(int width) {
initialized = true; initialized = true;
memset(data, 0, width * sizeof(float)); memset(data, 0, width * sizeof(float));
@ -127,27 +127,27 @@ public:
// on this item // on this item
void SetWithWeight(const HbrFVarData& fvvi, int startindex, int width, float weight) { void SetWithWeight(const HbrFVarData& fvvi, int startindex, int width, float weight) {
float *dst = data + startindex, *src = fvvi.data + startindex; float *dst = data + startindex, *src = fvvi.data + startindex;
for (int i = 0; i < width; ++i) { for (int i = 0; i < width; ++i) {
*dst++ = weight * *src++; *dst++ = weight * *src++;
} }
} }
// Add values of the indicated item (with the indicated weighing) // Add values of the indicated item (with the indicated weighing)
// to this item // to this item
void AddWithWeight(const HbrFVarData& fvvi, int startindex, int width, float weight) { void AddWithWeight(const HbrFVarData& fvvi, int startindex, int width, float weight) {
float *dst = data + startindex, *src = fvvi.data + startindex; float *dst = data + startindex, *src = fvvi.data + startindex;
for (int i = 0; i < width; ++i) { for (int i = 0; i < width; ++i) {
*dst++ += weight * *src++; *dst++ += weight * *src++;
} }
} }
// Add all values of the indicated item (with the indicated // Add all values of the indicated item (with the indicated
// weighing) to this item // weighing) to this item
void AddWithWeightAll(const HbrFVarData& fvvi, int width, float weight) { void AddWithWeightAll(const HbrFVarData& fvvi, int width, float weight) {
float *dst = data, *src = fvvi.data; float *dst = data, *src = fvvi.data;
for (int i = 0; i < width; ++i) { for (int i = 0; i < width; ++i) {
*dst++ += weight * *src++; *dst++ += weight * *src++;
} }
} }
// Compare all values item against a float buffer. Returns true // Compare all values item against a float buffer. Returns true
@ -165,7 +165,7 @@ public:
initialized = true; initialized = true;
memcpy(data, values, width * sizeof(float)); memcpy(data, values, width * sizeof(float));
} }
// Compare this item against another item with tolerance. Returns // Compare this item against another item with tolerance. Returns
// true if it compares identical // true if it compares identical
bool Compare(const HbrFVarData& fvvi, int startindex, int width, float tolerance=0.0f) const { bool Compare(const HbrFVarData& fvvi, int startindex, int width, float tolerance=0.0f) const {
@ -177,7 +177,7 @@ public:
// Modify the data of the item with an edit // Modify the data of the item with an edit
void ApplyFVarEdit(const HbrFVarEdit<T>& edit); void ApplyFVarEdit(const HbrFVarEdit<T>& edit);
private: private:
bool initialized; bool initialized;
const HbrFace<T> *face; const HbrFace<T> *face;
@ -197,20 +197,20 @@ namespace OPENSUBDIV_VERSION {
template <class T> template <class T>
void void
HbrFVarData<T>::ApplyFVarEdit(const HbrFVarEdit<T>& edit) { HbrFVarData<T>::ApplyFVarEdit(const HbrFVarEdit<T>& edit) {
float *dst = data + edit.GetIndex() + edit.GetOffset(); float *dst = data + edit.GetIndex() + edit.GetOffset();
const float *src = edit.GetEdit(); const float *src = edit.GetEdit();
for (int i = 0; i < edit.GetWidth(); ++i) { for (int i = 0; i < edit.GetWidth(); ++i) {
switch(edit.GetOperation()) { switch(edit.GetOperation()) {
case HbrVertexEdit<T>::Set: case HbrVertexEdit<T>::Set:
*dst++ = *src++; *dst++ = *src++;
break; break;
case HbrVertexEdit<T>::Add: case HbrVertexEdit<T>::Add:
*dst++ += *src++; *dst++ += *src++;
break; break;
case HbrVertexEdit<T>::Subtract: case HbrVertexEdit<T>::Subtract:
*dst++ -= *src++; *dst++ -= *src++;
} }
} }
initialized = true; initialized = true;
} }

View File

@ -71,7 +71,7 @@ template <class T>
std::ostream& operator<<(std::ostream& out, const HbrFVarEdit<T>& path) { std::ostream& operator<<(std::ostream& out, const HbrFVarEdit<T>& path) {
out << "vertex path = (" << path.faceid << ' '; out << "vertex path = (" << path.faceid << ' ';
for (int i = 0; i < path.nsubfaces; ++i) { for (int i = 0; i < path.nsubfaces; ++i) {
out << static_cast<int>(path.subfaces[i]) << ' '; out << static_cast<int>(path.subfaces[i]) << ' ';
} }
return out << static_cast<int>(path.vertexid) << "), edit = (" << path.edit[0] << ',' << path.edit[1] << ',' << path.edit[2] << ')'; return out << static_cast<int>(path.vertexid) << "), edit = (" << path.edit[0] << ',' << path.edit[1] << ',' << path.edit[2] << ')';
} }
@ -82,24 +82,24 @@ class HbrFVarEdit : public HbrHierarchicalEdit<T> {
public: public:
HbrFVarEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _vertexid, int _index, int _width, int _offset, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit) HbrFVarEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _vertexid, int _index, int _width, int _offset, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), offset(_offset), op(_op) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), offset(_offset), op(_op) {
edit = new float[width]; edit = new float[width];
memcpy(edit, _edit, width * sizeof(float)); memcpy(edit, _edit, width * sizeof(float));
} }
HbrFVarEdit(int _faceid, int _nsubfaces, int *_subfaces, int _vertexid, int _index, int _width, int _offset, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit) HbrFVarEdit(int _faceid, int _nsubfaces, int *_subfaces, int _vertexid, int _index, int _width, int _offset, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), offset(_offset), op(_op) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), offset(_offset), op(_op) {
edit = new float[width]; edit = new float[width];
memcpy(edit, _edit, width * sizeof(float)); memcpy(edit, _edit, width * sizeof(float));
} }
virtual ~HbrFVarEdit() { virtual ~HbrFVarEdit() {
delete[] edit; delete[] edit;
} }
// Return the vertex id (the last element in the path) // Return the vertex id (the last element in the path)
unsigned char GetVertexID() const { return vertexid; } unsigned char GetVertexID() const { return vertexid; }
friend std::ostream& operator<< <T> (std::ostream& out, const HbrFVarEdit<T>& path); friend std::ostream& operator<< <T> (std::ostream& out, const HbrFVarEdit<T>& path);
// Return index into the facevarying data // Return index into the facevarying data
@ -110,15 +110,15 @@ public:
// Return offset of the data // Return offset of the data
int GetOffset() const { return offset; } int GetOffset() const { return offset; }
// Get the numerical value of the edit // Get the numerical value of the edit
const float* GetEdit() const { return edit; } const float* GetEdit() const { return edit; }
// Get the type of operation // Get the type of operation
typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; } typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; }
virtual void ApplyEditToFace(HbrFace<T>* face) { virtual void ApplyEditToFace(HbrFace<T>* face) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) { if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
// The edit will modify the data and almost certainly // The edit will modify the data and almost certainly
// create a discontinuity, so allocate storage for a new // create a discontinuity, so allocate storage for a new
// copy of the existing data specific to the face (or use // copy of the existing data specific to the face (or use
@ -132,7 +132,7 @@ public:
} else { } else {
fvt.ApplyFVarEdit(*const_cast<const HbrFVarEdit<T>*>(this)); fvt.ApplyFVarEdit(*const_cast<const HbrFVarEdit<T>*>(this));
} }
} }
} }
private: private:

View File

@ -94,7 +94,7 @@ public:
~HbrHalfedge(); ~HbrHalfedge();
void Clear(); void Clear();
// Finish the initialization of the halfedge. Should only be // Finish the initialization of the halfedge. Should only be
// called by HbrFace // called by HbrFace
void Initialize(HbrHalfedge<T>* opposite, int index, HbrVertex<T>* origin, unsigned int *fvarbits, HbrFace<T>* face); void Initialize(HbrHalfedge<T>* opposite, int index, HbrVertex<T>* origin, unsigned int *fvarbits, HbrFace<T>* face);
@ -136,7 +136,7 @@ public:
return this - incidentFace->extraedges; return this - incidentFace->extraedges;
} }
} }
// Returns the incident vertex // Returns the incident vertex
HbrVertex<T>* GetVertex() const { HbrVertex<T>* GetVertex() const {
return incidentVertex; return incidentVertex;
@ -149,16 +149,16 @@ public:
// Changes the origin vertex. Generally not a good idea to do // Changes the origin vertex. Generally not a good idea to do
void SetOrgVertex(HbrVertex<T>* v) { incidentVertex = v; } void SetOrgVertex(HbrVertex<T>* v) { incidentVertex = v; }
// Returns the destination vertex // Returns the destination vertex
HbrVertex<T>* GetDestVertex() const { return GetNext()->GetOrgVertex(); } HbrVertex<T>* GetDestVertex() const { return GetNext()->GetOrgVertex(); }
// Returns the incident facet // Returns the incident facet
HbrFace<T>* GetFace() const { return incidentFace; } HbrFace<T>* GetFace() const { return incidentFace; }
// Returns the mesh to which this edge belongs // Returns the mesh to which this edge belongs
HbrMesh<T>* GetMesh() const { return incidentFace->GetMesh(); } HbrMesh<T>* GetMesh() const { return incidentFace->GetMesh(); }
// Returns the face on the right // Returns the face on the right
HbrFace<T>* GetRightFace() const { return opposite ? opposite->GetLeftFace() : NULL; } HbrFace<T>* GetRightFace() const { return opposite ? opposite->GetLeftFace() : NULL; }
@ -173,7 +173,7 @@ public:
int intindex = datum >> 4; int intindex = datum >> 4;
unsigned int bits = infsharp << ((datum & 15) * 2); unsigned int bits = infsharp << ((datum & 15) * 2);
getFVarInfSharp()[intindex] |= bits; getFVarInfSharp()[intindex] |= bits;
if (opposite) { if (opposite) {
opposite->getFVarInfSharp()[intindex] |= bits; opposite->getFVarInfSharp()[intindex] |= bits;
} }
} }
@ -187,7 +187,7 @@ public:
memcpy(fvarinfsharp, edge->getFVarInfSharp(), fvarbitsSizePerEdge * sizeof(unsigned int)); memcpy(fvarinfsharp, edge->getFVarInfSharp(), fvarbitsSizePerEdge * sizeof(unsigned int));
} }
} }
// Returns whether the edge is infinitely sharp in facevarying for // Returns whether the edge is infinitely sharp in facevarying for
// a particular facevarying datum // a particular facevarying datum
bool GetFVarInfiniteSharp(int datum); bool GetFVarInfiniteSharp(int datum);
@ -198,7 +198,7 @@ public:
// Get the sharpness relative to facevarying data // Get the sharpness relative to facevarying data
float GetFVarSharpness(int datum, bool ignoreGeometry=false); float GetFVarSharpness(int datum, bool ignoreGeometry=false);
// Returns the (raw) sharpness of the edge // Returns the (raw) sharpness of the edge
float GetSharpness() const { return sharpness; } float GetSharpness() const { return sharpness; }
@ -209,7 +209,7 @@ public:
// subdivision (next = false) or at the next level of subdivision // subdivision (next = false) or at the next level of subdivision
// (next = true). // (next = true).
bool IsSharp(bool next) const { return (next ? (sharpness > 0.0f) : (sharpness >= 1.0f)); } bool IsSharp(bool next) const { return (next ? (sharpness > 0.0f) : (sharpness >= 1.0f)); }
// Clears the masks of the adjacent edge vertices. Usually called // Clears the masks of the adjacent edge vertices. Usually called
// when a change in edge sharpness occurs. // when a change in edge sharpness occurs.
void ClearMask() { GetOrgVertex()->ClearMask(); GetDestVertex()->ClearMask(); } void ClearMask() { GetOrgVertex()->ClearMask(); GetDestVertex()->ClearMask(); }
@ -219,38 +219,38 @@ public:
// Make sure the edge has its opposite face // Make sure the edge has its opposite face
void GuaranteeNeighbor(); void GuaranteeNeighbor();
// Remove the reference to subdivided vertex // Remove the reference to subdivided vertex
void RemoveChild() { vchild = 0; } void RemoveChild() { vchild = 0; }
// Sharpness constants // Sharpness constants
enum Mask { enum Mask {
k_Smooth = 0, k_Smooth = 0,
k_Sharp = 1, k_Sharp = 1,
k_InfinitelySharp = 10 k_InfinitelySharp = 10
}; };
#ifdef HBRSTITCH #ifdef HBRSTITCH
StitchEdge* GetStitchEdge(int i) { StitchEdge* GetStitchEdge(int i) {
StitchEdge **stitchEdge = getStitchEdges(); StitchEdge **stitchEdge = getStitchEdges();
// If the stitch edge exists, the ownership is transferred to // If the stitch edge exists, the ownership is transferred to
// the caller. Make sure the opposite edge loses ownership as // the caller. Make sure the opposite edge loses ownership as
// well. // well.
if (stitchEdge[i]) { if (stitchEdge[i]) {
if (opposite) { if (opposite) {
opposite->getStitchEdges()[i] = 0; opposite->getStitchEdges()[i] = 0;
} }
return StitchGetEdge(&stitchEdge[i]); return StitchGetEdge(&stitchEdge[i]);
} }
// If the stitch edge does not exist then we create one now. // If the stitch edge does not exist then we create one now.
// Make sure the opposite edge gets a copy of it too // Make sure the opposite edge gets a copy of it too
else { else {
StitchGetEdge(&stitchEdge[i]); StitchGetEdge(&stitchEdge[i]);
if (opposite) { if (opposite) {
opposite->getStitchEdges()[i] = stitchEdge[i]; opposite->getStitchEdges()[i] = stitchEdge[i];
} }
return stitchEdge[i]; return stitchEdge[i];
} }
} }
// If stitch edge exists, and this edge has no opposite, destroy // If stitch edge exists, and this edge has no opposite, destroy
@ -266,70 +266,70 @@ public:
} }
} }
} }
StitchEdge* GetRayStitchEdge(int i) { StitchEdge* GetRayStitchEdge(int i) {
return GetStitchEdge(i + 2); return GetStitchEdge(i + 2);
} }
// Splits our split edge between our children. We'd better have // Splits our split edge between our children. We'd better have
// subdivided this edge by this point // subdivided this edge by this point
void SplitStitchEdge(int i) { void SplitStitchEdge(int i) {
StitchEdge* se = GetStitchEdge(i); StitchEdge* se = GetStitchEdge(i);
HbrHalfedge<T>* ea = GetOrgVertex()->Subdivide()->GetEdge(Subdivide()); HbrHalfedge<T>* ea = GetOrgVertex()->Subdivide()->GetEdge(Subdivide());
HbrHalfedge<T>* eb = Subdivide()->GetEdge(GetDestVertex()->Subdivide()); HbrHalfedge<T>* eb = Subdivide()->GetEdge(GetDestVertex()->Subdivide());
StitchEdge **ease = ea->getStitchEdges(); StitchEdge **ease = ea->getStitchEdges();
StitchEdge **ebse = eb->getStitchEdges(); StitchEdge **ebse = eb->getStitchEdges();
if (i >= 2) { // ray tracing stitches if (i >= 2) { // ray tracing stitches
if (!raystitchccw) { if (!raystitchccw) {
StitchSplitEdge(se, &ease[i], &ebse[i], false, 0, 0, 0); StitchSplitEdge(se, &ease[i], &ebse[i], false, 0, 0, 0);
} else { } else {
StitchSplitEdge(se, &ebse[i], &ease[i], true, 0, 0, 0); StitchSplitEdge(se, &ebse[i], &ease[i], true, 0, 0, 0);
} }
ea->raystitchccw = eb->raystitchccw = raystitchccw; ea->raystitchccw = eb->raystitchccw = raystitchccw;
if (eb->opposite) { if (eb->opposite) {
eb->opposite->getStitchEdges()[i] = ebse[i]; eb->opposite->getStitchEdges()[i] = ebse[i];
eb->opposite->raystitchccw = raystitchccw; eb->opposite->raystitchccw = raystitchccw;
} }
if (ea->opposite) { if (ea->opposite) {
ea->opposite->getStitchEdges()[i] = ease[i]; ea->opposite->getStitchEdges()[i] = ease[i];
ea->opposite->raystitchccw = raystitchccw; ea->opposite->raystitchccw = raystitchccw;
} }
} else { } else {
if (!stitchccw) { if (!stitchccw) {
StitchSplitEdge(se, &ease[i], &ebse[i], false, 0, 0, 0); StitchSplitEdge(se, &ease[i], &ebse[i], false, 0, 0, 0);
} else { } else {
StitchSplitEdge(se, &ebse[i], &ease[i], true, 0, 0, 0); StitchSplitEdge(se, &ebse[i], &ease[i], true, 0, 0, 0);
} }
ea->stitchccw = eb->stitchccw = stitchccw; ea->stitchccw = eb->stitchccw = stitchccw;
if (eb->opposite) { if (eb->opposite) {
eb->opposite->getStitchEdges()[i] = ebse[i]; eb->opposite->getStitchEdges()[i] = ebse[i];
eb->opposite->stitchccw = stitchccw; eb->opposite->stitchccw = stitchccw;
} }
if (ea->opposite) { if (ea->opposite) {
ea->opposite->getStitchEdges()[i] = ease[i]; ea->opposite->getStitchEdges()[i] = ease[i];
ea->opposite->stitchccw = stitchccw; ea->opposite->stitchccw = stitchccw;
} }
} }
} }
void SplitRayStitchEdge(int i) { void SplitRayStitchEdge(int i) {
SplitStitchEdge(i + 2); SplitStitchEdge(i + 2);
} }
void SetStitchEdge(int i, StitchEdge* edge) { void SetStitchEdge(int i, StitchEdge* edge) {
StitchEdge **stitchEdges = getStitchEdges(); StitchEdge **stitchEdges = getStitchEdges();
stitchEdges[i] = edge; stitchEdges[i] = edge;
if (opposite) { if (opposite) {
opposite->getStitchEdges()[i] = edge; opposite->getStitchEdges()[i] = edge;
} }
} }
void SetRayStitchEdge(int i, StitchEdge* edge) { void SetRayStitchEdge(int i, StitchEdge* edge) {
StitchEdge **stitchEdges = getStitchEdges(); StitchEdge **stitchEdges = getStitchEdges();
stitchEdges[i+2] = edge; stitchEdges[i+2] = edge;
if (opposite) { if (opposite) {
opposite->getStitchEdges()[i+2] = edge; opposite->getStitchEdges()[i+2] = edge;
} }
} }
void* GetStitchData() const { void* GetStitchData() const {
@ -340,32 +340,32 @@ public:
void SetStitchData(void* data) { void SetStitchData(void* data) {
*(incidentFace->stitchDatas + GetIndex()) = data; *(incidentFace->stitchDatas + GetIndex()) = data;
stitchdatavalid = data ? 1 : 0; stitchdatavalid = data ? 1 : 0;
if (opposite) { if (opposite) {
*(opposite->incidentFace->stitchDatas + opposite->GetIndex()) = data; *(opposite->incidentFace->stitchDatas + opposite->GetIndex()) = data;
opposite->stitchdatavalid = stitchdatavalid; opposite->stitchdatavalid = stitchdatavalid;
} }
} }
bool GetStitchCCW(bool raytraced) const { return raytraced ? raystitchccw : stitchccw; } bool GetStitchCCW(bool raytraced) const { return raytraced ? raystitchccw : stitchccw; }
void ClearStitchCCW(bool raytraced) { void ClearStitchCCW(bool raytraced) {
if (raytraced) { if (raytraced) {
raystitchccw = 0; raystitchccw = 0;
if (opposite) opposite->raystitchccw = 0; if (opposite) opposite->raystitchccw = 0;
} else { } else {
stitchccw = 0; stitchccw = 0;
if (opposite) opposite->stitchccw = 0; if (opposite) opposite->stitchccw = 0;
} }
} }
void ToggleStitchCCW(bool raytraced) { void ToggleStitchCCW(bool raytraced) {
if (raytraced) { if (raytraced) {
raystitchccw = 1 - raystitchccw; raystitchccw = 1 - raystitchccw;
if (opposite) opposite->raystitchccw = raystitchccw; if (opposite) opposite->raystitchccw = raystitchccw;
} else { } else {
stitchccw = 1 - stitchccw; stitchccw = 1 - stitchccw;
if (opposite) opposite->stitchccw = stitchccw; if (opposite) opposite->stitchccw = stitchccw;
} }
} }
#endif #endif
@ -395,7 +395,7 @@ private:
unsigned char coarse:1; unsigned char coarse:1;
unsigned char lastedge:1; unsigned char lastedge:1;
unsigned char firstedge:1; unsigned char firstedge:1;
// Returns bitmask indicating whether a given facevarying datum // Returns bitmask indicating whether a given facevarying datum
// for the edge is infinitely sharp. Each datum has two bits, and // for the edge is infinitely sharp. Each datum has two bits, and
// if those two bits are set to 3, it means the status has not // if those two bits are set to 3, it means the status has not
@ -426,14 +426,14 @@ HbrHalfedge<T>::Initialize(HbrHalfedge<T>* opposite, int index, HbrVertex<T>* or
lastedge = (index == face->GetNumVertices() - 1); lastedge = (index == face->GetNumVertices() - 1);
firstedge = (index == 0); firstedge = (index == 0);
if (opposite) { if (opposite) {
sharpness = opposite->sharpness; sharpness = opposite->sharpness;
#ifdef HBRSTITCH #ifdef HBRSTITCH
StitchEdge **stitchEdges = getStitchEdges(); StitchEdge **stitchEdges = getStitchEdges();
for (int i = 0; i < face->GetMesh()->GetStitchCount(); ++i) { for (int i = 0; i < face->GetMesh()->GetStitchCount(); ++i) {
stitchEdges[i] = opposite->getStitchEdges()[i]; stitchEdges[i] = opposite->getStitchEdges()[i];
} }
stitchccw = opposite->stitchccw; stitchccw = opposite->stitchccw;
raystitchccw = opposite->raystitchccw; raystitchccw = opposite->raystitchccw;
stitchdatavalid = 0; stitchdatavalid = 0;
if (stitchEdges && opposite->GetStitchData()) { if (stitchEdges && opposite->GetStitchData()) {
*(incidentFace->stitchDatas + index) = opposite->GetStitchData(); *(incidentFace->stitchDatas + index) = opposite->GetStitchData();
@ -449,9 +449,9 @@ HbrHalfedge<T>::Initialize(HbrHalfedge<T>* opposite, int index, HbrVertex<T>* or
sharpness = 0.0f; sharpness = 0.0f;
#ifdef HBRSTITCH #ifdef HBRSTITCH
StitchEdge **stitchEdges = getStitchEdges(); StitchEdge **stitchEdges = getStitchEdges();
for (int i = 0; i < face->GetMesh()->GetStitchCount(); ++i) { for (int i = 0; i < face->GetMesh()->GetStitchCount(); ++i) {
stitchEdges[i] = 0; stitchEdges[i] = 0;
} }
stitchccw = 1; stitchccw = 1;
raystitchccw = 1; raystitchccw = 1;
stitchdatavalid = 0; stitchdatavalid = 0;
@ -461,7 +461,7 @@ HbrHalfedge<T>::Initialize(HbrHalfedge<T>* opposite, int index, HbrVertex<T>* or
int fvarbitsSizePerEdge = ((fvarcount + 15) / 16); int fvarbitsSizePerEdge = ((fvarcount + 15) / 16);
memset(fvarbits, 0xff, fvarbitsSizePerEdge * sizeof(unsigned int)); memset(fvarbits, 0xff, fvarbitsSizePerEdge * sizeof(unsigned int));
} }
} }
} }
template <class T> template <class T>
@ -473,21 +473,21 @@ template <class T>
void void
HbrHalfedge<T>::Clear() { HbrHalfedge<T>::Clear() {
if (opposite) { if (opposite) {
opposite->opposite = 0; opposite->opposite = 0;
if (vchild) { if (vchild) {
// Transfer ownership of the vchild to the opposite ptr // Transfer ownership of the vchild to the opposite ptr
opposite->vchild = vchild; opposite->vchild = vchild;
// Done this way just for assertion sanity // Done this way just for assertion sanity
vchild->SetParent(static_cast<HbrHalfedge*>(0)); vchild->SetParent(static_cast<HbrHalfedge*>(0));
vchild->SetParent(opposite); vchild->SetParent(opposite);
vchild = 0; vchild = 0;
} }
opposite = 0; opposite = 0;
} }
// Orphan the child vertex // Orphan the child vertex
else if (vchild) { else if (vchild) {
vchild->SetParent(static_cast<HbrHalfedge*>(0)); vchild->SetParent(static_cast<HbrHalfedge*>(0));
vchild = 0; vchild = 0;
} }
} }
@ -528,14 +528,14 @@ HbrHalfedge<T>::GetFVarInfiniteSharp(int datum) {
assert (bits != 2); assert (bits != 2);
return bits ? true : false; return bits ? true : false;
} }
// If there is no face varying data it can't be infinitely sharp! // If there is no face varying data it can't be infinitely sharp!
const int fvarwidth = GetMesh()->GetTotalFVarWidth(); const int fvarwidth = GetMesh()->GetTotalFVarWidth();
if (!fvarwidth) { if (!fvarwidth) {
bits = ~(0x3 << shift); bits = ~(0x3 << shift);
fvarinfsharp[intindex] &= bits; fvarinfsharp[intindex] &= bits;
if (opposite) opposite->getFVarInfSharp()[intindex] &= bits; if (opposite) opposite->getFVarInfSharp()[intindex] &= bits;
return false; return false;
} }
// If either incident face is missing, it's a geometric boundary // If either incident face is missing, it's a geometric boundary
@ -543,9 +543,9 @@ HbrHalfedge<T>::GetFVarInfiniteSharp(int datum) {
HbrFace<T>* left = GetLeftFace(), *right = GetRightFace(); HbrFace<T>* left = GetLeftFace(), *right = GetRightFace();
if (!left || !right) { if (!left || !right) {
bits = ~(0x2 << shift); bits = ~(0x2 << shift);
fvarinfsharp[intindex] &= bits; fvarinfsharp[intindex] &= bits;
if (opposite) opposite->getFVarInfSharp()[intindex] &= bits; if (opposite) opposite->getFVarInfSharp()[intindex] &= bits;
return true; return true;
} }
// Look for the indices on each face which correspond to the // Look for the indices on each face which correspond to the
@ -555,17 +555,17 @@ HbrHalfedge<T>::GetFVarInfiniteSharp(int datum) {
e = left->GetFirstEdge(); e = left->GetFirstEdge();
nv = left->GetNumVertices(); nv = left->GetNumVertices();
for (i = 0; i < nv; ++i) { for (i = 0; i < nv; ++i) {
if (e->GetOrgVertex() == GetOrgVertex()) lorg = i; if (e->GetOrgVertex() == GetOrgVertex()) lorg = i;
if (e->GetOrgVertex() == GetDestVertex()) ldst = i; if (e->GetOrgVertex() == GetDestVertex()) ldst = i;
e = e->GetNext(); e = e->GetNext();
} }
e = right->GetFirstEdge(); e = right->GetFirstEdge();
nv = right->GetNumVertices(); nv = right->GetNumVertices();
for (i = 0; i < nv; ++i) { for (i = 0; i < nv; ++i) {
if (e->GetOrgVertex() == GetOrgVertex()) rorg = i; if (e->GetOrgVertex() == GetOrgVertex()) rorg = i;
if (e->GetOrgVertex() == GetDestVertex()) rdst = i; if (e->GetOrgVertex() == GetDestVertex()) rdst = i;
e = e->GetNext(); e = e->GetNext();
} }
assert(lorg >= 0 && ldst >= 0 && rorg >= 0 && rdst >= 0); assert(lorg >= 0 && ldst >= 0 && rorg >= 0 && rdst >= 0);
// Compare the facevarying data to some tolerance // Compare the facevarying data to some tolerance
const int startindex = GetMesh()->GetFVarIndices()[datum]; const int startindex = GetMesh()->GetFVarIndices()[datum];
@ -573,8 +573,8 @@ HbrHalfedge<T>::GetFVarInfiniteSharp(int datum) {
if (!right->GetFVarData(rorg).Compare(left->GetFVarData(lorg), startindex, width, 0.001f) || if (!right->GetFVarData(rorg).Compare(left->GetFVarData(lorg), startindex, width, 0.001f) ||
!right->GetFVarData(rdst).Compare(left->GetFVarData(ldst), startindex, width, 0.001f)) { !right->GetFVarData(rdst).Compare(left->GetFVarData(ldst), startindex, width, 0.001f)) {
bits = ~(0x2 << shift); bits = ~(0x2 << shift);
fvarinfsharp[intindex] &= bits; fvarinfsharp[intindex] &= bits;
if (opposite) opposite->getFVarInfSharp()[intindex] &= bits; if (opposite) opposite->getFVarInfSharp()[intindex] &= bits;
return true; return true;
} }
@ -602,15 +602,15 @@ HbrHalfedge<T>::GetFVarSharpness(int datum, bool ignoreGeometry) {
if (infsharp) return k_InfinitelySharp; if (infsharp) return k_InfinitelySharp;
if (!ignoreGeometry) { if (!ignoreGeometry) {
// If it's a geometrically sharp edge it's going to be a // If it's a geometrically sharp edge it's going to be a
// facevarying sharp edge too // facevarying sharp edge too
if (sharpness > k_Smooth) { if (sharpness > k_Smooth) {
return k_InfinitelySharp; return k_InfinitelySharp;
} }
} }
return k_Smooth; return k_Smooth;
} }
template <class T> template <class T>
std::ostream& std::ostream&
@ -618,14 +618,14 @@ operator<<(std::ostream& out, const HbrHalfedge<T>& edge) {
if (edge.IsBoundary()) out << "boundary "; if (edge.IsBoundary()) out << "boundary ";
out << "edge connecting "; out << "edge connecting ";
if (edge.GetOrgVertex()) if (edge.GetOrgVertex())
out << *edge.GetOrgVertex(); out << *edge.GetOrgVertex();
else else
out << "(none)"; out << "(none)";
out << " to "; out << " to ";
if (edge.GetDestVertex()) { if (edge.GetDestVertex()) {
out << *edge.GetDestVertex(); out << *edge.GetDestVertex();
} else { } else {
out << "(none)"; out << "(none)";
} }
return out; return out;
} }
@ -636,7 +636,7 @@ template <class T>
class HbrHalfedgeCompare { class HbrHalfedgeCompare {
public: public:
bool operator() (const HbrHalfedge<T>* a, HbrHalfedge<T>* b) const { bool operator() (const HbrHalfedge<T>* a, HbrHalfedge<T>* b) const {
return (a->GetFace()->GetPath() < b->GetFace()->GetPath()); return (a->GetFace()->GetPath() < b->GetFace()->GetPath());
} }
}; };

View File

@ -71,44 +71,44 @@ class HbrHierarchicalEdit {
public: public:
typedef enum Operation { typedef enum Operation {
Set, Set,
Add, Add,
Subtract Subtract
} Operation; } Operation;
protected: protected:
HbrHierarchicalEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces) HbrHierarchicalEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces)
: faceid(_faceid), nsubfaces(_nsubfaces) { : faceid(_faceid), nsubfaces(_nsubfaces) {
subfaces = new unsigned char[_nsubfaces]; subfaces = new unsigned char[_nsubfaces];
for (int i = 0; i < nsubfaces; ++i) { for (int i = 0; i < nsubfaces; ++i) {
subfaces[i] = _subfaces[i]; subfaces[i] = _subfaces[i];
} }
} }
HbrHierarchicalEdit(int _faceid, int _nsubfaces, int *_subfaces) HbrHierarchicalEdit(int _faceid, int _nsubfaces, int *_subfaces)
: faceid(_faceid), nsubfaces(_nsubfaces) { : faceid(_faceid), nsubfaces(_nsubfaces) {
subfaces = new unsigned char[_nsubfaces]; subfaces = new unsigned char[_nsubfaces];
for (int i = 0; i < nsubfaces; ++i) { for (int i = 0; i < nsubfaces; ++i) {
subfaces[i] = static_cast<unsigned char>(_subfaces[i]); subfaces[i] = static_cast<unsigned char>(_subfaces[i]);
} }
} }
public: public:
virtual ~HbrHierarchicalEdit() { virtual ~HbrHierarchicalEdit() {
delete[] subfaces; delete[] subfaces;
} }
bool operator<(const HbrHierarchicalEdit& p) const { bool operator<(const HbrHierarchicalEdit& p) const {
if (faceid < p.faceid) return true; if (faceid < p.faceid) return true;
if (faceid > p.faceid) return false; if (faceid > p.faceid) return false;
int minlength = nsubfaces; int minlength = nsubfaces;
if (minlength > p.nsubfaces) minlength = p.nsubfaces; if (minlength > p.nsubfaces) minlength = p.nsubfaces;
for (int i = 0; i < minlength; ++i) { for (int i = 0; i < minlength; ++i) {
if (subfaces[i] < p.subfaces[i]) return true; if (subfaces[i] < p.subfaces[i]) return true;
if (subfaces[i] > p.subfaces[i]) return false; if (subfaces[i] > p.subfaces[i]) return false;
} }
return (nsubfaces < p.nsubfaces); return (nsubfaces < p.nsubfaces);
} }
// Return the face id (the first element in the path) // Return the face id (the first element in the path)
@ -119,7 +119,7 @@ public:
// Return a subface element in the path // Return a subface element in the path
unsigned char GetSubface(int index) const { return subfaces[index]; } unsigned char GetSubface(int index) const { return subfaces[index]; }
// Determines whether this hierarchical edit is relevant to the // Determines whether this hierarchical edit is relevant to the
// face in question // face in question
bool IsRelevantToFace(HbrFace<T>* face) const; bool IsRelevantToFace(HbrFace<T>* face) const;
@ -128,12 +128,12 @@ public:
virtual void ApplyEditToFace(HbrFace<T>* /* face */) {} virtual void ApplyEditToFace(HbrFace<T>* /* face */) {}
// Applys edit to vertex. Subclasses may override this method. // Applys edit to vertex. Subclasses may override this method.
virtual void ApplyEditToVertex(HbrFace<T>* /* face */, HbrVertex<T>* /* vertex */) {} virtual void ApplyEditToVertex(HbrFace<T>* /* face */, HbrVertex<T>* /* vertex */) {}
#ifdef PRMAN #ifdef PRMAN
// Gets the effect of this hierarchical edit on the bounding box. // Gets the effect of this hierarchical edit on the bounding box.
// Subclasses may override this method // Subclasses may override this method
virtual void ApplyToBound(struct bbox& /* box */, RtMatrix * /* mx */) {} virtual void ApplyToBound(struct bbox& /* box */, RtMatrix * /* mx */) const {}
#endif #endif
protected: protected:
@ -150,7 +150,7 @@ protected:
template <class T> template <class T>
class HbrHierarchicalEditComparator { class HbrHierarchicalEditComparator {
public: public:
bool operator() (const HbrHierarchicalEdit<T>* path1, const HbrHierarchicalEdit<T>* path2) const { bool operator() (const HbrHierarchicalEdit<T>* path1, const HbrHierarchicalEdit<T>* path2) const {
return (*path1 < *path2); return (*path1 < *path2);
} }
}; };
@ -181,7 +181,7 @@ HbrHierarchicalEdit<T>::IsRelevantToFace(HbrFace<T>* face) const {
if (!p) return false; if (!p) return false;
if (this == p) return true; if (this == p) return true;
if (faceid != p->faceid) return false; if (faceid != p->faceid) return false;
// If our path length is less than the face depth, it should mean // If our path length is less than the face depth, it should mean
@ -190,7 +190,7 @@ HbrHierarchicalEdit<T>::IsRelevantToFace(HbrFace<T>* face) const {
if (nsubfaces < face->GetDepth()) return false; if (nsubfaces < face->GetDepth()) return false;
if (memcmp(subfaces, p->subfaces, face->GetDepth() * sizeof(unsigned char)) != 0) { if (memcmp(subfaces, p->subfaces, face->GetDepth() * sizeof(unsigned char)) != 0) {
return false; return false;
} }
return true; return true;
} }

View File

@ -68,7 +68,7 @@ template <class T>
std::ostream& operator<<(std::ostream& out, const HbrHoleEdit<T>& path) { std::ostream& operator<<(std::ostream& out, const HbrHoleEdit<T>& path) {
out << "edge path = (" << path.faceid << ' '; out << "edge path = (" << path.faceid << ' ';
for (int i = 0; i < path.nsubfaces; ++i) { for (int i = 0; i < path.nsubfaces; ++i) {
out << static_cast<int>(path.subfaces[i]) << ' '; out << static_cast<int>(path.subfaces[i]) << ' ';
} }
return out << ")"; return out << ")";
} }
@ -79,22 +79,22 @@ class HbrHoleEdit : public HbrHierarchicalEdit<T> {
public: public:
HbrHoleEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces) HbrHoleEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces) {
}
HbrHoleEdit(int _faceid, int _nsubfaces, int *_subfaces)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces) {
} }
HbrHoleEdit(int _faceid, int _nsubfaces, int *_subfaces)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces) {
}
virtual ~HbrHoleEdit() {} virtual ~HbrHoleEdit() {}
friend std::ostream& operator<< <T> (std::ostream& out, const HbrHoleEdit<T>& path); friend std::ostream& operator<< <T> (std::ostream& out, const HbrHoleEdit<T>& path);
virtual void ApplyEditToFace(HbrFace<T>* face) { virtual void ApplyEditToFace(HbrFace<T>* face) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) { if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
face->SetHole(); face->SetHole();
} }
} }
}; };

View File

@ -74,29 +74,30 @@ template <class T>
class HbrLoopSubdivision : public HbrSubdivision<T>{ class HbrLoopSubdivision : public HbrSubdivision<T>{
public: public:
HbrLoopSubdivision<T>() HbrLoopSubdivision<T>()
: HbrSubdivision<T>() {} : HbrSubdivision<T>() {}
virtual HbrSubdivision<T>* Clone() const { virtual HbrSubdivision<T>* Clone() const {
return new HbrLoopSubdivision<T>(); return new HbrLoopSubdivision<T>();
} }
virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face); virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face);
virtual HbrFace<T>* RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex); virtual HbrFace<T>* RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex);
virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge); virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
virtual void GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex); virtual void GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
virtual bool HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face); virtual bool HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face);
virtual bool HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge); virtual bool HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
virtual bool HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex); virtual bool HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face); virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face);
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge); virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex); virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
virtual bool VertexIsExtraordinary(HbrMesh<T>* mesh, HbrVertex<T>* vertex) { return vertex->GetValence() != 6; } virtual bool VertexIsExtraordinary(HbrMesh<T>* mesh, HbrVertex<T>* vertex) { return vertex->GetValence() != 6; }
virtual bool FaceIsExtraordinary(HbrMesh<T>* /* mesh */, HbrFace<T>* face) { return face->GetNumVertices() != 3; }
virtual int GetFaceChildrenCount(int nvertices) const { return 4; } virtual int GetFaceChildrenCount(int nvertices) const { return 4; }
private: private:
// Transfers facevarying data from a parent face to a child face // Transfers facevarying data from a parent face to a child face
@ -121,7 +122,7 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
// we need to do three edge subdivision rules // we need to do three edge subdivision rules
if (index == 3) { if (index == 3) {
const int fvarcount = mesh->GetFVarCount(); const int fvarcount = mesh->GetFVarCount();
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
HbrHalfedge<T> *edge = face->GetEdge(i); HbrHalfedge<T> *edge = face->GetEdge(i);
GuaranteeNeighbor(mesh, edge); GuaranteeNeighbor(mesh, edge);
childVertex = child->GetVertex((i + 2) % 3); childVertex = child->GetVertex((i + 2) % 3);
@ -129,11 +130,11 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
if (!fvIsSmooth) { if (!fvIsSmooth) {
childVertex->NewFVarData(child); childVertex->NewFVarData(child);
} }
HbrFVarData<T>& fv = childVertex->GetFVarData(child); HbrFVarData<T>& fv = childVertex->GetFVarData(child);
int fvarindex = 0; int fvarindex = 0;
for (int fvaritem = 0; fvaritem < fvarcount; ++fvaritem) { for (int fvaritem = 0; fvaritem < fvarcount; ++fvaritem) {
const int fvarwidth = mesh->GetFVarWidths()[fvaritem]; const int fvarwidth = mesh->GetFVarWidths()[fvaritem];
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone || if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
face->GetEdge(i)->GetFVarSharpness(fvaritem) || face->GetEdge(i)->IsBoundary()) { face->GetEdge(i)->GetFVarSharpness(fvaritem) || face->GetEdge(i)->IsBoundary()) {
@ -157,13 +158,13 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
fvarindex += fvarwidth; fvarindex += fvarwidth;
} }
fv.SetInitialized(); fv.SetInitialized();
} }
return; return;
} }
HbrHalfedge<T>* edge; HbrHalfedge<T>* edge;
HbrVertex<T>* v = face->GetVertex(index); HbrVertex<T>* v = face->GetVertex(index);
// Otherwise we proceed with one vertex and two edge subdivision // Otherwise we proceed with one vertex and two edge subdivision
// applications. First the vertex subdivision rule. Analyze // applications. First the vertex subdivision rule. Analyze
// whether the vertex is on the boundary and whether it's an // whether the vertex is on the boundary and whether it's an
@ -189,14 +190,14 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
bool fv0IsSmooth, fv1IsSmooth, fv2IsSmooth; bool fv0IsSmooth, fv1IsSmooth, fv2IsSmooth;
childVertex = child->GetVertex(index); childVertex = child->GetVertex(index);
fv0IsSmooth = v->IsFVarAllSmooth(); fv0IsSmooth = v->IsFVarAllSmooth();
if (!fv0IsSmooth) { if (!fv0IsSmooth) {
childVertex->NewFVarData(child); childVertex->NewFVarData(child);
} }
HbrFVarData<T>& fv0 = childVertex->GetFVarData(child); HbrFVarData<T>& fv0 = childVertex->GetFVarData(child);
edge = face->GetEdge(index); edge = face->GetEdge(index);
GuaranteeNeighbor(mesh, edge); GuaranteeNeighbor(mesh, edge);
assert(edge->GetOrgVertex() == v); assert(edge->GetOrgVertex() == v);
@ -208,7 +209,7 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
HbrFVarData<T>& fv1 = childVertex->GetFVarData(child); HbrFVarData<T>& fv1 = childVertex->GetFVarData(child);
edge = edge->GetPrev(); edge = edge->GetPrev();
GuaranteeNeighbor(mesh, edge); GuaranteeNeighbor(mesh, edge);
assert(edge == face->GetEdge((index + 2) % 3)); assert(edge == face->GetEdge((index + 2) % 3));
assert(edge->GetDestVertex() == v); assert(edge->GetDestVertex() == v);
childVertex = child->GetVertex((index + 2) % 3); childVertex = child->GetVertex((index + 2) % 3);
@ -217,13 +218,13 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
childVertex->NewFVarData(child); childVertex->NewFVarData(child);
} }
HbrFVarData<T>& fv2 = childVertex->GetFVarData(child); HbrFVarData<T>& fv2 = childVertex->GetFVarData(child);
const int fvarcount = mesh->GetFVarCount(); const int fvarcount = mesh->GetFVarCount();
int fvarindex = 0; int fvarindex = 0;
for (int fvaritem = 0; fvaritem < fvarcount; ++fvaritem) { for (int fvaritem = 0; fvaritem < fvarcount; ++fvaritem) {
bool infcorner = false; bool infcorner = false;
const int fvarwidth = mesh->GetFVarWidths()[fvaritem]; const int fvarwidth = mesh->GetFVarWidths()[fvaritem];
const char fvarmask = v->GetFVarMask(fvaritem); const char fvarmask = v->GetFVarMask(fvaritem);
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryEdgeAndCorner) { if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryEdgeAndCorner) {
if (fvarmask >= HbrVertex<T>::k_Corner) { if (fvarmask >= HbrVertex<T>::k_Corner) {
infcorner = true; infcorner = true;
@ -295,11 +296,11 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
if (bestface->GetVertex(j) == w) break; if (bestface->GetVertex(j) == w) break;
} }
assert(j != bestface->GetNumVertices()); assert(j != bestface->GetNumVertices());
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f); fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
} }
// Boundary vertex rule (can use FVarSmooth, which is equivalent // Boundary vertex rule (can use FVarSmooth, which is equivalent
// to checking that it's sharper than a dart) // to checking that it's sharper than a dart)
else if (fvarmask != 0) { else if (fvarmask != 0) {
// Use 0.75 of the current vert // Use 0.75 of the current vert
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.75f); fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.75f);
@ -348,7 +349,7 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
starte = bestedge; starte = bestedge;
w = 0; w = 0;
if (HbrHalfedge<T>* e = starte) { if (HbrHalfedge<T>* e = starte) {
assert(starte->GetOrgVertex() == v); assert(starte->GetOrgVertex() == v);
do { do {
if (e->GetFVarSharpness(fvaritem) || !e->GetRightFace()) { if (e->GetFVarSharpness(fvaritem) || !e->GetRightFace()) {
bestface = e->GetLeftFace(); bestface = e->GetLeftFace();
@ -365,10 +366,10 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
} }
assert(j != bestface->GetNumVertices()); assert(j != bestface->GetNumVertices());
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f); fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
} }
// Smooth rule // Smooth rule
else if (!fv0IsSmooth || !fv0.IsInitialized()) { else if (!fv0IsSmooth || !fv0.IsInitialized()) {
int valence = v->GetValence(); int valence = v->GetValence();
float invvalence = 1.0f / valence; float invvalence = 1.0f / valence;
float beta = 0.25f * cosf((float)M_PI * 2.0f * invvalence) + 0.375f; float beta = 0.25f * cosf((float)M_PI * 2.0f * invvalence) + 0.375f;
@ -383,7 +384,7 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge; HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge;
edge = start; edge = start;
while (edge) { while (edge) {
HbrFace<T>* g = edge->GetLeftFace(); HbrFace<T>* g = edge->GetLeftFace();
// .. and look for the edge on that face whose origin is // .. and look for the edge on that face whose origin is
// the same as v, and add a contribution from its // the same as v, and add a contribution from its
@ -423,23 +424,23 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
} }
} }
} }
// Edge subdivision rule // Edge subdivision rule
edge = edge->GetPrev(); edge = edge->GetPrev();
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone || if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) { edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) {
// Sharp edge rule // Sharp edge rule
fv2.SetWithWeight(face->GetFVarData((index + 2) % 3), fvarindex, fvarwidth, 0.5f); fv2.SetWithWeight(face->GetFVarData((index + 2) % 3), fvarindex, fvarwidth, 0.5f);
fv2.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f); fv2.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f);
} else if (!fv2IsSmooth || !fv2.IsInitialized()) { } else if (!fv2IsSmooth || !fv2.IsInitialized()) {
// Smooth edge subdivision. Add 0.375 of adjacent vertices // Smooth edge subdivision. Add 0.375 of adjacent vertices
fv2.SetWithWeight(face->GetFVarData((index + 2) % 3), fvarindex, fvarwidth, 0.375f); fv2.SetWithWeight(face->GetFVarData((index + 2) % 3), fvarindex, fvarwidth, 0.375f);
fv2.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.375f); fv2.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.375f);
// Add 0.125 of opposite vertices // Add 0.125 of opposite vertices
fv2.AddWithWeight(face->GetFVarData((index + 1) % 3), fvarindex, fvarwidth, 0.125f); fv2.AddWithWeight(face->GetFVarData((index + 1) % 3), fvarindex, fvarwidth, 0.125f);
HbrFace<T>* oppFace = edge->GetRightFace(); HbrFace<T>* oppFace = edge->GetRightFace();
for (int j = 0; j < oppFace->GetNumVertices(); ++j) { for (int j = 0; j < oppFace->GetNumVertices(); ++j) {
@ -447,7 +448,7 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
fv2.AddWithWeight(oppFace->GetFVarData((j+2)%oppFace->GetNumVertices()), fvarindex, fvarwidth, 0.125f); fv2.AddWithWeight(oppFace->GetFVarData((j+2)%oppFace->GetNumVertices()), fvarindex, fvarwidth, 0.125f);
break; break;
} }
} }
} }
fvarindex += fvarwidth; fvarindex += fvarwidth;
@ -463,15 +464,15 @@ HbrLoopSubdivision<T>::transferEditsToChild(HbrFace<T>* face, HbrFace<T>* child,
// Hand down pointers to hierarchical edits // Hand down pointers to hierarchical edits
if (HbrHierarchicalEdit<T>** edits = face->GetHierarchicalEdits()) { if (HbrHierarchicalEdit<T>** edits = face->GetHierarchicalEdits()) {
while (HbrHierarchicalEdit<T>* edit = *edits) { while (HbrHierarchicalEdit<T>* edit = *edits) {
if (!edit->IsRelevantToFace(face)) break; if (!edit->IsRelevantToFace(face)) break;
if (edit->GetNSubfaces() > face->GetDepth() && if (edit->GetNSubfaces() > face->GetDepth() &&
(edit->GetSubface(face->GetDepth()) == index)) { (edit->GetSubface(face->GetDepth()) == index)) {
child->SetHierarchicalEdits(edits); child->SetHierarchicalEdits(edits);
break; break;
} }
edits++; edits++;
} }
} }
} }
@ -481,56 +482,56 @@ HbrLoopSubdivision<T>::Refine(HbrMesh<T>* mesh, HbrFace<T>* face) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "\n\nRefining face " << *face << "\n"; std::cerr << "\n\nRefining face " << *face << "\n";
#endif #endif
assert(face->GetNumVertices() == 3); // or triangulate it? assert(face->GetNumVertices() == 3); // or triangulate it?
HbrHalfedge<T>* edge = face->GetFirstEdge(); HbrHalfedge<T>* edge = face->GetFirstEdge();
HbrHalfedge<T>* prevedge = edge->GetPrev(); HbrHalfedge<T>* prevedge = edge->GetPrev();
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
HbrVertex<T>* vertex = edge->GetOrgVertex(); HbrVertex<T>* vertex = edge->GetOrgVertex();
if (!face->GetChild(i)) { if (!face->GetChild(i)) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Kid " << i << "\n"; std::cerr << "Kid " << i << "\n";
#endif #endif
HbrFace<T>* child; HbrFace<T>* child;
HbrVertex<T>* vertices[3]; HbrVertex<T>* vertices[3];
vertices[i] = vertex->Subdivide(); vertices[i] = vertex->Subdivide();
vertices[(i + 1) % 3] = edge->Subdivide(); vertices[(i + 1) % 3] = edge->Subdivide();
vertices[(i + 2) % 3] = prevedge->Subdivide(); vertices[(i + 2) % 3] = prevedge->Subdivide();
child = mesh->NewFace(3, vertices, face, i); child = mesh->NewFace(3, vertices, face, i);
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Creating face " << *child << " during refine\n"; std::cerr << "Creating face " << *child << " during refine\n";
#endif #endif
// Hand down edge sharpness // Hand down edge sharpness
float sharpness; float sharpness;
HbrHalfedge<T>* childedge; HbrHalfedge<T>* childedge;
childedge = child->GetEdge(i); childedge = child->GetEdge(i);
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) { if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight( HbrSubdivision<T>::SubdivideCreaseWeight(
edge, edge->GetDestVertex(), childedge); edge, edge->GetDestVertex(), childedge);
} }
childedge->CopyFVarInfiniteSharpness(edge); childedge->CopyFVarInfiniteSharpness(edge);
childedge = child->GetEdge((i+2)%3); childedge = child->GetEdge((i+2)%3);
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) { if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight( HbrSubdivision<T>::SubdivideCreaseWeight(
prevedge, prevedge->GetOrgVertex(), childedge); prevedge, prevedge->GetOrgVertex(), childedge);
} }
childedge->CopyFVarInfiniteSharpness(prevedge); childedge->CopyFVarInfiniteSharpness(prevedge);
if (mesh->GetTotalFVarWidth()) { if (mesh->GetTotalFVarWidth()) {
transferFVarToChild(mesh, face, child, i); transferFVarToChild(mesh, face, child, i);
} }
transferEditsToChild(face, child, i); transferEditsToChild(face, child, i);
} }
prevedge = edge; prevedge = edge;
edge = edge->GetNext(); edge = edge->GetNext();
} }
refineFaceAtMiddle(mesh, face); refineFaceAtMiddle(mesh, face);
@ -545,55 +546,55 @@ HbrLoopSubdivision<T>::RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, Hb
#endif #endif
HbrHalfedge<T>* edge = face->GetFirstEdge(); HbrHalfedge<T>* edge = face->GetFirstEdge();
HbrHalfedge<T>* prevedge = edge->GetPrev(); HbrHalfedge<T>* prevedge = edge->GetPrev();
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
if (edge->GetOrgVertex() == vertex) { if (edge->GetOrgVertex() == vertex) {
if (!face->GetChild(i)) { if (!face->GetChild(i)) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Kid " << i << "\n"; std::cerr << "Kid " << i << "\n";
#endif #endif
HbrFace<T>* child; HbrFace<T>* child;
HbrVertex<T>* vertices[3]; HbrVertex<T>* vertices[3];
vertices[i] = vertex->Subdivide(); vertices[i] = vertex->Subdivide();
vertices[(i + 1) % 3] = edge->Subdivide(); vertices[(i + 1) % 3] = edge->Subdivide();
vertices[(i + 2) % 3] = prevedge->Subdivide(); vertices[(i + 2) % 3] = prevedge->Subdivide();
child = mesh->NewFace(3, vertices, face, i); child = mesh->NewFace(3, vertices, face, i);
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Creating face " << *child << " during refine\n"; std::cerr << "Creating face " << *child << " during refine\n";
#endif #endif
// Hand down edge sharpness // Hand down edge sharpness
float sharpness; float sharpness;
HbrHalfedge<T>* childedge; HbrHalfedge<T>* childedge;
childedge = child->GetEdge(i); childedge = child->GetEdge(i);
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) { if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight( HbrSubdivision<T>::SubdivideCreaseWeight(
edge, edge->GetDestVertex(), childedge); edge, edge->GetDestVertex(), childedge);
} }
childedge->CopyFVarInfiniteSharpness(edge); childedge->CopyFVarInfiniteSharpness(edge);
childedge = child->GetEdge((i+2)%3); childedge = child->GetEdge((i+2)%3);
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) { if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight( HbrSubdivision<T>::SubdivideCreaseWeight(
prevedge, prevedge->GetOrgVertex(), childedge); prevedge, prevedge->GetOrgVertex(), childedge);
} }
childedge->CopyFVarInfiniteSharpness(prevedge); childedge->CopyFVarInfiniteSharpness(prevedge);
if (mesh->GetTotalFVarWidth()) { if (mesh->GetTotalFVarWidth()) {
transferFVarToChild(mesh, face, child, i); transferFVarToChild(mesh, face, child, i);
} }
transferEditsToChild(face, child, i); transferEditsToChild(face, child, i);
return child; return child;
} else { } else {
return face->GetChild(i); return face->GetChild(i);
} }
} }
prevedge = edge; prevedge = edge;
edge = edge->GetNext(); edge = edge->GetNext();
} }
return 0; return 0;
} }
@ -602,7 +603,7 @@ template <class T>
void void
HbrLoopSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) { HbrLoopSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
if (edge->GetOpposite()) { if (edge->GetOpposite()) {
return; return;
} }
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
@ -611,7 +612,7 @@ HbrLoopSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge)
/* /*
Imagine the following: Imagine the following:
X X
/ \ / \
/ \ / \
@ -622,7 +623,7 @@ HbrLoopSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge)
/ \ \ / \ \
X------X--------X X------X--------X
1 1
If the parent of _both_ incident vertices are themselves edges, If the parent of _both_ incident vertices are themselves edges,
(like the edge marked 3 above), then this edge is in the center (like the edge marked 3 above), then this edge is in the center
of the parent face. Refining the parent face in the middle or of the parent face. Refining the parent face in the middle or
@ -633,41 +634,41 @@ HbrLoopSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge)
HbrHalfedge<T>* parentEdge2 = edge->GetDestVertex()->GetParentEdge(); HbrHalfedge<T>* parentEdge2 = edge->GetDestVertex()->GetParentEdge();
if (parentEdge1 && parentEdge2) { if (parentEdge1 && parentEdge2) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "two parent edge situation\n"; std::cerr << "two parent edge situation\n";
#endif #endif
HbrFace<T>* parentFace = parentEdge1->GetFace(); HbrFace<T>* parentFace = parentEdge1->GetFace();
assert(parentFace == parentEdge2->GetFace()); assert(parentFace == parentEdge2->GetFace());
if(parentEdge1->GetOrgVertex() == parentEdge2->GetDestVertex()) { if(parentEdge1->GetOrgVertex() == parentEdge2->GetDestVertex()) {
refineFaceAtMiddle(mesh, parentFace); refineFaceAtMiddle(mesh, parentFace);
} else { } else {
RefineFaceAtVertex(mesh, parentFace, parentEdge1->GetOrgVertex()); RefineFaceAtVertex(mesh, parentFace, parentEdge1->GetOrgVertex());
} }
assert(edge->GetOpposite()); assert(edge->GetOpposite());
return; return;
} }
// Otherwise we're in the situation of edge 1 or edge 2 in the // Otherwise we're in the situation of edge 1 or edge 2 in the
// diagram above. // diagram above.
if (parentEdge1) { if (parentEdge1) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "parent edge 1 " << *parentEdge1 << "\n"; std::cerr << "parent edge 1 " << *parentEdge1 << "\n";
#endif #endif
HbrVertex<T>* parentVertex2 = edge->GetDestVertex()->GetParentVertex(); HbrVertex<T>* parentVertex2 = edge->GetDestVertex()->GetParentVertex();
assert(parentVertex2); assert(parentVertex2);
RefineFaceAtVertex(mesh, parentEdge1->GetLeftFace(), parentVertex2); RefineFaceAtVertex(mesh, parentEdge1->GetLeftFace(), parentVertex2);
if (parentEdge1->GetRightFace()) { if (parentEdge1->GetRightFace()) {
RefineFaceAtVertex(mesh, parentEdge1->GetRightFace(), parentVertex2); RefineFaceAtVertex(mesh, parentEdge1->GetRightFace(), parentVertex2);
} }
} else if (parentEdge2) { } else if (parentEdge2) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "parent edge 2 " << *parentEdge2 << "\n"; std::cerr << "parent edge 2 " << *parentEdge2 << "\n";
#endif #endif
HbrVertex<T>* parentVertex1 = edge->GetOrgVertex()->GetParentVertex(); HbrVertex<T>* parentVertex1 = edge->GetOrgVertex()->GetParentVertex();
assert(parentVertex1); assert(parentVertex1);
RefineFaceAtVertex(mesh, parentEdge2->GetLeftFace(), parentVertex1); RefineFaceAtVertex(mesh, parentEdge2->GetLeftFace(), parentVertex1);
if (parentEdge2->GetRightFace()) { if (parentEdge2->GetRightFace()) {
RefineFaceAtVertex(mesh, parentEdge2->GetRightFace(), parentVertex1); RefineFaceAtVertex(mesh, parentEdge2->GetRightFace(), parentVertex1);
} }
} }
} }
@ -686,50 +687,50 @@ HbrLoopSubdivision<T>::GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex
// and have 1) refined at both vertices of the parent edge, and 2) // and have 1) refined at both vertices of the parent edge, and 2)
// have refined their "middle" face (which doesn't live at either // have refined their "middle" face (which doesn't live at either
// vertex). // vertex).
HbrHalfedge<T>* parentEdge = vertex->GetParentEdge(); HbrHalfedge<T>* parentEdge = vertex->GetParentEdge();
if (parentEdge) { if (parentEdge) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "parent edge situation " << *parentEdge << "\n"; std::cerr << "parent edge situation " << *parentEdge << "\n";
#endif #endif
HbrVertex<T>* dest = parentEdge->GetDestVertex(); HbrVertex<T>* dest = parentEdge->GetDestVertex();
HbrVertex<T>* org = parentEdge->GetOrgVertex(); HbrVertex<T>* org = parentEdge->GetOrgVertex();
GuaranteeNeighbor(mesh, parentEdge); GuaranteeNeighbor(mesh, parentEdge);
HbrFace<T>* parentFace = parentEdge->GetLeftFace(); HbrFace<T>* parentFace = parentEdge->GetLeftFace();
RefineFaceAtVertex(mesh, parentFace, dest); RefineFaceAtVertex(mesh, parentFace, dest);
RefineFaceAtVertex(mesh, parentFace, org); RefineFaceAtVertex(mesh, parentFace, org);
refineFaceAtMiddle(mesh, parentFace); refineFaceAtMiddle(mesh, parentFace);
parentFace = parentEdge->GetRightFace(); parentFace = parentEdge->GetRightFace();
// The right face may not necessarily exist even after // The right face may not necessarily exist even after
// GuaranteeNeighbor // GuaranteeNeighbor
if (parentFace) { if (parentFace) {
RefineFaceAtVertex(mesh, parentFace, dest); RefineFaceAtVertex(mesh, parentFace, dest);
RefineFaceAtVertex(mesh, parentFace, org); RefineFaceAtVertex(mesh, parentFace, org);
refineFaceAtMiddle(mesh, parentFace); refineFaceAtMiddle(mesh, parentFace);
} }
return; return;
} }
// The second case: the vertex is a child of a vertex. In this case // The second case: the vertex is a child of a vertex. In this case
// we have to recursively guarantee that the parent's adjacent // we have to recursively guarantee that the parent's adjacent
// faces also exist. // faces also exist.
HbrVertex<T>* parentVertex = vertex->GetParentVertex(); HbrVertex<T>* parentVertex = vertex->GetParentVertex();
if (parentVertex) { if (parentVertex) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "parent vertex situation " << *parentVertex << "\n"; std::cerr << "parent vertex situation " << *parentVertex << "\n";
#endif #endif
parentVertex->GuaranteeNeighbors(); parentVertex->GuaranteeNeighbors();
// And then we refine all the face neighbors of the parent // And then we refine all the face neighbors of the parent
// vertex // vertex
HbrHalfedge<T>* start = parentVertex->GetIncidentEdge(), *edge; HbrHalfedge<T>* start = parentVertex->GetIncidentEdge(), *edge;
edge = start; edge = start;
while (edge) { while (edge) {
HbrFace<T>* f = edge->GetLeftFace(); HbrFace<T>* f = edge->GetLeftFace();
RefineFaceAtVertex(mesh, f, parentVertex); RefineFaceAtVertex(mesh, f, parentVertex);
edge = parentVertex->GetNextEdge(edge); edge = parentVertex->GetNextEdge(edge);
if (edge == start) break; if (edge == start) break;
} }
} }
} }
@ -740,9 +741,9 @@ HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face) {
if (face->IsHole()) return false; if (face->IsHole()) return false;
// A limit face exists if all the bounding edges have limit curves // A limit face exists if all the bounding edges have limit curves
for (int i = 0; i < face->GetNumVertices(); ++i) { for (int i = 0; i < face->GetNumVertices(); ++i) {
if (!HasLimit(mesh, face->GetEdge(i))) { if (!HasLimit(mesh, face->GetEdge(i))) {
return false; return false;
} }
} }
return true; return true;
} }
@ -750,14 +751,14 @@ HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face) {
template <class T> template <class T>
bool bool
HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) { HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
// A sharp edge has a limit curve if both endpoints have limits. // A sharp edge has a limit curve if both endpoints have limits.
// A smooth edge has a limit if both endpoints have limits and // A smooth edge has a limit if both endpoints have limits and
// the edge isn't on the boundary. // the edge isn't on the boundary.
if (edge->GetSharpness() >= HbrHalfedge<T>::k_InfinitelySharp) return true; if (edge->GetSharpness() >= HbrHalfedge<T>::k_InfinitelySharp) return true;
if (!HasLimit(mesh, edge->GetOrgVertex()) || !HasLimit(mesh, edge->GetDestVertex())) return false; if (!HasLimit(mesh, edge->GetOrgVertex()) || !HasLimit(mesh, edge->GetDestVertex())) return false;
return !edge->IsBoundary(); return !edge->IsBoundary();
} }
@ -766,21 +767,21 @@ bool
HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex) { HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
vertex->GuaranteeNeighbors(); vertex->GuaranteeNeighbors();
switch (vertex->GetMask(false)) { switch (vertex->GetMask(false)) {
case HbrVertex<T>::k_Smooth: case HbrVertex<T>::k_Smooth:
case HbrVertex<T>::k_Dart: case HbrVertex<T>::k_Dart:
return !vertex->OnBoundary(); return !vertex->OnBoundary();
break; break;
case HbrVertex<T>::k_Crease: case HbrVertex<T>::k_Crease:
case HbrVertex<T>::k_Corner: case HbrVertex<T>::k_Corner:
default: default:
if (vertex->IsVolatile()) { if (vertex->IsVolatile()) {
// Search for any incident semisharp boundary edge // Search for any incident semisharp boundary edge
HbrHalfedge<T>* start = vertex->GetIncidentEdge(), *edge, *next; HbrHalfedge<T>* start = vertex->GetIncidentEdge(), *edge, *next;
edge = start; edge = start;
while (edge) { while (edge) {
if (edge->IsBoundary() && edge->GetSharpness() < HbrHalfedge<T>::k_InfinitelySharp) { if (edge->IsBoundary() && edge->GetSharpness() < HbrHalfedge<T>::k_InfinitelySharp) {
return false; return false;
} }
next = vertex->GetNextEdge(edge); next = vertex->GetNextEdge(edge);
if (next == start) { if (next == start) {
break; break;
@ -793,9 +794,9 @@ HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
} else { } else {
edge = next; edge = next;
} }
} }
} }
return true; return true;
} }
} }
@ -824,46 +825,46 @@ HbrLoopSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
// If there's the possibility of vertex edits on either vertex, we // If there's the possibility of vertex edits on either vertex, we
// have to make sure the edit has been applied // have to make sure the edit has been applied
if (mesh->HasVertexEdits()) { if (mesh->HasVertexEdits()) {
edge->GetOrgVertex()->GuaranteeNeighbors(); edge->GetOrgVertex()->GuaranteeNeighbors();
edge->GetDestVertex()->GuaranteeNeighbors(); edge->GetDestVertex()->GuaranteeNeighbors();
} }
if (!edge->IsBoundary() && esharp <= 1.0f) { if (!edge->IsBoundary() && esharp <= 1.0f) {
// Of the two half-edges, pick one of them consistently such // Of the two half-edges, pick one of them consistently such
// that the org and dest vertices are also consistent through // that the org and dest vertices are also consistent through
// multi-threading. It doesn't matter as far as the // multi-threading. It doesn't matter as far as the
// theoretical calculation is concerned, but it is desirable // theoretical calculation is concerned, but it is desirable
// to be consistent about it in the face of the limitations of // to be consistent about it in the face of the limitations of
// floating point commutativity. So we always pick the // floating point commutativity. So we always pick the
// half-edge such that its incident face is the smallest of // half-edge such that its incident face is the smallest of
// the two faces, as far as the face paths are concerned. // the two faces, as far as the face paths are concerned.
if (edge->GetOpposite() && edge->GetOpposite()->GetFace()->GetPath() < edge->GetFace()->GetPath()) { if (edge->GetOpposite() && edge->GetOpposite()->GetFace()->GetPath() < edge->GetFace()->GetPath()) {
edge = edge->GetOpposite(); edge = edge->GetOpposite();
} }
// Handle both the smooth and fractional sharpness cases. We
// lerp between the sharp case (average of the two end points)
// and the unsharp case (3/8 of each of the two end points
// plus 1/8 of the two opposite face averages).
// Lerp end point weight between non sharp contribution of // Handle both the smooth and fractional sharpness cases. We
// 3/8 and the sharp contribution of 0.5. // lerp between the sharp case (average of the two end points)
float endPtWeight = 0.375f + esharp * (0.5f - 0.375f); // and the unsharp case (3/8 of each of the two end points
data.AddWithWeight(edge->GetOrgVertex()->GetData(), endPtWeight); // plus 1/8 of the two opposite face averages).
data.AddWithWeight(edge->GetDestVertex()->GetData(), endPtWeight);
// Lerp the opposite pt weights between non sharp contribution // Lerp end point weight between non sharp contribution of
// of 1/8 and the sharp contribution of 0. // 3/8 and the sharp contribution of 0.5.
float oppPtWeight = 0.125f * (1 - esharp); float endPtWeight = 0.375f + esharp * (0.5f - 0.375f);
HbrHalfedge<T>* ee = edge->GetNext(); data.AddWithWeight(edge->GetOrgVertex()->GetData(), endPtWeight);
data.AddWithWeight(ee->GetDestVertex()->GetData(), oppPtWeight); data.AddWithWeight(edge->GetDestVertex()->GetData(), endPtWeight);
ee = edge->GetOpposite()->GetNext();
data.AddWithWeight(ee->GetDestVertex()->GetData(), oppPtWeight); // Lerp the opposite pt weights between non sharp contribution
// of 1/8 and the sharp contribution of 0.
float oppPtWeight = 0.125f * (1 - esharp);
HbrHalfedge<T>* ee = edge->GetNext();
data.AddWithWeight(ee->GetDestVertex()->GetData(), oppPtWeight);
ee = edge->GetOpposite()->GetNext();
data.AddWithWeight(ee->GetDestVertex()->GetData(), oppPtWeight);
} else { } else {
// Fully sharp edge, just average the two end points // Fully sharp edge, just average the two end points
data.AddWithWeight(edge->GetOrgVertex()->GetData(), 0.5f); data.AddWithWeight(edge->GetOrgVertex()->GetData(), 0.5f);
data.AddWithWeight(edge->GetDestVertex()->GetData(), 0.5f); data.AddWithWeight(edge->GetDestVertex()->GetData(), 0.5f);
} }
// Varying data is always the average of two end points // Varying data is always the average of two end points
@ -876,7 +877,7 @@ HbrLoopSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
// Only boundary edges will create extraordinary vertices // Only boundary edges will create extraordinary vertices
if (edge->IsBoundary()) { if (edge->IsBoundary()) {
v->SetExtraordinary(); v->SetExtraordinary();
} }
return v; return v;
} }
@ -888,7 +889,7 @@ HbrLoopSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
// Ensure the ring of faces around this vertex exists before // Ensure the ring of faces around this vertex exists before
// we compute the valence // we compute the valence
vertex->GuaranteeNeighbors(); vertex->GuaranteeNeighbors();
float valence = static_cast<float>(vertex->GetValence()); float valence = static_cast<float>(vertex->GetValence());
float invvalence = 1.0f / valence; float invvalence = 1.0f / valence;
@ -907,63 +908,63 @@ HbrLoopSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
// subdivision, then use fractional mask weights to weigh // subdivision, then use fractional mask weights to weigh
// each weighing // each weighing
if (masks[0] != masks[1]) { if (masks[0] != masks[1]) {
weights[1] = vertex->GetFractionalMask(); weights[1] = vertex->GetFractionalMask();
weights[0] = 1.0f - weights[1]; weights[0] = 1.0f - weights[1];
passes = 2; passes = 2;
} else { } else {
weights[0] = 1.0f; weights[0] = 1.0f;
weights[1] = 0.0f; weights[1] = 0.0f;
passes = 1; passes = 1;
} }
for (int i = 0; i < passes; ++i) { for (int i = 0; i < passes; ++i) {
switch (masks[i]) { switch (masks[i]) {
case HbrVertex<T>::k_Smooth: case HbrVertex<T>::k_Smooth:
case HbrVertex<T>::k_Dart: { case HbrVertex<T>::k_Dart: {
float beta = 0.25f * cosf((float)M_PI * 2.0f * invvalence) + 0.375f; float beta = 0.25f * cosf((float)M_PI * 2.0f * invvalence) + 0.375f;
beta = beta * beta; beta = beta * beta;
beta = (0.625f - beta) * invvalence; beta = (0.625f - beta) * invvalence;
data.AddWithWeight(vertex->GetData(), weights[i] * (1 - (beta * valence))); data.AddWithWeight(vertex->GetData(), weights[i] * (1 - (beta * valence)));
HbrSubdivision<T>::AddSurroundingVerticesWithWeight( HbrSubdivision<T>::AddSurroundingVerticesWithWeight(
mesh, vertex, weights[i] * beta, &data); mesh, vertex, weights[i] * beta, &data);
break; break;
} }
case HbrVertex<T>::k_Crease: { case HbrVertex<T>::k_Crease: {
// Compute 3/4 of old vertex value // Compute 3/4 of old vertex value
data.AddWithWeight(vertex->GetData(), weights[i] * 0.75f); data.AddWithWeight(vertex->GetData(), weights[i] * 0.75f);
// Add 0.125f of the (hopefully only two!) neighbouring // Add 0.125f of the (hopefully only two!) neighbouring
// sharp edges // sharp edges
HbrSubdivision<T>::AddCreaseEdgesWithWeight( HbrSubdivision<T>::AddCreaseEdgesWithWeight(
mesh, vertex, i == 1, weights[i] * 0.125f, &data); mesh, vertex, i == 1, weights[i] * 0.125f, &data);
break; break;
} }
case HbrVertex<T>::k_Corner: case HbrVertex<T>::k_Corner:
default: { default: {
// Just copy the old value // Just copy the old value
data.AddWithWeight(vertex->GetData(), weights[i]); data.AddWithWeight(vertex->GetData(), weights[i]);
break; break;
} }
} }
} }
// Varying data is always just propogated down // Varying data is always just propagated down
data.AddVaryingWithWeight(vertex->GetData(), 1.0f); data.AddVaryingWithWeight(vertex->GetData(), 1.0f);
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Subdividing at " << *vertex << "\n"; std::cerr << "Subdividing at " << *vertex << "\n";
std::cerr << " created " << *v << "\n"; std::cerr << " created " << *v << "\n";
#endif #endif
// Inherit extraordinary flag and sharpness // Inherit extraordinary flag and sharpness
if (vertex->IsExtraordinary()) v->SetExtraordinary(); if (vertex->IsExtraordinary()) v->SetExtraordinary();
float sharp = vertex->GetSharpness(); float sharp = vertex->GetSharpness();
if (sharp >= HbrVertex<T>::k_InfinitelySharp) { if (sharp >= HbrVertex<T>::k_InfinitelySharp) {
v->SetSharpness(HbrVertex<T>::k_InfinitelySharp); v->SetSharpness(HbrVertex<T>::k_InfinitelySharp);
} else if (sharp > HbrVertex<T>::k_Smooth) { } else if (sharp > HbrVertex<T>::k_Smooth) {
v->SetSharpness(std::max((float) HbrVertex<T>::k_Smooth, sharp - 1.0f)); v->SetSharpness(std::max((float) HbrVertex<T>::k_Smooth, sharp - 1.0f));
} else { } else {
v->SetSharpness(HbrVertex<T>::k_Smooth); v->SetSharpness(HbrVertex<T>::k_Smooth);
} }
return v; return v;
} }
@ -974,28 +975,28 @@ HbrLoopSubdivision<T>::refineFaceAtMiddle(HbrMesh<T>* mesh, HbrFace<T>* face) {
#ifdef HBR_DEBUG #ifdef HBR_DEBUG
std::cerr << "Refining middle face of " << *face << "\n"; std::cerr << "Refining middle face of " << *face << "\n";
#endif
if (!face->GetChild(3)) {
HbrFace<T>* child;
HbrVertex<T>* vertices[3];
// The fourth face is not an obvious child of any vertex. We
// assign it index 3 despite there being no fourth vertex in
// the triangle. The ordering of vertices here is done to
// preserve parametric space as best we can
vertices[0] = face->GetEdge(1)->Subdivide();
vertices[1] = face->GetEdge(2)->Subdivide();
vertices[2] = face->GetEdge(0)->Subdivide();
child = mesh->NewFace(3, vertices, face, 3);
#ifdef HBR_DEBUG
std::cerr << "Creating face " << *child << "\n";
#endif #endif
if (mesh->GetTotalFVarWidth()) {
transferFVarToChild(mesh, face, child, 3);
}
transferEditsToChild(face, child, 3); if (!face->GetChild(3)) {
HbrFace<T>* child;
HbrVertex<T>* vertices[3];
// The fourth face is not an obvious child of any vertex. We
// assign it index 3 despite there being no fourth vertex in
// the triangle. The ordering of vertices here is done to
// preserve parametric space as best we can
vertices[0] = face->GetEdge(1)->Subdivide();
vertices[1] = face->GetEdge(2)->Subdivide();
vertices[2] = face->GetEdge(0)->Subdivide();
child = mesh->NewFace(3, vertices, face, 3);
#ifdef HBR_DEBUG
std::cerr << "Creating face " << *child << "\n";
#endif
if (mesh->GetTotalFVarWidth()) {
transferFVarToChild(mesh, face, child, 3);
}
transferEditsToChild(face, child, 3);
} }
} }

View File

@ -59,8 +59,7 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <deque> #include <vector>
#include <list>
#include <set> #include <set>
#include <iostream> #include <iostream>
@ -94,14 +93,14 @@ public:
#endif #endif
); );
~HbrMesh(); ~HbrMesh();
// Create vertex with the indicated ID and data // Create vertex with the indicated ID and data
HbrVertex<T>* NewVertex(int id, const T &data); HbrVertex<T>* NewVertex(int id, const T &data);
// Create vertex with the indicated data. The ID will be assigned // Create vertex with the indicated data. The ID will be assigned
// by the mesh. // by the mesh.
HbrVertex<T>* NewVertex(const T &data); HbrVertex<T>* NewVertex(const T &data);
// Create vertex without an ID - one will be assigned by the mesh, // Create vertex without an ID - one will be assigned by the mesh,
// and the data implicitly created will share the same id // and the data implicitly created will share the same id
HbrVertex<T>* NewVertex(); HbrVertex<T>* NewVertex();
@ -120,36 +119,36 @@ public:
// Finishes initialization of the mesh // Finishes initialization of the mesh
void Finish(); void Finish();
// Remove the indicated face from the mesh // Remove the indicated face from the mesh
void DeleteFace(HbrFace<T>* face); void DeleteFace(HbrFace<T>* face);
// Remove the indicated vertex from the mesh // Remove the indicated vertex from the mesh
void DeleteVertex(HbrVertex<T>* vertex); void DeleteVertex(HbrVertex<T>* vertex);
// Returns number of vertices in the mesh // Returns number of vertices in the mesh
int GetNumVertices() const; int GetNumVertices() const;
// Returns number of disconnected vertices in the mesh // Returns number of disconnected vertices in the mesh
int GetNumDisconnectedVertices() const; int GetNumDisconnectedVertices() const;
// Returns number of faces in the mesh // Returns number of faces in the mesh
int GetNumFaces() const; int GetNumFaces() const;
// Returns number of coarse faces in the mesh // Returns number of coarse faces in the mesh
int GetNumCoarseFaces() const; int GetNumCoarseFaces() const;
// Ask for face with the indicated ID // Ask for face with the indicated ID
HbrFace<T>* GetFace(int id) const; HbrFace<T>* GetFace(int id) const;
// Returns a collection of all vertices in the mesh // Returns a collection of all vertices in the mesh
void GetVertices(std::list<HbrVertex<T>*>& vertices) const; void GetVertices(std::vector<HbrVertex<T>*>& vertices) const;
// Applies operator to all vertices // Applies operator to all vertices
void ApplyOperatorAllVertices(HbrVertexOperator<T> &op) const; void ApplyOperatorAllVertices(HbrVertexOperator<T> &op) const;
// Returns a collection of all faces in the mesh // Returns a collection of all faces in the mesh
void GetFaces(std::list<HbrFace<T>*>& faces) const; void GetFaces(std::vector<HbrFace<T>*>& faces) const;
// Returns the subdivision method // Returns the subdivision method
HbrSubdivision<T>* GetSubdivision() const { return subdivision; } HbrSubdivision<T>* GetSubdivision() const { return subdivision; }
@ -159,7 +158,7 @@ public:
// Return a table of the start index of each facevarying variable // Return a table of the start index of each facevarying variable
const int *GetFVarIndices() const { return fvarindices; } const int *GetFVarIndices() const { return fvarindices; }
// Return a table of the size of each facevarying variable // Return a table of the size of each facevarying variable
const int *GetFVarWidths() const { return fvarwidths; } const int *GetFVarWidths() const { return fvarwidths; }
@ -177,9 +176,9 @@ public:
// Interpolate boundary management // Interpolate boundary management
enum InterpolateBoundaryMethod { enum InterpolateBoundaryMethod {
k_InterpolateBoundaryNone, k_InterpolateBoundaryNone,
k_InterpolateBoundaryEdgeOnly, k_InterpolateBoundaryEdgeOnly,
k_InterpolateBoundaryEdgeAndCorner, k_InterpolateBoundaryEdgeAndCorner,
k_InterpolateBoundaryAlwaysSharp k_InterpolateBoundaryAlwaysSharp
}; };
@ -190,15 +189,15 @@ public:
bool GetFVarPropagateCorners() const { return fvarpropagatecorners; } bool GetFVarPropagateCorners() const { return fvarpropagatecorners; }
void SetFVarPropagateCorners(bool p) { fvarpropagatecorners = p; } void SetFVarPropagateCorners(bool p) { fvarpropagatecorners = p; }
// Register routines for keeping track of memory usage // Register routines for keeping track of memory usage
void RegisterMemoryRoutines(void (*increment)(unsigned long bytes), void (*decrement)(unsigned long bytes)) { void RegisterMemoryRoutines(void (*increment)(unsigned long bytes), void (*decrement)(unsigned long bytes)) {
m_faceAllocator.SetMemStatsIncrement(increment); m_faceAllocator.SetMemStatsIncrement(increment);
m_faceAllocator.SetMemStatsDecrement(decrement); m_faceAllocator.SetMemStatsDecrement(decrement);
m_vertexAllocator.SetMemStatsIncrement(increment); m_vertexAllocator.SetMemStatsIncrement(increment);
m_vertexAllocator.SetMemStatsDecrement(decrement); m_vertexAllocator.SetMemStatsDecrement(decrement);
s_memStatsIncrement = increment; s_memStatsIncrement = increment;
s_memStatsDecrement = decrement; s_memStatsDecrement = decrement;
} }
// Add a vertex to consider for garbage collection. All // Add a vertex to consider for garbage collection. All
@ -219,37 +218,39 @@ public:
// Add a new hierarchical edit to the mesh // Add a new hierarchical edit to the mesh
void AddHierarchicalEdit(HbrHierarchicalEdit<T>* edit); void AddHierarchicalEdit(HbrHierarchicalEdit<T>* edit);
// Return a pointer to the beginning of the list of hierarchical edits // Return the hierarchical edits associated with the mesh
HbrHierarchicalEdit<T>** GetHierarchicalEdits() const { return hierarchicalEditArray; } const std::vector<HbrHierarchicalEdit<T>*> &GetHierarchicalEdits() const {
return hierarchicalEdits;
}
// Whether the mesh has certain types of edits // Whether the mesh has certain types of edits
bool HasVertexEdits() const { return hasVertexEdits; } bool HasVertexEdits() const { return hasVertexEdits; }
bool HasCreaseEdits() const { return hasCreaseEdits; } bool HasCreaseEdits() const { return hasCreaseEdits; }
void Unrefine(int numCoarseVerts, int numCoarseFaces) { void Unrefine(int numCoarseVerts, int numCoarseFaces) {
static int oldMaxFaceID = 0; static int oldMaxFaceID = 0;
if(oldMaxFaceID == 0) { if(oldMaxFaceID == 0) {
oldMaxFaceID = numCoarseFaces; oldMaxFaceID = numCoarseFaces;
} }
for (int i = numCoarseFaces; i < maxFaceID; ++i) { for (int i = numCoarseFaces; i < maxFaceID; ++i) {
if (faces[i]) { if (faces[i]) {
HbrFace<T>* f = faces[i]; HbrFace<T>* f = faces[i];
if(f && not f->IsCoarse()) if(f && not f->IsCoarse())
DeleteFace(f); DeleteFace(f);
} }
} }
//oldMaxFaceID = maxFaceID; //oldMaxFaceID = maxFaceID;
maxFaceID = numCoarseFaces; maxFaceID = numCoarseFaces;
int vert = numCoarseVerts % vsetsize; int vert = numCoarseVerts % vsetsize;
for( int set=(numCoarseVerts/vsetsize); set<nvsets; set++ ) { for( int set=(numCoarseVerts/vsetsize); set<nvsets; set++ ) {
for( ; vert<vsetsize; vert++ ) { for( ; vert<vsetsize; vert++ ) {
HbrVertex<T>* v = vertices[set][vert]; HbrVertex<T>* v = vertices[set][vert];
if(v && not v->IsReferenced()) if(v && not v->IsReferenced())
DeleteVertex(v); DeleteVertex(v);
} }
vert = 0; vert = 0;
} }
} }
// Whether the mesh is in "transient" mode, i.e. all // Whether the mesh is in "transient" mode, i.e. all
@ -257,9 +258,9 @@ public:
void SetTransientMode(bool mode) { void SetTransientMode(bool mode) {
m_transientMode = mode; m_transientMode = mode;
} }
void FreeTransientData(); void FreeTransientData();
private: private:
// The mutex type depends on where hbr is being used. // The mutex type depends on where hbr is being used.
#if PRMAN #if PRMAN
@ -277,8 +278,8 @@ private:
public: public:
ScopedLock(Mutex *mutex) : _mutex(mutex) { ScopedLock(Mutex *mutex) : _mutex(mutex) {
mutex->Lock(); mutex->Lock();
} }
~ScopedLock() { ~ScopedLock() {
Release(); Release();
} }
@ -292,12 +293,12 @@ private:
Mutex *_mutex; Mutex *_mutex;
}; };
#endif #endif
// Mutex used to lock access to the "vertices" data member. // Mutex used to lock access to the "vertices" data member.
mutable Mutex m_verticesMutex; mutable Mutex m_verticesMutex;
private: private:
// Subdivision method used in this mesh // Subdivision method used in this mesh
HbrSubdivision<T>* subdivision; HbrSubdivision<T>* subdivision;
@ -316,7 +317,7 @@ private:
#ifdef HBRSTITCH #ifdef HBRSTITCH
const int stitchCount; const int stitchCount;
#endif #endif
// Vertices which comprise this mesh // Vertices which comprise this mesh
HbrVertex<T>*** vertices; HbrVertex<T>*** vertices;
int nvsets; int nvsets;
@ -344,28 +345,22 @@ private:
// Whether facevarying corners propagate their sharpness // Whether facevarying corners propagate their sharpness
bool fvarpropagatecorners; bool fvarpropagatecorners;
// Memory statistics tracking routines // Memory statistics tracking routines
HbrMemStatFunction s_memStatsIncrement; HbrMemStatFunction s_memStatsIncrement;
HbrMemStatFunction s_memStatsDecrement; HbrMemStatFunction s_memStatsDecrement;
// Vertices which may be garbage collected // Vertices which may be garbage collected
std::deque<HbrVertex<T>*> gcVertices; std::vector<HbrVertex<T>*> gcVertices;
// List of vertex IDs which may be recycled // List of vertex IDs which may be recycled
std::set<int> recycleIDs; std::set<int> recycleIDs;
// Sorted hierarchical edits. This set is valid only until // Hierarchical edits. This vector is left unsorted until Finish()
// Finish() is called, at which point the mesh should switch over // is called, at which point it is sorted. After that point,
// to using hierarchicalEditArray // HbrFaces have pointers directly into this array so manipulation
std::multiset<HbrHierarchicalEdit<T>*, HbrHierarchicalEditComparator<T> > hierarchicalEditSet; // of it should be avoided.
std::vector<HbrHierarchicalEdit<T>*> hierarchicalEdits;
// Sorted array of hierarchical edits. This array is valid only
// after Finish() has been called. Note that HbrFaces have
// pointers directly into this array so manipulation of it should
// be avoided
int nHierarchicalEdits;
HbrHierarchicalEdit<T>** hierarchicalEditArray;
// Size of faces (including 4 facevarying bits and stitch edges) // Size of faces (including 4 facevarying bits and stitch edges)
const size_t m_faceSize; const size_t m_faceSize;
@ -373,14 +368,14 @@ private:
// Size of vertices (includes storage for one piece of facevarying data) // Size of vertices (includes storage for one piece of facevarying data)
const size_t m_vertexSize; const size_t m_vertexSize;
HbrAllocator<HbrVertex<T> > m_vertexAllocator; HbrAllocator<HbrVertex<T> > m_vertexAllocator;
// Memory used by this mesh alone, plus all its faces and vertices // Memory used by this mesh alone, plus all its faces and vertices
size_t m_memory; size_t m_memory;
// Number of coarse faces. Initialized at Finish() // Number of coarse faces. Initialized at Finish()
int m_numCoarseFaces; int m_numCoarseFaces;
// Flags which indicate whether the mesh has certain types of // Flags which indicate whether the mesh has certain types of
// edits // edits
unsigned hasVertexEdits:1; unsigned hasVertexEdits:1;
@ -392,11 +387,11 @@ private:
bool m_transientMode; bool m_transientMode;
// Vertices which are transient // Vertices which are transient
std::deque<HbrVertex<T>*> m_transientVertices; std::vector<HbrVertex<T>*> m_transientVertices;
// Faces which are transient // Faces which are transient
std::deque<HbrFace<T>*> m_transientFaces; std::vector<HbrFace<T>*> m_transientFaces;
}; };
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION
@ -429,8 +424,6 @@ HbrMesh<T>::HbrMesh(HbrSubdivision<T>* s, int _fvarcount, const int *_fvarindice
fvarinterpboundarymethod(k_InterpolateBoundaryNone), fvarinterpboundarymethod(k_InterpolateBoundaryNone),
fvarpropagatecorners(false), fvarpropagatecorners(false),
s_memStatsIncrement(0), s_memStatsDecrement(0), s_memStatsIncrement(0), s_memStatsDecrement(0),
nHierarchicalEdits(0),
hierarchicalEditArray(0),
m_faceSize(sizeof(HbrFace<T>) + 4 * m_faceSize(sizeof(HbrFace<T>) + 4 *
((fvarcount + 15) / 16 * sizeof(unsigned int) ((fvarcount + 15) / 16 * sizeof(unsigned int)
#ifdef HBRSTITCH #ifdef HBRSTITCH
@ -438,11 +431,11 @@ HbrMesh<T>::HbrMesh(HbrSubdivision<T>* s, int _fvarcount, const int *_fvarindice
+ sizeof(void*) // for stitch data + sizeof(void*) // for stitch data
#endif #endif
)), )),
m_faceAllocator(&m_memory, 64, 0, 0, m_faceSize), m_faceAllocator(&m_memory, 512, 0, 0, m_faceSize),
m_vertexSize(sizeof(HbrVertex<T>) + m_vertexSize(sizeof(HbrVertex<T>) +
sizeof(HbrHalfedge<T>*) + // for incidentEdges[1] sizeof(HbrHalfedge<T>*) + // for incidentEdges[1]
totalfvarwidth * sizeof(float) + sizeof(HbrFVarData<T>)), totalfvarwidth * sizeof(float) + sizeof(HbrFVarData<T>)),
m_vertexAllocator(&m_memory, 64, 0, 0, m_vertexSize), m_vertexAllocator(&m_memory, 512, 0, 0, m_vertexSize),
m_memory(0), m_memory(0),
m_numCoarseFaces(-1), m_numCoarseFaces(-1),
hasVertexEdits(0), hasVertexEdits(0),
@ -456,17 +449,17 @@ HbrMesh<T>::~HbrMesh() {
int i; int i;
if (faces) { if (faces) {
for (i = 0; i < nfaces; ++i) { for (i = 0; i < nfaces; ++i) {
if (faces[i]) { if (faces[i]) {
faces[i]->Destroy(); faces[i]->Destroy();
m_faceAllocator.Deallocate(faces[i]); m_faceAllocator.Deallocate(faces[i]);
} }
} }
if (s_memStatsDecrement) { if (s_memStatsDecrement) {
s_memStatsDecrement(nfaces * sizeof(HbrFace<T>*)); s_memStatsDecrement(nfaces * sizeof(HbrFace<T>*));
} }
m_memory -= nfaces * sizeof(HbrFace<T>*); m_memory -= nfaces * sizeof(HbrFace<T>*);
delete[] faces; delete[] faces;
} }
if (nvsets) { if (nvsets) {
@ -483,14 +476,12 @@ HbrMesh<T>::~HbrMesh() {
s_memStatsDecrement(vsetsize * sizeof(HbrVertex<T>*)); s_memStatsDecrement(vsetsize * sizeof(HbrVertex<T>*));
} }
m_memory -= vsetsize * sizeof(HbrVertex<T>*); m_memory -= vsetsize * sizeof(HbrVertex<T>*);
} }
delete[] vertices; delete[] vertices;
} }
if (hierarchicalEditArray) { for (typename std::vector<HbrHierarchicalEdit<T>* >::iterator hi =
for (i = 0; i < nHierarchicalEdits; ++i) { hierarchicalEdits.begin(); hi != hierarchicalEdits.end(); ++hi) {
delete hierarchicalEditArray[i]; delete *hi;
}
delete[] hierarchicalEditArray;
} }
} }
@ -501,11 +492,11 @@ HbrMesh<T>::NewVertex(int id, const T &data) {
int arrayindex = id / vsetsize; int arrayindex = id / vsetsize;
int vertindex = id % vsetsize; int vertindex = id % vsetsize;
#if PRMAN or MENV #if PRMAN or MENV
ScopedLock lock(&m_verticesMutex); ScopedLock lock(&m_verticesMutex);
#else #else
IlmThread::Lock lock(m_verticesMutex); IlmThread::Lock lock(m_verticesMutex);
#endif #endif
HbrVertex<T>** vset = 0; HbrVertex<T>** vset = 0;
if (arrayindex >= nvsets) { if (arrayindex >= nvsets) {
HbrVertex<T>*** nvertices = new HbrVertex<T>**[arrayindex + 1]; HbrVertex<T>*** nvertices = new HbrVertex<T>**[arrayindex + 1];
@ -526,22 +517,22 @@ HbrMesh<T>::NewVertex(int id, const T &data) {
vertices = nvertices; vertices = nvertices;
} }
vset = vertices[arrayindex]; vset = vertices[arrayindex];
#if PRMAN or MENV #if PRMAN or MENV
lock.Release(); lock.Release();
#else #else
lock.release(); lock.release();
#endif #endif
v = vset[vertindex]; v = vset[vertindex];
if (v) { if (v) {
v->Destroy(); v->Destroy();
} else { } else {
v = m_vertexAllocator.Allocate(); v = m_vertexAllocator.Allocate();
} }
v->Initialize(id, data, GetTotalFVarWidth()); v->Initialize(id, data, GetTotalFVarWidth());
vset[vertindex] = v; vset[vertindex] = v;
if (id >= maxVertexID) { if (id >= maxVertexID) {
maxVertexID = id + 1; maxVertexID = id + 1;
} }
// Newly created vertices are always candidates for garbage // Newly created vertices are always candidates for garbage
@ -563,11 +554,11 @@ HbrMesh<T>::NewVertex(const T &data) {
// we can // we can
int id = maxVertexID; int id = maxVertexID;
if (!recycleIDs.empty()) { if (!recycleIDs.empty()) {
id = *recycleIDs.begin(); id = *recycleIDs.begin();
recycleIDs.erase(recycleIDs.begin()); recycleIDs.erase(recycleIDs.begin());
} }
if (id >= maxVertexID) { if (id >= maxVertexID) {
maxVertexID = id + 1; maxVertexID = id + 1;
} }
return NewVertex(id, data); return NewVertex(id, data);
} }
@ -579,11 +570,11 @@ HbrMesh<T>::NewVertex() {
// we can // we can
int id = maxVertexID; int id = maxVertexID;
if (!recycleIDs.empty()) { if (!recycleIDs.empty()) {
id = *recycleIDs.begin(); id = *recycleIDs.begin();
recycleIDs.erase(recycleIDs.begin()); recycleIDs.erase(recycleIDs.begin());
} }
if (id >= maxVertexID) { if (id >= maxVertexID) {
maxVertexID = id + 1; maxVertexID = id + 1;
} }
T data(id); T data(id);
data.Clear(); data.Clear();
@ -596,11 +587,11 @@ HbrMesh<T>::GetVertex(int id) const {
int arrayindex = id / vsetsize; int arrayindex = id / vsetsize;
int vertindex = id % vsetsize; int vertindex = id % vsetsize;
#if PRMAN or MENV #if PRMAN or MENV
ScopedLock lock(&m_verticesMutex); ScopedLock lock(&m_verticesMutex);
#else #else
IlmThread::Lock lock(m_verticesMutex); IlmThread::Lock lock(m_verticesMutex);
#endif #endif
if (arrayindex >= nvsets) { if (arrayindex >= nvsets) {
return 0; return 0;
} }
@ -614,45 +605,45 @@ HbrMesh<T>::NewFace(int nv, int *vtx, int uindex) {
HbrVertex<T>** facevertices = reinterpret_cast<HbrVertex<T>**>(alloca(sizeof(HbrVertex<T>*) * nv)); HbrVertex<T>** facevertices = reinterpret_cast<HbrVertex<T>**>(alloca(sizeof(HbrVertex<T>*) * nv));
int i; int i;
for (i = 0; i < nv; ++i) { for (i = 0; i < nv; ++i) {
facevertices[i] = GetVertex(vtx[i]); facevertices[i] = GetVertex(vtx[i]);
if (!facevertices[i]) { if (!facevertices[i]) {
return 0; return 0;
} }
} }
HbrFace<T> *f = 0; HbrFace<T> *f = 0;
// Resize if needed // Resize if needed
if (nfaces <= maxFaceID) { if (nfaces <= maxFaceID) {
int nnfaces = nfaces; int nnfaces = nfaces;
while (nnfaces <= maxFaceID) { while (nnfaces <= maxFaceID) {
nnfaces *= 2; nnfaces *= 2;
if (nnfaces < 1) nnfaces = 1; if (nnfaces < 1) nnfaces = 1;
} }
HbrFace<T>** newfaces = new HbrFace<T>*[nnfaces]; HbrFace<T>** newfaces = new HbrFace<T>*[nnfaces];
if (s_memStatsIncrement) { if (s_memStatsIncrement) {
s_memStatsIncrement(nnfaces * sizeof(HbrFace<T>*)); s_memStatsIncrement(nnfaces * sizeof(HbrFace<T>*));
} }
m_memory += nnfaces * sizeof(HbrFace<T>*); m_memory += nnfaces * sizeof(HbrFace<T>*);
if (faces) { if (faces) {
for (i = 0; i < nfaces; ++i) { for (i = 0; i < nfaces; ++i) {
newfaces[i] = faces[i]; newfaces[i] = faces[i];
} }
if (s_memStatsDecrement) { if (s_memStatsDecrement) {
s_memStatsDecrement(nfaces * sizeof(HbrFace<T>*)); s_memStatsDecrement(nfaces * sizeof(HbrFace<T>*));
} }
m_memory -= nfaces * sizeof(HbrFace<T>*); m_memory -= nfaces * sizeof(HbrFace<T>*);
delete[] faces; delete[] faces;
} }
for (i = nfaces; i < nnfaces; ++i) { for (i = nfaces; i < nnfaces; ++i) {
newfaces[i] = 0; newfaces[i] = 0;
} }
faces = newfaces; faces = newfaces;
nfaces = nnfaces; nfaces = nnfaces;
} }
f = faces[maxFaceID]; f = faces[maxFaceID];
if (f) { if (f) {
f->Destroy(); f->Destroy();
} else { } else {
f = m_faceAllocator.Allocate(); f = m_faceAllocator.Allocate();
} }
f->Initialize(this, NULL, -1, maxFaceID, uindex, nv, facevertices, totalfvarwidth, 0); f->Initialize(this, NULL, -1, maxFaceID, uindex, nv, facevertices, totalfvarwidth, 0);
faces[maxFaceID] = f; faces[maxFaceID] = f;
@ -673,37 +664,37 @@ HbrMesh<T>::NewFace(int nv, HbrVertex<T> **vtx, HbrFace<T>* parent, int childind
HbrFace<T> *f = 0; HbrFace<T> *f = 0;
// Resize if needed // Resize if needed
if (nfaces <= maxFaceID) { if (nfaces <= maxFaceID) {
int nnfaces = nfaces; int nnfaces = nfaces;
while (nnfaces <= maxFaceID) { while (nnfaces <= maxFaceID) {
nnfaces *= 2; nnfaces *= 2;
if (nnfaces < 1) nnfaces = 1; if (nnfaces < 1) nnfaces = 1;
} }
HbrFace<T>** newfaces = new HbrFace<T>*[nnfaces]; HbrFace<T>** newfaces = new HbrFace<T>*[nnfaces];
if (s_memStatsIncrement) { if (s_memStatsIncrement) {
s_memStatsIncrement(nnfaces * sizeof(HbrFace<T>*)); s_memStatsIncrement(nnfaces * sizeof(HbrFace<T>*));
} }
m_memory += nnfaces * sizeof(HbrFace<T>*); m_memory += nnfaces * sizeof(HbrFace<T>*);
if (faces) { if (faces) {
for (int i = 0; i < nfaces; ++i) { for (int i = 0; i < nfaces; ++i) {
newfaces[i] = faces[i]; newfaces[i] = faces[i];
} }
if (s_memStatsDecrement) { if (s_memStatsDecrement) {
s_memStatsDecrement(nfaces * sizeof(HbrFace<T>*)); s_memStatsDecrement(nfaces * sizeof(HbrFace<T>*));
} }
m_memory -= nfaces * sizeof(HbrFace<T>*); m_memory -= nfaces * sizeof(HbrFace<T>*);
delete[] faces; delete[] faces;
} }
for (int i = nfaces; i < nnfaces; ++i) { for (int i = nfaces; i < nnfaces; ++i) {
newfaces[i] = 0; newfaces[i] = 0;
} }
faces = newfaces; faces = newfaces;
nfaces = nnfaces; nfaces = nnfaces;
} }
f = faces[maxFaceID]; f = faces[maxFaceID];
if (f) { if (f) {
f->Destroy(); f->Destroy();
} else { } else {
f = m_faceAllocator.Allocate(); f = m_faceAllocator.Allocate();
} }
f->Initialize(this, parent, childindex, maxFaceID, parent ? parent->GetUniformIndex() : 0, nv, vtx, totalfvarwidth, parent ? parent->GetDepth() + 1 : 0); f->Initialize(this, parent, childindex, maxFaceID, parent ? parent->GetUniformIndex() : 0, nv, vtx, totalfvarwidth, parent ? parent->GetDepth() + 1 : 0);
if (parent) { if (parent) {
@ -725,36 +716,36 @@ HbrMesh<T>::Finish() {
int i, j; int i, j;
m_numCoarseFaces = 0; m_numCoarseFaces = 0;
for (i = 0; i < nfaces; ++i) { for (i = 0; i < nfaces; ++i) {
if (faces[i]) { if (faces[i]) {
faces[i]->SetCoarse(); faces[i]->SetCoarse();
m_numCoarseFaces++; m_numCoarseFaces++;
} }
} }
std::list<HbrVertex<T>*> vertexlist; std::vector<HbrVertex<T>*> vertexlist;
GetVertices(vertexlist); GetVertices(vertexlist);
for (typename std::list<HbrVertex<T>*>::iterator vi = vertexlist.begin(); for (typename std::vector<HbrVertex<T>*>::iterator vi = vertexlist.begin();
vi != vertexlist.end(); ++vi) { vi != vertexlist.end(); ++vi) {
HbrVertex<T>* vertex = *vi; HbrVertex<T>* vertex = *vi;
if (vertex->IsConnected()) vertex->Finish(); if (vertex->IsConnected()) vertex->Finish();
} }
// If interpolateboundary is on, process boundary edges // If interpolateboundary is on, process boundary edges
if (interpboundarymethod == k_InterpolateBoundaryEdgeOnly || interpboundarymethod == k_InterpolateBoundaryEdgeAndCorner) { if (interpboundarymethod == k_InterpolateBoundaryEdgeOnly || interpboundarymethod == k_InterpolateBoundaryEdgeAndCorner) {
for (i = 0; i < nfaces; ++i) { for (i = 0; i < nfaces; ++i) {
if (HbrFace<T>* face = faces[i]) { if (HbrFace<T>* face = faces[i]) {
int nv = face->GetNumVertices(); int nv = face->GetNumVertices();
for (int k = 0; k < nv; ++k) { for (int k = 0; k < nv; ++k) {
HbrHalfedge<T>* edge = face->GetEdge(k); HbrHalfedge<T>* edge = face->GetEdge(k);
if (edge->IsBoundary()) { if (edge->IsBoundary()) {
edge->SetSharpness(HbrHalfedge<T>::k_InfinitelySharp); edge->SetSharpness(HbrHalfedge<T>::k_InfinitelySharp);
} }
} }
} }
} }
} }
// Process corners // Process corners
if (interpboundarymethod == k_InterpolateBoundaryEdgeAndCorner) { if (interpboundarymethod == k_InterpolateBoundaryEdgeAndCorner) {
for (typename std::list<HbrVertex<T>*>::iterator vi = vertexlist.begin(); for (typename std::vector<HbrVertex<T>*>::iterator vi = vertexlist.begin();
vi != vertexlist.end(); ++vi) { vi != vertexlist.end(); ++vi) {
HbrVertex<T>* vertex = *vi; HbrVertex<T>* vertex = *vi;
if (vertex && vertex->IsConnected() && vertex->OnBoundary() && vertex->GetCoarseValence() == 2) { if (vertex && vertex->IsConnected() && vertex->OnBoundary() && vertex->GetCoarseValence() == 2) {
@ -762,31 +753,27 @@ HbrMesh<T>::Finish() {
} }
} }
} }
// Convert the sorted set of hierarchical edits to an array
nHierarchicalEdits = hierarchicalEditSet.size(); // Sort the hierarchical edits
if (nHierarchicalEdits) { if (!hierarchicalEdits.empty()) {
// Size the array by one extra; the last will be a sentinel HbrHierarchicalEditComparator<T> cmp;
// value (null) int nHierarchicalEdits = (int)hierarchicalEdits.size();
hierarchicalEditArray = new HbrHierarchicalEdit<T>*[nHierarchicalEdits + 1]; std::sort(hierarchicalEdits.begin(), hierarchicalEdits.end(), cmp);
i = 0; // Push a sentinel null value - we rely upon this sentinel to
for (typename std::multiset<HbrHierarchicalEdit<T>*, HbrHierarchicalEditComparator<T> >::iterator pi = hierarchicalEditSet.begin(); pi != hierarchicalEditSet.end(); ++pi) { // ensure face->GetHierarchicalEdits knows when to terminate
hierarchicalEditArray[i++] = *pi; hierarchicalEdits.push_back(0);
}
assert(i == nHierarchicalEdits);
hierarchicalEditArray[i] = 0;
j = 0; j = 0;
// Link faces to hierarchical edits // Link faces to hierarchical edits
for (i = 0; i < nfaces; ++i) { for (i = 0; i < nfaces; ++i) {
if (faces[i]) { if (faces[i]) {
while (j < nHierarchicalEdits && hierarchicalEditArray[j]->GetFaceID() < i) { while (j < nHierarchicalEdits && hierarchicalEdits[j]->GetFaceID() < i) {
++j; ++j;
} }
if (j < nHierarchicalEdits && hierarchicalEditArray[j]->GetFaceID() == i) { if (j < nHierarchicalEdits && hierarchicalEdits[j]->GetFaceID() == i) {
faces[i]->SetHierarchicalEdits(&hierarchicalEditArray[j]); faces[i]->SetHierarchicalEdits(&hierarchicalEdits[j]);
} }
} }
} }
hierarchicalEditSet.clear();
} }
} }
@ -794,12 +781,12 @@ template <class T>
void void
HbrMesh<T>::DeleteFace(HbrFace<T>* face) { HbrMesh<T>::DeleteFace(HbrFace<T>* face) {
if (face->GetID() < nfaces) { if (face->GetID() < nfaces) {
HbrFace<T>* f = faces[face->GetID()]; HbrFace<T>* f = faces[face->GetID()];
if (f == face) { if (f == face) {
faces[face->GetID()] = 0; faces[face->GetID()] = 0;
face->Destroy(); face->Destroy();
m_faceAllocator.Deallocate(face); m_faceAllocator.Deallocate(face);
} }
} }
} }
@ -811,18 +798,18 @@ HbrMesh<T>::DeleteVertex(HbrVertex<T>* vertex) {
recycleIDs.insert(vertex->GetID()); recycleIDs.insert(vertex->GetID());
int id = vertex->GetID(); int id = vertex->GetID();
int arrayindex = id / vsetsize; int arrayindex = id / vsetsize;
#if PRMAN or MENV #if PRMAN or MENV
ScopedLock lock(&m_verticesMutex); ScopedLock lock(&m_verticesMutex);
#else #else
IlmThread::Lock lock(m_verticesMutex); IlmThread::Lock lock(m_verticesMutex);
#endif #endif
int vertindex = id % vsetsize; int vertindex = id % vsetsize;
HbrVertex<T>** vset = vertices[arrayindex]; HbrVertex<T>** vset = vertices[arrayindex];
#if PRMAN or MENV #if PRMAN or MENV
lock.Release(); lock.Release();
#else #else
lock.release(); lock.release();
#endif #endif
vset[vertindex] = 0; vset[vertindex] = 0;
vertex->Destroy(); vertex->Destroy();
m_vertexAllocator.Deallocate(vertex); m_vertexAllocator.Deallocate(vertex);
@ -833,11 +820,11 @@ template <class T>
int int
HbrMesh<T>::GetNumVertices() const { HbrMesh<T>::GetNumVertices() const {
int count = 0; int count = 0;
#if PRMAN or MENV #if PRMAN or MENV
ScopedLock lock(&m_verticesMutex); ScopedLock lock(&m_verticesMutex);
#else #else
IlmThread::Lock lock(m_verticesMutex); IlmThread::Lock lock(m_verticesMutex);
#endif #endif
for (int vi = 0; vi < nvsets; ++vi) { for (int vi = 0; vi < nvsets; ++vi) {
HbrVertex<T>** vset = vertices[vi]; HbrVertex<T>** vset = vertices[vi];
for (int i = 0; i < vsetsize; ++i) { for (int i = 0; i < vsetsize; ++i) {
@ -851,11 +838,11 @@ template <class T>
int int
HbrMesh<T>::GetNumDisconnectedVertices() const { HbrMesh<T>::GetNumDisconnectedVertices() const {
int disconnected = 0; int disconnected = 0;
#if PRMAN or MENV #if PRMAN or MENV
ScopedLock lock(&m_verticesMutex); ScopedLock lock(&m_verticesMutex);
#else #else
IlmThread::Lock lock(m_verticesMutex); IlmThread::Lock lock(m_verticesMutex);
#endif #endif
for (int vi = 0; vi < nvsets; ++vi) { for (int vi = 0; vi < nvsets; ++vi) {
HbrVertex<T>** vset = vertices[vi]; HbrVertex<T>** vset = vertices[vi];
for (int i = 0; i < vsetsize; ++i) { for (int i = 0; i < vsetsize; ++i) {
@ -874,7 +861,7 @@ int
HbrMesh<T>::GetNumFaces() const { HbrMesh<T>::GetNumFaces() const {
int count = 0; int count = 0;
for (int i = 0; i < nfaces; ++i) { for (int i = 0; i < nfaces; ++i) {
if (faces[i]) count++; if (faces[i]) count++;
} }
return count; return count;
} }
@ -887,7 +874,7 @@ HbrMesh<T>::GetNumCoarseFaces() const {
// Otherwise we have to just count it up now // Otherwise we have to just count it up now
int count = 0; int count = 0;
for (int i = 0; i < nfaces; ++i) { for (int i = 0; i < nfaces; ++i) {
if (faces[i] && faces[i]->IsCoarse()) count++; if (faces[i] && faces[i]->IsCoarse()) count++;
} }
return count; return count;
} }
@ -896,19 +883,19 @@ template <class T>
HbrFace<T>* HbrFace<T>*
HbrMesh<T>::GetFace(int id) const { HbrMesh<T>::GetFace(int id) const {
if (id < nfaces) { if (id < nfaces) {
return faces[id]; return faces[id];
} }
return 0; return 0;
} }
template <class T> template <class T>
void void
HbrMesh<T>::GetVertices(std::list<HbrVertex<T>*>& lvertices) const { HbrMesh<T>::GetVertices(std::vector<HbrVertex<T>*>& lvertices) const {
#if PRMAN or MENV #if PRMAN or MENV
ScopedLock lock(&m_verticesMutex); ScopedLock lock(&m_verticesMutex);
#else #else
IlmThread::Lock lock(m_verticesMutex); IlmThread::Lock lock(m_verticesMutex);
#endif #endif
for (int vi = 0; vi < nvsets; ++vi) { for (int vi = 0; vi < nvsets; ++vi) {
HbrVertex<T>** vset = vertices[vi]; HbrVertex<T>** vset = vertices[vi];
for (int i = 0; i < vsetsize; ++i) { for (int i = 0; i < vsetsize; ++i) {
@ -920,11 +907,11 @@ HbrMesh<T>::GetVertices(std::list<HbrVertex<T>*>& lvertices) const {
template <class T> template <class T>
void void
HbrMesh<T>::ApplyOperatorAllVertices(HbrVertexOperator<T> &op) const { HbrMesh<T>::ApplyOperatorAllVertices(HbrVertexOperator<T> &op) const {
#if PRMAN or MENV #if PRMAN or MENV
ScopedLock lock(&m_verticesMutex); ScopedLock lock(&m_verticesMutex);
#else #else
IlmThread::Lock lock(m_verticesMutex); IlmThread::Lock lock(m_verticesMutex);
#endif #endif
for (int vi = 0; vi < nvsets; ++vi) { for (int vi = 0; vi < nvsets; ++vi) {
HbrVertex<T>** vset = vertices[vi]; HbrVertex<T>** vset = vertices[vi];
for (int i = 0; i < vsetsize; ++i) { for (int i = 0; i < vsetsize; ++i) {
@ -935,9 +922,9 @@ HbrMesh<T>::ApplyOperatorAllVertices(HbrVertexOperator<T> &op) const {
template <class T> template <class T>
void void
HbrMesh<T>::GetFaces(std::list<HbrFace<T>*>& lfaces) const { HbrMesh<T>::GetFaces(std::vector<HbrFace<T>*>& lfaces) const {
for (int i = 0; i < nfaces; ++i) { for (int i = 0; i < nfaces; ++i) {
if (faces[i]) lfaces.push_back(faces[i]); if (faces[i]) lfaces.push_back(faces[i]);
} }
} }
@ -959,7 +946,7 @@ HbrMesh<T>::PrintStats(std::ostream &out) {
singular++; singular++;
} }
else if (!v->IsConnected()) { else if (!v->IsConnected()) {
out << " disconnected: " << *v << "\n"; out << " disconnected: " << *v << "\n";
disconnected++; disconnected++;
} else { } else {
if (v->IsExtraordinary()) { if (v->IsExtraordinary()) {
@ -979,74 +966,80 @@ HbrMesh<T>::PrintStats(std::ostream &out) {
int sumsides = 0; int sumsides = 0;
int numfaces = 0; int numfaces = 0;
for (i = 0; i < nfaces; ++i) { for (i = 0; i < nfaces; ++i) {
if (HbrFace<T>* f = faces[i]) { if (HbrFace<T>* f = faces[i]) {
numfaces++; numfaces++;
sumsides += f->GetNumVertices(); sumsides += f->GetNumVertices();
} }
} }
out << "Mesh has " << nfaces << " faces\n"; out << "Mesh has " << nfaces << " faces\n";
out << "Average sidedness " << (float) sumsides / nfaces << "\n"; out << "Average sidedness " << (float) sumsides / nfaces << "\n";
} }
#define HBR_MESH_BUFFERSIZE 4096
template <class T> template <class T>
void void
HbrMesh<T>::GarbageCollect() { HbrMesh<T>::GarbageCollect() {
if (gcVertices.empty()) return; if (gcVertices.empty()) return;
if (gcVertices.size() <= HBR_MESH_BUFFERSIZE) return; static const size_t gcthreshold = 4096;
if (gcVertices.size() <= gcthreshold) return;
// Go through the list of garbage collectable vertices and gather // Go through the list of garbage collectable vertices and gather
// up the neighboring faces of those vertices which can be garbage // up the neighboring faces of those vertices which can be garbage
// collected. // collected.
std::list<HbrFace<T>*> killlist; std::vector<HbrFace<T>*> killlist;
std::list<HbrVertex<T>*> vlist; std::vector<HbrVertex<T>*> vlist;
while (gcVertices.size() > HBR_MESH_BUFFERSIZE / 2) { // Process the vertices in the same order as they were collected
HbrVertex<T>* v = gcVertices.front(); gcVertices.pop_front(); // (gcVertices used to be declared as a std::deque, but that was
v->ClearCollected(); // causing unnecessary heap traffic).
if (v->IsUsed()) continue; int numprocessed = gcVertices.size() - gcthreshold / 2;
vlist.push_back(v); for (int i = 0; i < numprocessed; ++i) {
HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge; HbrVertex<T>* v = gcVertices[i];
edge = start; v->ClearCollected();
while (edge) { if (v->IsUsed()) continue;
HbrFace<T>* f = edge->GetLeftFace(); vlist.push_back(v);
if (!f->IsCollected()) { HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge;
edge = start;
while (edge) {
HbrFace<T>* f = edge->GetLeftFace();
if (!f->IsCollected()) {
f->SetCollected(); f->SetCollected();
killlist.push_back(f); killlist.push_back(f);
} }
edge = v->GetNextEdge(edge); edge = v->GetNextEdge(edge);
if (edge == start) break; if (edge == start) break;
} }
} }
gcVertices.erase(gcVertices.begin(), gcVertices.begin() + numprocessed);
// Delete those faces // Delete those faces
for (typename std::list<HbrFace<T>*>::iterator fi = killlist.begin(); fi != killlist.end(); ++fi) { for (typename std::vector<HbrFace<T>*>::iterator fi = killlist.begin(); fi != killlist.end(); ++fi) {
if ((*fi)->GarbageCollectable()) { if ((*fi)->GarbageCollectable()) {
DeleteFace(*fi); DeleteFace(*fi);
} else { } else {
(*fi)->ClearCollected(); (*fi)->ClearCollected();
} }
} }
// Delete as many vertices as we can // Delete as many vertices as we can
for (typename std::list<HbrVertex<T>*>::iterator vi = vlist.begin(); vi != vlist.end(); ++vi) { for (typename std::vector<HbrVertex<T>*>::iterator vi = vlist.begin(); vi != vlist.end(); ++vi) {
HbrVertex<T>* v = *vi; HbrVertex<T>* v = *vi;
if (!v->IsReferenced()) { if (!v->IsReferenced()) {
DeleteVertex(v); DeleteVertex(v);
} }
} }
} }
template <class T> template <class T>
void void
HbrMesh<T>::AddHierarchicalEdit(HbrHierarchicalEdit<T>* edit) { HbrMesh<T>::AddHierarchicalEdit(HbrHierarchicalEdit<T>* edit) {
hierarchicalEditSet.insert(edit); hierarchicalEdits.push_back(edit);
if (dynamic_cast<HbrVertexEdit<T>*>(edit) || if (dynamic_cast<HbrVertexEdit<T>*>(edit) ||
dynamic_cast<HbrMovingVertexEdit<T>*>(edit)) { dynamic_cast<HbrMovingVertexEdit<T>*>(edit)) {
hasVertexEdits = 1; hasVertexEdits = 1;
} else if (dynamic_cast<HbrCreaseEdit<T>*>(edit)) { } else if (dynamic_cast<HbrCreaseEdit<T>*>(edit)) {
hasCreaseEdits = 1; hasCreaseEdits = 1;
} }
} }
@ -1054,13 +1047,13 @@ template <class T>
void void
HbrMesh<T>::FreeTransientData() { HbrMesh<T>::FreeTransientData() {
// When purging transient data, we must clear the faces first // When purging transient data, we must clear the faces first
for (typename std::deque<HbrFace<T>*>::iterator fi = m_transientFaces.begin(); for (typename std::vector<HbrFace<T>*>::iterator fi = m_transientFaces.begin();
fi != m_transientFaces.end(); ++fi) { fi != m_transientFaces.end(); ++fi) {
DeleteFace(*fi); DeleteFace(*fi);
} }
// The vertices should now be trivial to purge after the transient // The vertices should now be trivial to purge after the transient
// faces have been cleared // faces have been cleared
for (typename std::deque<HbrVertex<T>*>::iterator vi = m_transientVertices.begin(); for (typename std::vector<HbrVertex<T>*>::iterator vi = m_transientVertices.begin();
vi != m_transientVertices.end(); ++vi) { vi != m_transientVertices.end(); ++vi) {
DeleteVertex(*vi); DeleteVertex(*vi);
} }
@ -1075,11 +1068,11 @@ HbrMesh<T>::FreeTransientData() {
} }
} }
// Reset max vertex ID. Slightly more complicated // Reset max vertex ID. Slightly more complicated
#if PRMAN or MENV #if PRMAN or MENV
ScopedLock lock(&m_verticesMutex); ScopedLock lock(&m_verticesMutex);
#else #else
IlmThread::Lock lock(m_verticesMutex); IlmThread::Lock lock(m_verticesMutex);
#endif #endif
for (i = (nvsets * vsetsize) - 1; i >= 0; --i) { for (i = (nvsets * vsetsize) - 1; i >= 0; --i) {
int arrayindex = i / vsetsize; int arrayindex = i / vsetsize;
int vertindex = i % vsetsize; int vertindex = i % vsetsize;

View File

@ -69,12 +69,12 @@ template <class T> class HbrMesh;
template <class T> class HbrSubdivision { template <class T> class HbrSubdivision {
public: public:
HbrSubdivision<T>() HbrSubdivision<T>()
: creaseSubdivision(k_CreaseNormal) {} : creaseSubdivision(k_CreaseNormal) {}
virtual ~HbrSubdivision<T>() {} virtual ~HbrSubdivision<T>() {}
virtual HbrSubdivision<T>* Clone() const = 0; virtual HbrSubdivision<T>* Clone() const = 0;
// How to subdivide a face // How to subdivide a face
virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face) = 0; virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face) = 0;
@ -83,7 +83,7 @@ public:
// Refine all faces around a particular vertex // Refine all faces around a particular vertex
virtual void RefineAtVertex(HbrMesh<T>* mesh, HbrVertex<T>* vertex); virtual void RefineAtVertex(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
// Given an edge, try to ensure the edge's opposite exists by // Given an edge, try to ensure the edge's opposite exists by
// forcing refinement up the hierarchy // forcing refinement up the hierarchy
virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) = 0; virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) = 0;
@ -97,7 +97,7 @@ public:
virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrFace<T>* /* face */) { return true; } virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrFace<T>* /* face */) { return true; }
virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrHalfedge<T>* /* edge */) { return true; } virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrHalfedge<T>* /* edge */) { return true; }
virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrVertex<T>* /* vertex */) { return true; } virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrVertex<T>* /* vertex */) { return true; }
// How to turn faces, edges, and vertices into vertices // How to turn faces, edges, and vertices into vertices
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) = 0; virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) = 0;
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) = 0; virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) = 0;
@ -106,6 +106,9 @@ public:
// Returns true if the vertex is extraordinary in the subdivision scheme // Returns true if the vertex is extraordinary in the subdivision scheme
virtual bool VertexIsExtraordinary(HbrMesh<T>* /* mesh */, HbrVertex<T>* /* vertex */) { return false; } virtual bool VertexIsExtraordinary(HbrMesh<T>* /* mesh */, HbrVertex<T>* /* vertex */) { return false; }
// Returns true if the face is extraordinary in the subdivision scheme
virtual bool FaceIsExtraordinary(HbrMesh<T>* /* mesh */, HbrFace<T>* /* face */) { return false; }
// Crease subdivision rules. When subdividing a edge with a crease // Crease subdivision rules. When subdividing a edge with a crease
// strength, we get two child subedges, and we need to determine // strength, we get two child subedges, and we need to determine
// what weights to assign these subedges. The "normal" rule // what weights to assign these subedges. The "normal" rule
@ -115,8 +118,8 @@ public:
// vertices, and weighs them; for more information consult // vertices, and weighs them; for more information consult
// the Geri's Game paper. // the Geri's Game paper.
enum CreaseSubdivision { enum CreaseSubdivision {
k_CreaseNormal, k_CreaseNormal,
k_CreaseChaikin k_CreaseChaikin
}; };
CreaseSubdivision GetCreaseSubdivisionMethod() const { return creaseSubdivision; } CreaseSubdivision GetCreaseSubdivisionMethod() const { return creaseSubdivision; }
void SetCreaseSubdivisionMethod(CreaseSubdivision method) { creaseSubdivision = method; } void SetCreaseSubdivisionMethod(CreaseSubdivision method) { creaseSubdivision = method; }
@ -132,7 +135,7 @@ public:
// Returns the expected number of children faces after subdivision // Returns the expected number of children faces after subdivision
// for a face with the given number of vertices. // for a face with the given number of vertices.
virtual int GetFaceChildrenCount(int nvertices) const = 0; virtual int GetFaceChildrenCount(int nvertices) const = 0;
protected: protected:
CreaseSubdivision creaseSubdivision; CreaseSubdivision creaseSubdivision;
@ -143,7 +146,7 @@ protected:
// Helper routine for subclasses: for a given vertex with a crease // Helper routine for subclasses: for a given vertex with a crease
// mask, adds contributions from the two crease edges // mask, adds contributions from the two crease edges
void AddCreaseEdgesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, bool next, float weight, T* data); void AddCreaseEdgesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, bool next, float weight, T* data);
private: private:
// Helper class used by AddSurroundingVerticesWithWeight // Helper class used by AddSurroundingVerticesWithWeight
class SmoothSubdivisionVertexOperator : public HbrVertexOperator<T> { class SmoothSubdivisionVertexOperator : public HbrVertexOperator<T> {
@ -155,7 +158,7 @@ private:
{ {
} }
virtual void operator() (HbrVertex<T> &vertex) { virtual void operator() (HbrVertex<T> &vertex) {
// Must ensure vertex edits have been applied // Must ensure vertex edits have been applied
if (m_meshHasEdits) { if (m_meshHasEdits) {
vertex.GuaranteeNeighbors(); vertex.GuaranteeNeighbors();
} }
@ -186,7 +189,7 @@ private:
// Must ensure vertex edits have been applied // Must ensure vertex edits have been applied
if (m_meshHasEdits) { if (m_meshHasEdits) {
a->GuaranteeNeighbors(); a->GuaranteeNeighbors();
} }
m_data->AddWithWeight(a->GetData(), m_weight); m_data->AddWithWeight(a->GetData(), m_weight);
m_count++; m_count++;
} }
@ -218,7 +221,7 @@ private:
HbrMesh<T>* const m_mesh; HbrMesh<T>* const m_mesh;
HbrVertex<T>* const m_vertex; HbrVertex<T>* const m_vertex;
}; };
}; };
template <class T> template <class T>
@ -238,48 +241,48 @@ HbrSubdivision<T>::SubdivideCreaseWeight(HbrHalfedge<T>* edge, HbrVertex<T>* ver
// In all methods, if the parent edge is infinitely sharp, the // In all methods, if the parent edge is infinitely sharp, the
// child edge is also infinitely sharp // child edge is also infinitely sharp
if (sharpness >= HbrHalfedge<T>::k_InfinitelySharp) { if (sharpness >= HbrHalfedge<T>::k_InfinitelySharp) {
subedge->SetSharpness(HbrHalfedge<T>::k_InfinitelySharp); subedge->SetSharpness(HbrHalfedge<T>::k_InfinitelySharp);
} }
// Chaikin's curve subdivision: use 3/4 of the parent sharpness, // Chaikin's curve subdivision: use 3/4 of the parent sharpness,
// plus 1/4 of crease sharpnesses incident to vertex // plus 1/4 of crease sharpnesses incident to vertex
else if (creaseSubdivision == HbrSubdivision<T>::k_CreaseChaikin) { else if (creaseSubdivision == HbrSubdivision<T>::k_CreaseChaikin) {
float childsharp = 0.0f; float childsharp = 0.0f;
// Add 1/4 of the sharpness of all crease edges incident to // Add 1/4 of the sharpness of all crease edges incident to
// the vertex (other than this crease edge) // the vertex (other than this crease edge)
std::list<HbrHalfedge<T>*> edges; std::vector<HbrHalfedge<T>*> edges;
vertex->GuaranteeNeighbors(); vertex->GuaranteeNeighbors();
vertex->GetSurroundingEdges(edges); vertex->GetSurroundingEdges(edges);
int n = 0; int n = 0;
for (typename std::list<HbrHalfedge<T>*>::iterator ei = edges.begin(); ei != edges.end(); ++ei) { for (typename std::vector<HbrHalfedge<T>*>::iterator ei = edges.begin(); ei != edges.end(); ++ei) {
if (*ei == edge) continue; if (*ei == edge) continue;
if ((*ei)->GetSharpness() > HbrHalfedge<T>::k_Smooth) { if ((*ei)->GetSharpness() > HbrHalfedge<T>::k_Smooth) {
childsharp += (*ei)->GetSharpness(); childsharp += (*ei)->GetSharpness();
n++; n++;
} }
} }
if (n) {
childsharp = childsharp * 0.25f / n;
}
// Add 3/4 of the sharpness of this crease edge
childsharp += sharpness * 0.75f;
childsharp -= 1.0f;
if (childsharp < (float) HbrHalfedge<T>::k_Smooth) {
childsharp = (float) HbrHalfedge<T>::k_Smooth;
}
subedge->SetSharpness(childsharp);
if (n) {
childsharp = childsharp * 0.25f / n;
}
// Add 3/4 of the sharpness of this crease edge
childsharp += sharpness * 0.75f;
childsharp -= 1.0f;
if (childsharp < (float) HbrHalfedge<T>::k_Smooth) {
childsharp = (float) HbrHalfedge<T>::k_Smooth;
}
subedge->SetSharpness(childsharp);
} else { } else {
sharpness -= 1.0f; sharpness -= 1.0f;
if (sharpness < (float) HbrHalfedge<T>::k_Smooth) { if (sharpness < (float) HbrHalfedge<T>::k_Smooth) {
sharpness = (float) HbrHalfedge<T>::k_Smooth; sharpness = (float) HbrHalfedge<T>::k_Smooth;
} }
subedge->SetSharpness(sharpness); subedge->SetSharpness(sharpness);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -71,7 +71,7 @@ template <class T>
std::ostream& operator<<(std::ostream& out, const HbrVertexEdit<T>& path) { std::ostream& operator<<(std::ostream& out, const HbrVertexEdit<T>& path) {
out << "vertex path = (" << path.faceid << ' '; out << "vertex path = (" << path.faceid << ' ';
for (int i = 0; i < path.nsubfaces; ++i) { for (int i = 0; i < path.nsubfaces; ++i) {
out << static_cast<int>(path.subfaces[i]) << ' '; out << static_cast<int>(path.subfaces[i]) << ' ';
} }
return out << static_cast<int>(path.vertexid) << "), edit = (" << path.edit[0] << ',' << path.edit[1] << ',' << path.edit[2] << ')'; return out << static_cast<int>(path.vertexid) << "), edit = (" << path.edit[0] << ',' << path.edit[1] << ',' << path.edit[2] << ')';
} }
@ -82,24 +82,24 @@ class HbrVertexEdit : public HbrHierarchicalEdit<T> {
public: public:
HbrVertexEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _vertexid, int _index, int _width, bool _isP, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit) HbrVertexEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _vertexid, int _index, int _width, bool _isP, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
edit = new float[width]; edit = new float[width];
memcpy(edit, _edit, width * sizeof(float)); memcpy(edit, _edit, width * sizeof(float));
} }
HbrVertexEdit(int _faceid, int _nsubfaces, int *_subfaces, int _vertexid, int _index, int _width, bool _isP, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit) HbrVertexEdit(int _faceid, int _nsubfaces, int *_subfaces, int _vertexid, int _index, int _width, bool _isP, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
edit = new float[width]; edit = new float[width];
memcpy(edit, _edit, width * sizeof(float)); memcpy(edit, _edit, width * sizeof(float));
} }
virtual ~HbrVertexEdit() { virtual ~HbrVertexEdit() {
delete[] edit; delete[] edit;
} }
// Return the vertex id (the last element in the path) // Return the vertex id (the last element in the path)
unsigned char GetVertexID() const { return vertexid; } unsigned char GetVertexID() const { return vertexid; }
friend std::ostream& operator<< <T> (std::ostream& out, const HbrVertexEdit<T>& path); friend std::ostream& operator<< <T> (std::ostream& out, const HbrVertexEdit<T>& path);
// Return index of variable this edit applies to // Return index of variable this edit applies to
@ -113,48 +113,48 @@ public:
// Get the type of operation // Get the type of operation
typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; } typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; }
virtual void ApplyEditToFace(HbrFace<T>* face) { virtual void ApplyEditToFace(HbrFace<T>* face) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) { if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
// Tags the vertex as being edited; it'll figure out what to // Tags the vertex as being edited; it'll figure out what to
// when GuaranteeNeighbor is called // when GuaranteeNeighbor is called
face->GetVertex(vertexid)->SetVertexEdit(); face->GetVertex(vertexid)->SetVertexEdit();
} }
// In any event, mark the face as having a vertex edit (which // In any event, mark the face as having a vertex edit (which
// may only be applied on subfaces) // may only be applied on subfaces)
face->MarkVertexEdits(); face->MarkVertexEdits();
} }
virtual void ApplyEditToVertex(HbrFace<T>* face, HbrVertex<T>* vertex) { virtual void ApplyEditToVertex(HbrFace<T>* face, HbrVertex<T>* vertex) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth() && if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth() &&
face->GetVertex(vertexid) == vertex) { face->GetVertex(vertexid) == vertex) {
vertex->GetData().ApplyVertexEdit(*const_cast<const HbrVertexEdit<T>*>(this)); vertex->GetData().ApplyVertexEdit(*const_cast<const HbrVertexEdit<T>*>(this));
} }
} }
#ifdef PRMAN #ifdef PRMAN
virtual void ApplyToBound(struct bbox& bbox, RtMatrix *mx) { virtual void ApplyToBound(struct bbox& bbox, RtMatrix *mx) const {
if (isP) { if (isP) {
struct xyz p = *(struct xyz*)edit; struct xyz p = *(struct xyz*)edit;
if (mx) if (mx)
MxTransformByMatrix(&p, &p, *mx, 1); MxTransformByMatrix(&p, &p, *mx, 1);
if (op == HbrHierarchicalEdit<T>::Set) { if (op == HbrHierarchicalEdit<T>::Set) {
bbox.min.x = std::min(bbox.min.x, p.x); bbox.min.x = std::min(bbox.min.x, p.x);
bbox.min.y = std::min(bbox.min.y, p.y); bbox.min.y = std::min(bbox.min.y, p.y);
bbox.min.z = std::min(bbox.min.z, p.z); bbox.min.z = std::min(bbox.min.z, p.z);
bbox.max.x = std::max(bbox.max.x, p.x); bbox.max.x = std::max(bbox.max.x, p.x);
bbox.max.y = std::max(bbox.max.y, p.y); bbox.max.y = std::max(bbox.max.y, p.y);
bbox.max.z = std::max(bbox.max.z, p.z); bbox.max.z = std::max(bbox.max.z, p.z);
} else if (op == HbrHierarchicalEdit<T>::Add || } else if (op == HbrHierarchicalEdit<T>::Add ||
op == HbrHierarchicalEdit<T>::Subtract) { op == HbrHierarchicalEdit<T>::Subtract) {
bbox.min.x -= fabsf(p.x); bbox.min.x -= fabsf(p.x);
bbox.min.y -= fabsf(p.y); bbox.min.y -= fabsf(p.y);
bbox.min.z -= fabsf(p.z); bbox.min.z -= fabsf(p.z);
bbox.max.x += fabsf(p.x); bbox.max.x += fabsf(p.x);
bbox.max.y += fabsf(p.y); bbox.max.y += fabsf(p.y);
bbox.max.z += fabsf(p.z); bbox.max.z += fabsf(p.z);
} }
} }
} }
#endif #endif
@ -173,24 +173,24 @@ class HbrMovingVertexEdit : public HbrHierarchicalEdit<T> {
public: public:
HbrMovingVertexEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _vertexid, int _index, int _width, bool _isP, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit) HbrMovingVertexEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces, unsigned char _vertexid, int _index, int _width, bool _isP, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
edit = new float[width * 2]; edit = new float[width * 2];
memcpy(edit, _edit, 2 * width * sizeof(float)); memcpy(edit, _edit, 2 * width * sizeof(float));
} }
HbrMovingVertexEdit(int _faceid, int _nsubfaces, int *_subfaces, int _vertexid, int _index, int _width, bool _isP, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit) HbrMovingVertexEdit(int _faceid, int _nsubfaces, int *_subfaces, int _vertexid, int _index, int _width, bool _isP, typename HbrHierarchicalEdit<T>::Operation _op, float *_edit)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) { : HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
edit = new float[width * 2]; edit = new float[width * 2];
memcpy(edit, _edit, 2 * width * sizeof(float)); memcpy(edit, _edit, 2 * width * sizeof(float));
} }
virtual ~HbrMovingVertexEdit() { virtual ~HbrMovingVertexEdit() {
delete[] edit; delete[] edit;
} }
// Return the vertex id (the last element in the path) // Return the vertex id (the last element in the path)
unsigned char GetVertexID() const { return vertexid; } unsigned char GetVertexID() const { return vertexid; }
friend std::ostream& operator<< <T> (std::ostream& out, const HbrVertexEdit<T>& path); friend std::ostream& operator<< <T> (std::ostream& out, const HbrVertexEdit<T>& path);
// Return index of variable this edit applies to // Return index of variable this edit applies to
@ -198,60 +198,60 @@ public:
// Return width of the variable // Return width of the variable
int GetWidth() const { return width; } int GetWidth() const { return width; }
// Get the numerical value of the edit // Get the numerical value of the edit
const float* GetEdit() const { return edit; } const float* GetEdit() const { return edit; }
// Get the type of operation // Get the type of operation
typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; } typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; }
virtual void ApplyEditToFace(HbrFace<T>* face) { virtual void ApplyEditToFace(HbrFace<T>* face) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) { if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
// Tags the vertex as being edited; it'll figure out what to // Tags the vertex as being edited; it'll figure out what to
// when GuaranteeNeighbor is called // when GuaranteeNeighbor is called
face->GetVertex(vertexid)->SetVertexEdit(); face->GetVertex(vertexid)->SetVertexEdit();
} }
// In any event, mark the face as having a vertex edit (which // In any event, mark the face as having a vertex edit (which
// may only be applied on subfaces) // may only be applied on subfaces)
face->MarkVertexEdits(); face->MarkVertexEdits();
} }
virtual void ApplyEditToVertex(HbrFace<T>* face, HbrVertex<T>* vertex) { virtual void ApplyEditToVertex(HbrFace<T>* face, HbrVertex<T>* vertex) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth() && if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth() &&
face->GetVertex(vertexid) == vertex) { face->GetVertex(vertexid) == vertex) {
vertex->GetData().ApplyMovingVertexEdit(*const_cast<const HbrMovingVertexEdit<T>*>(this)); vertex->GetData().ApplyMovingVertexEdit(*const_cast<const HbrMovingVertexEdit<T>*>(this));
} }
} }
#ifdef PRMAN #ifdef PRMAN
virtual void ApplyToBound(struct bbox& bbox, RtMatrix *mx) { virtual void ApplyToBound(struct bbox& bbox, RtMatrix *mx) const {
if (isP) { if (isP) {
struct xyz p1 = *(struct xyz*)edit; struct xyz p1 = *(struct xyz*)edit;
struct xyz p2 = *(struct xyz*)&edit[3]; struct xyz p2 = *(struct xyz*)&edit[3];
if (mx) { if (mx) {
MxTransformByMatrix(&p1, &p1, *mx, 1); MxTransformByMatrix(&p1, &p1, *mx, 1);
MxTransformByMatrix(&p2, &p2, *mx, 1); MxTransformByMatrix(&p2, &p2, *mx, 1);
} }
if (op == HbrVertexEdit<T>::Set) { if (op == HbrVertexEdit<T>::Set) {
bbox.min.x = std::min(std::min(bbox.min.x, p1.x), p2.x); bbox.min.x = std::min(std::min(bbox.min.x, p1.x), p2.x);
bbox.min.y = std::min(std::min(bbox.min.y, p1.y), p2.y); bbox.min.y = std::min(std::min(bbox.min.y, p1.y), p2.y);
bbox.min.z = std::min(std::min(bbox.min.z, p1.z), p2.z); bbox.min.z = std::min(std::min(bbox.min.z, p1.z), p2.z);
bbox.max.x = std::max(std::max(bbox.max.x, p1.x), p2.x); bbox.max.x = std::max(std::max(bbox.max.x, p1.x), p2.x);
bbox.max.y = std::max(std::max(bbox.max.y, p1.y), p2.y); bbox.max.y = std::max(std::max(bbox.max.y, p1.y), p2.y);
bbox.max.z = std::max(std::max(bbox.max.z, p1.z), p2.z); bbox.max.z = std::max(std::max(bbox.max.z, p1.z), p2.z);
} else if (op == HbrVertexEdit<T>::Add || } else if (op == HbrVertexEdit<T>::Add ||
op == HbrVertexEdit<T>::Subtract) { op == HbrVertexEdit<T>::Subtract) {
float maxx = std::max(fabsf(p1.x), fabsf(p2.x)); float maxx = std::max(fabsf(p1.x), fabsf(p2.x));
float maxy = std::max(fabsf(p1.y), fabsf(p2.y)); float maxy = std::max(fabsf(p1.y), fabsf(p2.y));
float maxz = std::max(fabsf(p1.z), fabsf(p2.z)); float maxz = std::max(fabsf(p1.z), fabsf(p2.z));
bbox.min.x -= maxx; bbox.min.x -= maxx;
bbox.min.y -= maxy; bbox.min.y -= maxy;
bbox.min.z -= maxz; bbox.min.z -= maxz;
bbox.max.x += maxx; bbox.max.x += maxx;
bbox.max.y += maxy; bbox.max.y += maxy;
bbox.max.z += maxz; bbox.max.z += maxz;
} }
} }
} }
#endif #endif

View File

@ -71,7 +71,7 @@ set(SOURCE_FILES
cpuKernel.cpp cpuKernel.cpp
kernelDispatcher.cpp kernelDispatcher.cpp
mesh.cpp mesh.cpp
vertexBuffer.cpp vertexBuffer.cpp
) )
set(KERNEL_FILES set(KERNEL_FILES
@ -96,7 +96,9 @@ set(PUBLIC_HEADER_FILES
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# platform dependent tweaks # platform dependent tweaks
if(APPLE) if(APPLE)
set(PLATFORM_COMPILE_FLAGS
-fPIC
)
elseif(UNIX) elseif(UNIX)
set(PLATFORM_COMPILE_FLAGS set(PLATFORM_COMPILE_FLAGS
-fPIC -fPIC
@ -110,26 +112,31 @@ add_definitions(
) )
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
if( OPENMP_FOUND ) if( PTEX_FOUND )
add_definitions( list(APPEND SOURCE_FILES
-DOPENSUBDIV_HAS_OPENMP pTexture.cpp
${OpenMP_CXX_FLAGS}
) )
list(APPEND PUBLIC_HEADER_FILES
pTexture.h
)
include_directories( ${PTEX_INCLUDE_DIR} )
list(APPEND PLATFORM_LIBRARIES
${PTEX_LIBRARY}
)
endif()
#-------------------------------------------------------------------------------
if( OPENMP_FOUND )
if (CMAKE_COMPILER_IS_GNUCXX) if (CMAKE_COMPILER_IS_GNUCXX)
list(APPEND PLATFORM_LIBRARIES list(APPEND PLATFORM_LIBRARIES
gomp gomp
) )
endif() endif()
else()
message(STATUS
"* OpenMP was not found : support for OMP parallel compute kernels will be diabled "
"in Osd. If your compiler supports OpenMP directives, please refer to the "
"FindOpenMP.cmake shared module in your cmake installation.")
endif() endif()
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# GL code & dependencies # GL code & dependencies
# note : (GLSL compute kernels require GL 4.2, which excludes APPLE) # note : (GLSL compute kernels require GL 4.2, which excludes APPLE)
if( OPENGL_FOUND AND GLEW_FOUND AND (NOT APPLE) ) if( OPENGL_FOUND AND GLEW_FOUND AND (NOT APPLE) )
list(APPEND SOURCE_FILES list(APPEND SOURCE_FILES
glslDispatcher.cpp glslDispatcher.cpp
@ -143,19 +150,16 @@ if( OPENGL_FOUND AND GLEW_FOUND AND (NOT APPLE) )
list(APPEND PLATFORM_LIBRARIES list(APPEND PLATFORM_LIBRARIES
${OPENGL_LIBRARY} ${OPENGL_LIBRARY}
${GLEW_LIBRARY} ${GLEW_LIBRARY}
)
add_definitions(
-DOPENSUBDIV_HAS_GLSL
) )
else() else( OPENGL_FOUND AND APPLE )
message(STATUS list(APPEND PLATFORM_LIBRARIES
"* OpenGL was not found : support for GLSL parallel compute kernels will be disabled " ${OPENGL_LIBRARY}
"in Osd. If you have an OpenGL SDK installed (version 4.2 or above), please refer to " ${ILMBASE_LIBRARIES}
"the FindOpenGL.cmake shared module in your cmake installation.") )
endif() endif()
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# OpenCL code & dependencies # OpenCL code & dependencies
if ( OPENCL_FOUND ) if ( OPENCL_FOUND )
list(APPEND SOURCE_FILES list(APPEND SOURCE_FILES
clDispatcher.cpp clDispatcher.cpp
@ -168,19 +172,11 @@ if ( OPENCL_FOUND )
) )
list(APPEND PLATFORM_LIBRARIES list(APPEND PLATFORM_LIBRARIES
${OPENCL_LIBRARIES} ${OPENCL_LIBRARIES}
)
add_definitions(
-DOPENSUBDIV_HAS_OPENCL
) )
else()
message(STATUS
"* OpenCL was not found : support for OpenCL parallel compute kernels will be disabled "
"in Osd. If you have the OpenCL SDK installed, please refer to the FindOpenCL.cmake "
"in ${PROJECT_SOURCE_DIR}/cmake.")
endif() endif()
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# CUDA code & dependencies # CUDA code & dependencies
if( CUDA_FOUND ) if( CUDA_FOUND )
list(APPEND SOURCE_FILES list(APPEND SOURCE_FILES
cudaDispatcher.cpp cudaDispatcher.cpp
@ -191,17 +187,9 @@ if( CUDA_FOUND )
list(APPEND KERNEL_FILES list(APPEND KERNEL_FILES
cudaKernel.cu cudaKernel.cu
) )
add_definitions(
-DOPENSUBDIV_HAS_CUDA
)
if (UNIX) if (UNIX)
list( APPEND CUDA_NVCC_FLAGS -Xcompiler -fPIC ) list( APPEND CUDA_NVCC_FLAGS -Xcompiler -fPIC )
endif() endif()
else()
message(STATUS
"* CUDA was not found : support for CUDA parallel compute kernels will be disabled "
"in Osd. If you have the CUDA SDK installed, please refer to the FindCUDA.cmake "
"shared module in your cmake installation.")
endif() endif()
@ -220,15 +208,15 @@ foreach(kernel_file ${KERNEL_FILES})
string(REGEX REPLACE "(.*)[.].*" "\\1.inc" inc_file ${kernel_file}) string(REGEX REPLACE "(.*)[.].*" "\\1.inc" inc_file ${kernel_file})
list(APPEND INC_FILES ${inc_file}) list(APPEND INC_FILES ${inc_file})
add_custom_command( add_custom_command(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${inc_file} OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${inc_file}
COMMAND stringify ${CMAKE_CURRENT_SOURCE_DIR}/${kernel_file} COMMAND stringify ${CMAKE_CURRENT_SOURCE_DIR}/${kernel_file}
${CMAKE_CURRENT_SOURCE_DIR}/${inc_file} ${CMAKE_CURRENT_SOURCE_DIR}/${inc_file}
DEPENDS stringify ${CMAKE_CURRENT_SOURCE_DIR}/${kernel_file} DEPENDS stringify ${CMAKE_CURRENT_SOURCE_DIR}/${kernel_file}
) )
endif() endif()
endforeach() endforeach()
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
@ -236,7 +224,7 @@ source_group("Kernels" FILES ${KERNEL_FILES})
source_group("Inc" FILES ${INC_FILES}) source_group("Inc" FILES ${INC_FILES})
_add_library(osd_static STATIC _add_possibly_cuda_library(osd_static STATIC
${SOURCE_FILES} ${SOURCE_FILES}
${PRIVATE_HEADER_FILES} ${PRIVATE_HEADER_FILES}
${PUBLIC_HEADER_FILES} ${PUBLIC_HEADER_FILES}
@ -250,7 +238,7 @@ target_link_libraries(osd_static
) )
if (NOT WIN32) if (NOT WIN32)
_add_library(osd_dynamic SHARED _add_possibly_cuda_library(osd_dynamic SHARED
${SOURCE_FILES} ${SOURCE_FILES}
${PRIVATE_HEADER_FILES} ${PRIVATE_HEADER_FILES}
${PUBLIC_HEADER_FILES} ${PUBLIC_HEADER_FILES}

View File

@ -61,6 +61,7 @@
#if defined(_WIN32) #if defined(_WIN32)
#include <windows.h> #include <windows.h>
#elif defined(__APPLE__) #elif defined(__APPLE__)
#include <OpenGL/OpenGL.h>
#include <OpenCL/opencl.h> #include <OpenCL/opencl.h>
#else #else
#include <GL/glx.h> #include <GL/glx.h>
@ -85,9 +86,9 @@ static const char *clSource =
std::vector<OsdClKernelDispatcher::ClKernel> OsdClKernelDispatcher::kernelRegistry; std::vector<OsdClKernelDispatcher::ClKernel> OsdClKernelDispatcher::kernelRegistry;
// XXX: context and queue should be moved to client code
cl_context OsdClKernelDispatcher::_clContext = NULL; cl_context OsdClKernelDispatcher::_clContext = NULL;
cl_command_queue OsdClKernelDispatcher::_clQueue = NULL; cl_command_queue OsdClKernelDispatcher::_clQueue = NULL;
cl_device_id OsdClKernelDispatcher::_clDevice=NULL;
OsdClVertexBuffer::OsdClVertexBuffer(int numElements, int numVertices, OsdClVertexBuffer::OsdClVertexBuffer(int numElements, int numVertices,
cl_context clContext, cl_command_queue clQueue) : cl_context clContext, cl_command_queue clQueue) :
@ -143,7 +144,7 @@ OsdClKernelDispatcher::DeviceTable::Copy(cl_context context, int size, const voi
clReleaseMemObject(devicePtr); clReleaseMemObject(devicePtr);
devicePtr = clCreateBuffer(context, CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR, size, devicePtr = clCreateBuffer(context, CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR, size,
const_cast<void*>(table), &ciErrNum); const_cast<void*>(table), &ciErrNum);
CL_CHECK_ERROR(ciErrNum, "Table copy %p\n", table); CL_CHECK_ERROR(ciErrNum, "Table copy %p\n", table);
} }
} }
@ -229,6 +230,52 @@ OsdClKernelDispatcher::Synchronize() {
clFinish(_clQueue); clFinish(_clQueue);
} }
void
OsdClKernelDispatcher::ApplyBilinearFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset,
int level, int start, int end, void * data) const {
ApplyCatmarkFaceVerticesKernel(mesh, offset, level, start, end, data);
}
void
OsdClKernelDispatcher::ApplyBilinearEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset,
int level, int start, int end, void * data) const {
cl_int ciErrNum;
size_t globalWorkSize[1] = { end-start };
cl_kernel kernel = _clKernel->GetBilinearEdgeKernel();
clSetKernelArg(kernel, 0, sizeof(cl_mem), GetVertexBuffer());
clSetKernelArg(kernel, 1, sizeof(cl_mem), GetVaryingBuffer());
clSetKernelArg(kernel, 2, sizeof(cl_mem), &_tables[E_IT].devicePtr);
clSetKernelArg(kernel, 3, sizeof(int), &_tableOffsets[E_IT][level-1]);
clSetKernelArg(kernel, 4, sizeof(int), &offset);
clSetKernelArg(kernel, 5, sizeof(int), &start);
clSetKernelArg(kernel, 6, sizeof(int), &end);
ciErrNum = clEnqueueNDRangeKernel(_clQueue, kernel, 1, NULL, globalWorkSize, NULL, 0, NULL, NULL);
CL_CHECK_ERROR(ciErrNum, "bilinear edge kernel %d\n", ciErrNum);
}
void
OsdClKernelDispatcher::ApplyBilinearVertexVerticesKernel(FarMesh<OsdVertex> * mesh, int offset,
int level, int start, int end, void * data) const {
cl_int ciErrNum;
size_t globalWorkSize[1] = { end-start };
cl_kernel kernel = _clKernel->GetBilinearVertexKernel();
clSetKernelArg(kernel, 0, sizeof(cl_mem), GetVertexBuffer());
clSetKernelArg(kernel, 1, sizeof(cl_mem), GetVaryingBuffer());
clSetKernelArg(kernel, 2, sizeof(cl_mem), &_tables[V_ITa].devicePtr);
clSetKernelArg(kernel, 3, sizeof(int), &_tableOffsets[V_ITa][level-1]);
clSetKernelArg(kernel, 4, sizeof(int), (void*)&offset);
clSetKernelArg(kernel, 5, sizeof(int), (void*)&start);
clSetKernelArg(kernel, 6, sizeof(int), (void*)&end);
ciErrNum = clEnqueueNDRangeKernel(_clQueue, kernel, 1, NULL, globalWorkSize, NULL, 0, NULL, NULL);
CL_CHECK_ERROR(ciErrNum, "bilinear vertex kernel 1 %d\n", ciErrNum);
}
void void
OsdClKernelDispatcher::ApplyCatmarkFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, OsdClKernelDispatcher::ApplyCatmarkFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset,
int level, int start, int end, void * data) const { int level, int start, int end, void * data) const {
@ -252,7 +299,7 @@ OsdClKernelDispatcher::ApplyCatmarkFaceVerticesKernel(FarMesh<OsdVertex> * mesh,
} }
void void
OsdClKernelDispatcher::ApplyCatmarkEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, OsdClKernelDispatcher::ApplyCatmarkEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset,
int level, int start, int end, void * data) const { int level, int start, int end, void * data) const {
cl_int ciErrNum; cl_int ciErrNum;
@ -268,7 +315,7 @@ OsdClKernelDispatcher::ApplyCatmarkEdgeVerticesKernel(FarMesh<OsdVertex> * mesh,
clSetKernelArg(kernel, 6, sizeof(int), &offset); clSetKernelArg(kernel, 6, sizeof(int), &offset);
clSetKernelArg(kernel, 7, sizeof(int), &start); clSetKernelArg(kernel, 7, sizeof(int), &start);
clSetKernelArg(kernel, 8, sizeof(int), &end); clSetKernelArg(kernel, 8, sizeof(int), &end);
ciErrNum = clEnqueueNDRangeKernel(_clQueue, kernel, 1, NULL, globalWorkSize, NULL, 0, NULL, NULL); ciErrNum = clEnqueueNDRangeKernel(_clQueue, kernel, 1, NULL, globalWorkSize, NULL, 0, NULL, NULL);
CL_CHECK_ERROR(ciErrNum, "edge kernel %d\n", ciErrNum); CL_CHECK_ERROR(ciErrNum, "edge kernel %d\n", ciErrNum);
} }
@ -388,7 +435,7 @@ OsdClKernelDispatcher::ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mesh,
} }
// XXX: initCL should be removed from libosd // XXX: initCL should be removed from libosd
void void
OsdClKernelDispatcher::initCL() { OsdClKernelDispatcher::initCL() {
cl_int ciErrNum; cl_int ciErrNum;
@ -415,9 +462,8 @@ OsdClKernelDispatcher::initCL() {
} }
} }
// ------------- // -------------
cl_device_id cdDevice; clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 1, &_clDevice, NULL);
clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 1, &cdDevice, NULL);
#if defined(_WIN32) #if defined(_WIN32)
cl_context_properties props[] = { cl_context_properties props[] = {
CL_GL_CONTEXT_KHR, (cl_context_properties)wglGetCurrentContext(), CL_GL_CONTEXT_KHR, (cl_context_properties)wglGetCurrentContext(),
@ -442,10 +488,10 @@ OsdClKernelDispatcher::initCL() {
#endif #endif
// XXX context creation should be moved to client code // XXX context creation should be moved to client code
_clContext = clCreateContext(props, 1, &cdDevice, NULL, NULL, &ciErrNum); _clContext = clCreateContext(props, 1, &_clDevice, NULL, NULL, &ciErrNum);
CL_CHECK_ERROR(ciErrNum, "clCreateContext\n"); CL_CHECK_ERROR(ciErrNum, "clCreateContext\n");
_clQueue = clCreateCommandQueue(_clContext, cdDevice, 0, &ciErrNum); _clQueue = clCreateCommandQueue(_clContext, _clDevice, 0, &ciErrNum);
CL_CHECK_ERROR(ciErrNum, "clCreateCommandQueue\n"); CL_CHECK_ERROR(ciErrNum, "clCreateCommandQueue\n");
} }
@ -460,6 +506,8 @@ OsdClKernelDispatcher::uninitCL() {
// ------------------------------------------------------------------ // ------------------------------------------------------------------
OsdClKernelDispatcher::ClKernel::ClKernel() : OsdClKernelDispatcher::ClKernel::ClKernel() :
_clBilinearEdge(NULL),
_clBilinearVertex(NULL),
_clCatmarkFace(NULL), _clCatmarkFace(NULL),
_clCatmarkEdge(NULL), _clCatmarkEdge(NULL),
_clCatmarkVertexA(NULL), _clCatmarkVertexA(NULL),
@ -472,6 +520,11 @@ OsdClKernelDispatcher::ClKernel::ClKernel() :
OsdClKernelDispatcher::ClKernel::~ClKernel() { OsdClKernelDispatcher::ClKernel::~ClKernel() {
if (_clBilinearEdge)
clReleaseKernel(_clBilinearEdge);
if (_clBilinearVertex)
clReleaseKernel(_clBilinearVertex);
if (_clCatmarkFace) if (_clCatmarkFace)
clReleaseKernel(_clCatmarkFace); clReleaseKernel(_clCatmarkFace);
if (_clCatmarkEdge) if (_clCatmarkEdge)
@ -491,6 +544,15 @@ OsdClKernelDispatcher::ClKernel::~ClKernel() {
if (_clProgram) clReleaseProgram(_clProgram); if (_clProgram) clReleaseProgram(_clProgram);
} }
static cl_kernel buildKernel(cl_program prog, const char * name) {
cl_int ciErr;
cl_kernel k = clCreateKernel(prog, name, &ciErr);
if (ciErr!=CL_SUCCESS)
printf("error building kernel '%s'\n", name);
return k;
}
bool bool
OsdClKernelDispatcher::ClKernel::Compile(cl_context clContext, int numVertexElements, int numVaryingElements) { OsdClKernelDispatcher::ClKernel::Compile(cl_context clContext, int numVertexElements, int numVaryingElements) {
@ -511,29 +573,23 @@ OsdClKernelDispatcher::ClKernel::Compile(cl_context clContext, int numVertexElem
ciErrNum = clBuildProgram(_clProgram, 0, NULL, NULL, NULL, NULL); ciErrNum = clBuildProgram(_clProgram, 0, NULL, NULL, NULL, NULL);
if (ciErrNum != CL_SUCCESS) { if (ciErrNum != CL_SUCCESS) {
OSD_ERROR("ERROR in clBuildProgram %d\n", ciErrNum); OSD_ERROR("ERROR in clBuildProgram %d\n", ciErrNum);
//char cBuildLog[10240]; char cBuildLog[10240];
//clGetProgramBuildInfo(_clProgram, cdDevice, CL_PROGRAM_BUILD_LOG, clGetProgramBuildInfo(_clProgram, _clDevice, CL_PROGRAM_BUILD_LOG,
// sizeof(cBuildLog), cBuildLog, NULL); sizeof(cBuildLog), cBuildLog, NULL);
//OSD_ERROR(cBuildLog); OSD_ERROR(cBuildLog);
return false; return false;
} }
// ------- // -------
_clBilinearEdge = buildKernel(_clProgram, "computeBilinearEdge");
_clCatmarkFace = clCreateKernel(_clProgram, "computeFace", &ciErrNum); _clBilinearVertex = buildKernel(_clProgram, "computeBilinearVertex");
CL_CHECK_ERROR(ciErrNum, "clCreateKernel face\n"); _clCatmarkFace = buildKernel(_clProgram, "computeFace");
_clCatmarkEdge = clCreateKernel(_clProgram, "computeEdge", &ciErrNum); _clCatmarkEdge = buildKernel(_clProgram, "computeEdge");
CL_CHECK_ERROR(ciErrNum, "clCreateKernel edge\n"); _clCatmarkVertexA = buildKernel(_clProgram, "computeVertexA");
_clCatmarkVertexA = clCreateKernel(_clProgram, "computeVertexA", &ciErrNum); _clCatmarkVertexB = buildKernel(_clProgram, "computeVertexB");
CL_CHECK_ERROR(ciErrNum, "clCreateKernel vertex a\n"); _clLoopEdge = buildKernel(_clProgram, "computeEdge");
_clCatmarkVertexB = clCreateKernel(_clProgram, "computeVertexB", &ciErrNum); _clLoopVertexA = buildKernel(_clProgram, "computeVertexA");
CL_CHECK_ERROR(ciErrNum, "clCreateKernel vertex b\n"); _clLoopVertexB = buildKernel(_clProgram, "computeLoopVertexB");
_clLoopEdge = clCreateKernel(_clProgram, "computeEdge", &ciErrNum);
CL_CHECK_ERROR(ciErrNum, "clCreateKernel edge\n");
_clLoopVertexA = clCreateKernel(_clProgram, "computeVertexA", &ciErrNum);
CL_CHECK_ERROR(ciErrNum, "clCreateKernel vertex a\n");
_clLoopVertexB = clCreateKernel(_clProgram, "computeLoopVertexB", &ciErrNum);
CL_CHECK_ERROR(ciErrNum, "clCreateKernel vertex b\n");
return true; return true;
} }

View File

@ -93,24 +93,38 @@ public:
virtual ~OsdClKernelDispatcher(); virtual ~OsdClKernelDispatcher();
virtual void ApplyBilinearFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyBilinearEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyBilinearVertexVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyCatmarkFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyCatmarkEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyCatmarkVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const; virtual void ApplyCatmarkVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const;
virtual void ApplyLoopEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyLoopEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyLoopVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyLoopVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const; 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 CopyTable(int tableIndex, size_t size, const void *ptr); virtual void CopyTable(int tableIndex, size_t size, const void *ptr);
virtual void AllocateEditTables(int n) {}
virtual void UpdateEditTable(int tableIndex, const FarTable<unsigned int> &offsets, const FarTable<float> &values,
int operation, int primVarOffset, int primVarWidth) {}
virtual void OnKernelLaunch() {} virtual void OnKernelLaunch() {}
virtual void OnKernelFinish() {} virtual void OnKernelFinish() {}
@ -118,7 +132,7 @@ public:
virtual OsdVertexBuffer *InitializeVertexBuffer(int numElements, int count); virtual OsdVertexBuffer *InitializeVertexBuffer(int numElements, int count);
virtual void BindVertexBuffer(OsdVertexBuffer *vertex, OsdVertexBuffer *varying); virtual void BindVertexBuffer(OsdVertexBuffer *vertex, OsdVertexBuffer *varying);
virtual void UnbindVertexBuffer(); virtual void UnbindVertexBuffer();
virtual void Synchronize(); virtual void Synchronize();
@ -139,13 +153,23 @@ protected:
bool Compile(cl_context clContext, int numVertexElements, int numVaryingElements); bool Compile(cl_context clContext, int numVertexElements, int numVaryingElements);
cl_kernel GetCatmarkFaceKernel() const { return _clCatmarkFace; } cl_kernel GetBilinearEdgeKernel() const { return _clBilinearEdge; }
cl_kernel GetCatmarkEdgeKernel() const { return _clCatmarkEdge; }
cl_kernel GetBilinearVertexKernel() const { return _clBilinearVertex; }
cl_kernel GetCatmarkFaceKernel() const { return _clCatmarkFace; }
cl_kernel GetCatmarkEdgeKernel() const { return _clCatmarkEdge; }
cl_kernel GetCatmarkVertexKernelA() const { return _clCatmarkVertexA; } cl_kernel GetCatmarkVertexKernelA() const { return _clCatmarkVertexA; }
cl_kernel GetCatmarkVertexKernelB() const { return _clCatmarkVertexB; } cl_kernel GetCatmarkVertexKernelB() const { return _clCatmarkVertexB; }
cl_kernel GetLoopEdgeKernel() const { return _clLoopEdge; }
cl_kernel GetLoopVertexKernelA() const { return _clLoopVertexA; } cl_kernel GetLoopEdgeKernel() const { return _clLoopEdge; }
cl_kernel GetLoopVertexKernelB() const { return _clLoopVertexB; }
cl_kernel GetLoopVertexKernelA() const { return _clLoopVertexA; }
cl_kernel GetLoopVertexKernelB() const { return _clLoopVertexB; }
struct Match { struct Match {
Match(int numVertexElements, int numVaryingElements) : Match(int numVertexElements, int numVaryingElements) :
@ -161,12 +185,22 @@ protected:
protected: protected:
cl_program _clProgram; cl_program _clProgram;
cl_kernel _clCatmarkFace, _clCatmarkEdge, _clCatmarkVertexA, _clCatmarkVertexB;
cl_kernel _clLoopEdge, _clLoopVertexA, _clLoopVertexB; cl_kernel _clBilinearEdge,
int _numVertexElements, _numVaryingElements; _clBilinearVertex,
_clCatmarkFace,
_clCatmarkEdge,
_clCatmarkVertexA,
_clCatmarkVertexB,
_clLoopEdge,
_clLoopVertexA,
_clLoopVertexB;
int _numVertexElements,
_numVaryingElements;
}; };
struct DeviceTable struct DeviceTable
{ {
DeviceTable() : devicePtr(NULL) {} DeviceTable() : devicePtr(NULL) {}
~DeviceTable(); ~DeviceTable();
@ -200,8 +234,9 @@ protected:
ClKernel * _clKernel; ClKernel * _clKernel;
// XXX: context and queue should be moved to client code // XXX: context and queue should be moved to client code
static cl_context _clContext; static cl_context _clContext;
static cl_command_queue _clQueue; static cl_command_queue _clQueue;
static cl_device_id _clDevice;
// static shader registry (XXX tentative..) // static shader registry (XXX tentative..)
static std::vector<ClKernel> kernelRegistry; static std::vector<ClKernel> kernelRegistry;

View File

@ -92,6 +92,60 @@ __global void addVaryingWithWeight(struct Varying *dst, __global struct Varying
} }
} }
__kernel void computeBilinearEdge(__global struct Vertex *vertex,
__global struct Varying *varying,
__global int *E_IT,
int ofs_E_IT,
int offset, int start, int end) {
E_IT += ofs_E_IT;
int i = start + get_global_id(0);
int eidx0 = E_IT[2*i+0];
int eidx1 = E_IT[2*i+1];
struct Vertex dst;
struct Varying dstVarying;
clearVertex(&dst);
clearVarying(&dstVarying);
addWithWeight(&dst, &vertex[eidx0], 0.5f);
addWithWeight(&dst, &vertex[eidx1], 0.5f);
vertex[i+offset] = dst;
if (varying) {
addVaryingWithWeight(&dstVarying, &varying[eidx0], 0.5f);
addVaryingWithWeight(&dstVarying, &varying[eidx1], 0.5f);
varying[i+offset] = dstVarying;
}
}
__kernel void computeBilinearVertex(__global struct Vertex *vertex,
__global struct Varying *varying,
__global int *V_ITa,
int ofs_V_ITa,
int offset, int start, int end) {
V_ITa += ofs_V_ITa;
int i = start + get_global_id(0);
int p = V_ITa[i];
struct Vertex dst;
clearVertex(&dst);
addWithWeight(&dst, &vertex[p], 1.0f);
vertex[i+offset] = dst;
if (varying) {
struct Varying dstVarying;
clearVarying(&dstVarying);
addVaryingWithWeight(&dstVarying, &varying[p], 1.0f);
varying[i+offset] = dstVarying;
}
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
__kernel void computeFace(__global struct Vertex *vertex, __kernel void computeFace(__global struct Vertex *vertex,
@ -107,9 +161,9 @@ __kernel void computeFace(__global struct Vertex *vertex,
int i = start + get_global_id(0); int i = start + get_global_id(0);
int h = F_ITa[2*i]; int h = F_ITa[2*i];
int n = F_ITa[2*i+1]; int n = F_ITa[2*i+1];
float weight = 1.0f/n; float weight = 1.0f/n;
struct Vertex dst; struct Vertex dst;
struct Varying dstVarying; struct Varying dstVarying;
clearVertex(&dst); clearVertex(&dst);
@ -136,11 +190,11 @@ __kernel void computeEdge(__global struct Vertex *vertex,
int i = start + get_global_id(0); int i = start + get_global_id(0);
int eidx0 = E_IT[4*i+0]; int eidx0 = E_IT[4*i+0];
int eidx1 = E_IT[4*i+1]; int eidx1 = E_IT[4*i+1];
int eidx2 = E_IT[4*i+2]; int eidx2 = E_IT[4*i+2];
int eidx3 = E_IT[4*i+3]; int eidx3 = E_IT[4*i+3];
float vertWeight = E_W[i*2+0]; float vertWeight = E_W[i*2+0];
// Fully sharp edge : vertWeight = 0.5f; // Fully sharp edge : vertWeight = 0.5f;
struct Vertex dst; struct Vertex dst;
struct Varying dstVarying; struct Varying dstVarying;
@ -149,10 +203,10 @@ __kernel void computeEdge(__global struct Vertex *vertex,
addWithWeight(&dst, &vertex[eidx0], vertWeight); addWithWeight(&dst, &vertex[eidx0], vertWeight);
addWithWeight(&dst, &vertex[eidx1], vertWeight); addWithWeight(&dst, &vertex[eidx1], vertWeight);
if (eidx2 > -1) { if (eidx2 > -1) {
float faceWeight = E_W[i*2+1]; float faceWeight = E_W[i*2+1];
addWithWeight(&dst, &vertex[eidx2], faceWeight); addWithWeight(&dst, &vertex[eidx2], faceWeight);
addWithWeight(&dst, &vertex[eidx3], faceWeight); addWithWeight(&dst, &vertex[eidx3], faceWeight);
} }
@ -180,15 +234,15 @@ __kernel void computeVertexA(__global struct Vertex *vertex,
int p = V_ITa[5*i+2]; int p = V_ITa[5*i+2];
int eidx0 = V_ITa[5*i+3]; int eidx0 = V_ITa[5*i+3];
int eidx1 = V_ITa[5*i+4]; int eidx1 = V_ITa[5*i+4];
float weight = (pass==1) ? V_W[i] : 1.0f - V_W[i]; float weight = (pass==1) ? V_W[i] : 1.0f - V_W[i];
// In the case of fractional weight, the weight must be inverted since // In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the // the value is shared with the k_Smooth kernel (statistically the
// k_Smooth kernel runs much more often than this one) // k_Smooth kernel runs much more often than this one)
if (weight>0.0f && weight<1.0f && n > 0) if (weight>0.0f && weight<1.0f && n > 0)
weight=1.0f-weight; weight=1.0f-weight;
struct Vertex dst; struct Vertex dst;
if (not pass) if (not pass)
clearVertex(&dst); clearVertex(&dst);
@ -227,7 +281,7 @@ __kernel void computeVertexB(__global struct Vertex *vertex,
int h = V_ITa[5*i]; int h = V_ITa[5*i];
int n = V_ITa[5*i+1]; int n = V_ITa[5*i+1];
int p = V_ITa[5*i+2]; int p = V_ITa[5*i+2];
float weight = V_W[i]; float weight = V_W[i];
float wp = 1.0f/(float)(n*n); float wp = 1.0f/(float)(n*n);
float wv = (n-2.0f) * n * wp; float wv = (n-2.0f) * n * wp;
@ -236,7 +290,7 @@ __kernel void computeVertexB(__global struct Vertex *vertex,
clearVertex(&dst); clearVertex(&dst);
addWithWeight(&dst, &vertex[p], weight * wv); addWithWeight(&dst, &vertex[p], weight * wv);
for (int j = 0; j < n; ++j) { for (int j = 0; j < n; ++j) {
addWithWeight(&dst, &vertex[V_IT[h+j*2]], weight * wp); addWithWeight(&dst, &vertex[V_IT[h+j*2]], weight * wp);
addWithWeight(&dst, &vertex[V_IT[h+j*2+1]], weight * wp); addWithWeight(&dst, &vertex[V_IT[h+j*2+1]], weight * wp);
@ -267,7 +321,7 @@ __kernel void computeLoopVertexB(__global struct Vertex *vertex,
int h = V_ITa[5*i]; int h = V_ITa[5*i];
int n = V_ITa[5*i+1]; int n = V_ITa[5*i+1];
int p = V_ITa[5*i+2]; int p = V_ITa[5*i+2];
float weight = V_W[i]; float weight = V_W[i];
float wp = 1.0f/(float)(n); float wp = 1.0f/(float)(n);
float beta = 0.25f * cos((float)(M_PI) * 2.0f * wp) + 0.375f; float beta = 0.25f * cos((float)(M_PI) * 2.0f * wp) + 0.375f;
@ -277,7 +331,7 @@ __kernel void computeLoopVertexB(__global struct Vertex *vertex,
struct Vertex dst; struct Vertex dst;
clearVertex(&dst); clearVertex(&dst);
addWithWeight(&dst, &vertex[p], weight * (1.0f - (beta * n))); addWithWeight(&dst, &vertex[p], weight * (1.0f - (beta * n)));
for (int j = 0; j < n; ++j) { for (int j = 0; j < n; ++j) {
addWithWeight(&dst, &vertex[V_IT[h+j]], weight * beta); addWithWeight(&dst, &vertex[V_IT[h+j]], weight * beta);
} }

View File

@ -63,25 +63,25 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef OPENSUBDIV_HAS_OPENMP #ifdef OPENSUBDIV_HAS_OPENMP
#include <omp.h> #include <omp.h>
#endif #endif
namespace OpenSubdiv { namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION { namespace OPENSUBDIV_VERSION {
OsdCpuKernelDispatcher::SubdivisionTable::~SubdivisionTable() { OsdCpuKernelDispatcher::Table::~Table() {
if (ptr) if (ptr)
free(ptr); free(ptr);
} }
void void
OsdCpuKernelDispatcher::SubdivisionTable::Copy( int size, const void *table ) { OsdCpuKernelDispatcher::Table::Copy( int size, const void *table ) {
if (size > 0) { if (size > 0) {
if (ptr) if (ptr)
free(ptr); free(ptr);
ptr = malloc(size); ptr = malloc(size);
memcpy(ptr, table, size); memcpy(ptr, table, size);
} }
@ -98,13 +98,13 @@ OsdCpuKernelDispatcher::~OsdCpuKernelDispatcher() {
delete _vdesc; delete _vdesc;
} }
static OsdCpuKernelDispatcher::OsdKernelDispatcher * static OsdCpuKernelDispatcher::OsdKernelDispatcher *
Create(int levels) { Create(int levels) {
return new OsdCpuKernelDispatcher(levels); return new OsdCpuKernelDispatcher(levels);
} }
#ifdef OPENSUBDIV_HAS_OPENMP #ifdef OPENSUBDIV_HAS_OPENMP
static OsdCpuKernelDispatcher::OsdKernelDispatcher * static OsdCpuKernelDispatcher::OsdKernelDispatcher *
CreateOmp(int levels) { CreateOmp(int levels) {
return new OsdCpuKernelDispatcher(levels, omp_get_num_procs()); return new OsdCpuKernelDispatcher(levels, omp_get_num_procs());
} }
@ -114,15 +114,15 @@ void
OsdCpuKernelDispatcher::Register() { OsdCpuKernelDispatcher::Register() {
Factory::GetInstance().Register(Create, kCPU); Factory::GetInstance().Register(Create, kCPU);
#ifdef OPENSUBDIV_HAS_OPENMP #ifdef OPENSUBDIV_HAS_OPENMP
Factory::GetInstance().Register(CreateOmp, kOPENMP); Factory::GetInstance().Register(CreateOmp, kOPENMP);
#endif #endif
} }
void void
OsdCpuKernelDispatcher::OnKernelLaunch() { OsdCpuKernelDispatcher::OnKernelLaunch() {
#ifdef OPENSUBDIV_HAS_OPENMP #ifdef OPENSUBDIV_HAS_OPENMP
omp_set_num_threads(_numOmpThreads); omp_set_num_threads(_numOmpThreads);
#endif #endif
} }
@ -130,7 +130,34 @@ OsdCpuKernelDispatcher::OnKernelLaunch() {
void void
OsdCpuKernelDispatcher::CopyTable(int tableIndex, size_t size, const void *ptr) { OsdCpuKernelDispatcher::CopyTable(int tableIndex, size_t size, const void *ptr) {
_tables[tableIndex].Copy(size, ptr); _tables[tableIndex].Copy((int)size, ptr);
}
void
OsdCpuKernelDispatcher::AllocateEditTables(int n) {
_editTables.resize(n*2);
_edits.resize(n);
}
void
OsdCpuKernelDispatcher::UpdateEditTable(int tableIndex, const FarTable<unsigned int> &offsets, const FarTable<float> &values,
int operation, int primVarOffset, int primVarWidth) {
_editTables[tableIndex*2+0].Copy(offsets.GetMemoryUsed(), offsets[0]);
_editTables[tableIndex*2+1].Copy(values.GetMemoryUsed(), values[0]);
_edits[tableIndex].offsetOffsets.resize(_maxLevel);
_edits[tableIndex].valueOffsets.resize(_maxLevel);
_edits[tableIndex].numEdits.resize(_maxLevel);
for (int i = 0; i < _maxLevel; ++i) {
_edits[tableIndex].offsetOffsets[i] = (int)(offsets[i] - offsets[0]);
_edits[tableIndex].valueOffsets[i] = (int)(values[i] - values[0]);
_edits[tableIndex].numEdits[i] = offsets.GetNumElements(i);
}
_edits[tableIndex].operation = operation;
_edits[tableIndex].primVarOffset = primVarOffset;
_edits[tableIndex].primVarWidth = primVarWidth;
} }
OsdVertexBuffer * OsdVertexBuffer *
@ -142,14 +169,14 @@ OsdCpuKernelDispatcher::InitializeVertexBuffer(int numElements, int numVertices)
void void
OsdCpuKernelDispatcher::BindVertexBuffer(OsdVertexBuffer *vertex, OsdVertexBuffer *varying) { OsdCpuKernelDispatcher::BindVertexBuffer(OsdVertexBuffer *vertex, OsdVertexBuffer *varying) {
if (vertex) if (vertex)
_currentVertexBuffer = dynamic_cast<OsdCpuVertexBuffer *>(vertex); _currentVertexBuffer = dynamic_cast<OsdCpuVertexBuffer *>(vertex);
else else
_currentVertexBuffer = NULL; _currentVertexBuffer = NULL;
if (varying) if (varying)
_currentVaryingBuffer = dynamic_cast<OsdCpuVertexBuffer *>(varying); _currentVaryingBuffer = dynamic_cast<OsdCpuVertexBuffer *>(varying);
else else
_currentVaryingBuffer = NULL; _currentVaryingBuffer = NULL;
_vdesc = new VertexDescriptor(_currentVertexBuffer ? _currentVertexBuffer->GetNumElements() : 0, _vdesc = new VertexDescriptor(_currentVertexBuffer ? _currentVertexBuffer->GetNumElements() : 0,
@ -172,7 +199,7 @@ OsdCpuKernelDispatcher::Synchronize() { }
void void
OsdCpuKernelDispatcher::ApplyBilinearFaceVerticesKernel( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { OsdCpuKernelDispatcher::ApplyBilinearFaceVerticesKernel( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
computeFace(_vdesc, GetVertexBuffer(), GetVaryingBuffer(), computeFace(_vdesc, GetVertexBuffer(), GetVaryingBuffer(),
(int*)_tables[F_IT].ptr + _tableOffsets[F_IT][level-1], (int*)_tables[F_IT].ptr + _tableOffsets[F_IT][level-1],
(int*)_tables[F_ITa].ptr + _tableOffsets[F_ITa][level-1], (int*)_tables[F_ITa].ptr + _tableOffsets[F_ITa][level-1],
@ -181,16 +208,16 @@ OsdCpuKernelDispatcher::ApplyBilinearFaceVerticesKernel( FarMesh<OsdVertex> * me
void void
OsdCpuKernelDispatcher::ApplyBilinearEdgeVerticesKernel( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { OsdCpuKernelDispatcher::ApplyBilinearEdgeVerticesKernel( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
computeBilinearEdge(_vdesc, GetVertexBuffer(), GetVaryingBuffer(), computeBilinearEdge(_vdesc, GetVertexBuffer(), GetVaryingBuffer(),
(int*)_tables[E_IT].ptr + _tableOffsets[E_IT][level-1], (int*)_tables[E_IT].ptr + _tableOffsets[E_IT][level-1],
offset, offset,
start, end); start, end);
} }
void void
OsdCpuKernelDispatcher::ApplyBilinearVertexVerticesKernel( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { OsdCpuKernelDispatcher::ApplyBilinearVertexVerticesKernel( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
computeBilinearVertex(_vdesc, GetVertexBuffer(), GetVaryingBuffer(), computeBilinearVertex(_vdesc, GetVertexBuffer(), GetVaryingBuffer(),
(int*)_tables[V_ITa].ptr + _tableOffsets[V_ITa][level-1], (int*)_tables[V_ITa].ptr + _tableOffsets[V_ITa][level-1],
offset, start, end); offset, start, end);
@ -198,7 +225,7 @@ OsdCpuKernelDispatcher::ApplyBilinearVertexVerticesKernel( FarMesh<OsdVertex> *
void void
OsdCpuKernelDispatcher::ApplyCatmarkFaceVerticesKernel( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { OsdCpuKernelDispatcher::ApplyCatmarkFaceVerticesKernel( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
computeFace(_vdesc, GetVertexBuffer(), GetVaryingBuffer(), computeFace(_vdesc, GetVertexBuffer(), GetVaryingBuffer(),
(int*)_tables[F_IT].ptr + _tableOffsets[F_IT][level-1], (int*)_tables[F_IT].ptr + _tableOffsets[F_IT][level-1],
(int*)_tables[F_ITa].ptr + _tableOffsets[F_ITa][level-1], (int*)_tables[F_ITa].ptr + _tableOffsets[F_ITa][level-1],
@ -207,17 +234,17 @@ OsdCpuKernelDispatcher::ApplyCatmarkFaceVerticesKernel( FarMesh<OsdVertex> * mes
void void
OsdCpuKernelDispatcher::ApplyCatmarkEdgeVerticesKernel( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { OsdCpuKernelDispatcher::ApplyCatmarkEdgeVerticesKernel( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
computeEdge(_vdesc, GetVertexBuffer(), GetVaryingBuffer(), computeEdge(_vdesc, GetVertexBuffer(), GetVaryingBuffer(),
(int*)_tables[E_IT].ptr + _tableOffsets[E_IT][level-1], (int*)_tables[E_IT].ptr + _tableOffsets[E_IT][level-1],
(float*)_tables[E_W].ptr + _tableOffsets[E_W][level-1], (float*)_tables[E_W].ptr + _tableOffsets[E_W][level-1],
offset, offset,
start, end); start, end);
} }
void void
OsdCpuKernelDispatcher::ApplyCatmarkVertexVerticesKernelB( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { OsdCpuKernelDispatcher::ApplyCatmarkVertexVerticesKernelB( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
computeVertexB(_vdesc, GetVertexBuffer(), GetVaryingBuffer(), computeVertexB(_vdesc, GetVertexBuffer(), GetVaryingBuffer(),
(int*)_tables[V_ITa].ptr + _tableOffsets[V_ITa][level-1], (int*)_tables[V_ITa].ptr + _tableOffsets[V_ITa][level-1],
(int*)_tables[V_IT].ptr + _tableOffsets[V_IT][level-1], (int*)_tables[V_IT].ptr + _tableOffsets[V_IT][level-1],
@ -227,7 +254,7 @@ OsdCpuKernelDispatcher::ApplyCatmarkVertexVerticesKernelB( FarMesh<OsdVertex> *
void void
OsdCpuKernelDispatcher::ApplyCatmarkVertexVerticesKernelA( FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const { OsdCpuKernelDispatcher::ApplyCatmarkVertexVerticesKernelA( FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const {
computeVertexA(_vdesc, GetVertexBuffer(), GetVaryingBuffer(), computeVertexA(_vdesc, GetVertexBuffer(), GetVaryingBuffer(),
(int*)_tables[V_ITa].ptr + _tableOffsets[V_ITa][level-1], (int*)_tables[V_ITa].ptr + _tableOffsets[V_ITa][level-1],
(float*)_tables[V_W].ptr + _tableOffsets[V_W][level-1], (float*)_tables[V_W].ptr + _tableOffsets[V_W][level-1],
@ -236,17 +263,17 @@ OsdCpuKernelDispatcher::ApplyCatmarkVertexVerticesKernelA( FarMesh<OsdVertex> *
void void
OsdCpuKernelDispatcher::ApplyLoopEdgeVerticesKernel( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { OsdCpuKernelDispatcher::ApplyLoopEdgeVerticesKernel( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
computeEdge(_vdesc, GetVertexBuffer(), GetVaryingBuffer(), computeEdge(_vdesc, GetVertexBuffer(), GetVaryingBuffer(),
(int*)_tables[E_IT].ptr + _tableOffsets[E_IT][level-1], (int*)_tables[E_IT].ptr + _tableOffsets[E_IT][level-1],
(float*)_tables[E_W].ptr + _tableOffsets[E_W][level-1], (float*)_tables[E_W].ptr + _tableOffsets[E_W][level-1],
offset, offset,
start, end); start, end);
} }
void void
OsdCpuKernelDispatcher::ApplyLoopVertexVerticesKernelB( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { OsdCpuKernelDispatcher::ApplyLoopVertexVerticesKernelB( FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
computeLoopVertexB(_vdesc, GetVertexBuffer(), GetVaryingBuffer(), computeLoopVertexB(_vdesc, GetVertexBuffer(), GetVaryingBuffer(),
(int*)_tables[V_ITa].ptr + _tableOffsets[V_ITa][level-1], (int*)_tables[V_ITa].ptr + _tableOffsets[V_ITa][level-1],
(int*)_tables[V_IT].ptr + _tableOffsets[V_IT][level-1], (int*)_tables[V_IT].ptr + _tableOffsets[V_IT][level-1],
@ -256,13 +283,31 @@ OsdCpuKernelDispatcher::ApplyLoopVertexVerticesKernelB( FarMesh<OsdVertex> * mes
void void
OsdCpuKernelDispatcher::ApplyLoopVertexVerticesKernelA( FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const { OsdCpuKernelDispatcher::ApplyLoopVertexVerticesKernelA( FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const {
computeVertexA(_vdesc, GetVertexBuffer(), GetVaryingBuffer(), computeVertexA(_vdesc, GetVertexBuffer(), GetVaryingBuffer(),
(int*)_tables[V_ITa].ptr + _tableOffsets[V_ITa][level-1], (int*)_tables[V_ITa].ptr + _tableOffsets[V_ITa][level-1],
(float*)_tables[V_W].ptr + _tableOffsets[V_W][level-1], (float*)_tables[V_W].ptr + _tableOffsets[V_W][level-1],
offset, start, end, pass); offset, start, end, pass);
} }
void
OsdCpuKernelDispatcher::ApplyVertexEdit(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) {
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]);
}
}
}
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv } // end namespace OpenSubdiv

View File

@ -69,35 +69,41 @@ class OsdCpuKernelDispatcher : public OsdKernelDispatcher
{ {
public: public:
OsdCpuKernelDispatcher(int levels, int numOmpThreads=1); OsdCpuKernelDispatcher(int levels, int numOmpThreads=1);
virtual ~OsdCpuKernelDispatcher(); virtual ~OsdCpuKernelDispatcher();
virtual void ApplyBilinearFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyBilinearFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyBilinearEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyBilinearEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyBilinearVertexVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyBilinearVertexVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyCatmarkFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyCatmarkEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyCatmarkVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const; virtual void ApplyCatmarkVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const;
virtual void ApplyLoopEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyLoopEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyLoopVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyLoopVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const; 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 CopyTable(int tableIndex, size_t size, const void *ptr); virtual void CopyTable(int tableIndex, size_t size, const void *ptr);
virtual void AllocateEditTables(int n);
virtual void UpdateEditTable(int tableIndex, const FarTable<unsigned int> &offsets, const FarTable<float> &values,
int operation, int primVarOffset, int primVarWidth);
virtual void OnKernelLaunch(); virtual void OnKernelLaunch();
virtual void OnKernelFinish() {} virtual void OnKernelFinish() {}
@ -113,15 +119,16 @@ public:
static void Register(); static void Register();
protected: protected:
struct SubdivisionTable {
SubdivisionTable() : ptr(NULL) { }
~SubdivisionTable(); // XXX: until far refactoring finishes, use this.
struct Table {
Table() : ptr(NULL) { }
~Table();
void Copy(int size, const void *ptr); void Copy(int size, const void *ptr);
void *ptr; void *ptr;
}; };
float *GetVertexBuffer() const { return _currentVertexBuffer ? _currentVertexBuffer->GetCpuBuffer() : NULL; } float *GetVertexBuffer() const { return _currentVertexBuffer ? _currentVertexBuffer->GetCpuBuffer() : NULL; }
@ -134,7 +141,8 @@ protected:
VertexDescriptor *_vdesc; VertexDescriptor *_vdesc;
int _numOmpThreads; int _numOmpThreads;
std::vector<SubdivisionTable> _tables; std::vector<Table> _tables;
std::vector<Table> _editTables;
}; };
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION

View File

@ -59,7 +59,7 @@
#include "../version.h" #include "../version.h"
#include "../osd/cpuKernel.h" #include "../osd/cpuKernel.h"
#ifdef OPENSUBDIV_HAS_OPENMP #ifdef OPENSUBDIV_HAS_OPENMP
#include <omp.h> #include <omp.h>
#endif #endif
@ -67,7 +67,7 @@ namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION { namespace OPENSUBDIV_VERSION {
void computeFace( const VertexDescriptor *vdesc, float * vertex, float * varying, const int *F_IT, const int *F_ITa, int offset, int start, int end) { void computeFace( const VertexDescriptor *vdesc, float * vertex, float * varying, const int *F_IT, const int *F_ITa, int offset, int start, int end) {
#ifdef _OPENMP #ifdef _OPENMP
#pragma omp parallel for #pragma omp parallel for
#endif #endif
@ -97,20 +97,20 @@ void computeEdge( const VertexDescriptor *vdesc, float *vertex, float *varying,
for (int i = start; i < end; i++) { for (int i = start; i < end; i++) {
int eidx0 = E_IT[4*i+0]; int eidx0 = E_IT[4*i+0];
int eidx1 = E_IT[4*i+1]; int eidx1 = E_IT[4*i+1];
int eidx2 = E_IT[4*i+2]; int eidx2 = E_IT[4*i+2];
int eidx3 = E_IT[4*i+3]; int eidx3 = E_IT[4*i+3];
float vertWeight = E_W[i*2+0]; float vertWeight = E_W[i*2+0];
int dstIndex = offset + i; int dstIndex = offset + i;
vdesc->Clear(vertex, varying, dstIndex); vdesc->Clear(vertex, varying, dstIndex);
vdesc->AddWithWeight(vertex, dstIndex, eidx0, vertWeight); vdesc->AddWithWeight(vertex, dstIndex, eidx0, vertWeight);
vdesc->AddWithWeight(vertex, dstIndex, eidx1, vertWeight); vdesc->AddWithWeight(vertex, dstIndex, eidx1, vertWeight);
if (eidx2 != -1) { if (eidx2 != -1) {
float faceWeight = E_W[i*2+1]; float faceWeight = E_W[i*2+1];
vdesc->AddWithWeight(vertex, dstIndex, eidx2, faceWeight); vdesc->AddWithWeight(vertex, dstIndex, eidx2, faceWeight);
vdesc->AddWithWeight(vertex, dstIndex, eidx3, faceWeight); vdesc->AddWithWeight(vertex, dstIndex, eidx3, faceWeight);
} }
@ -130,19 +130,19 @@ void computeVertexA(const VertexDescriptor *vdesc, float *vertex, float *varying
int p = V_ITa[5*i+2]; int p = V_ITa[5*i+2];
int eidx0 = V_ITa[5*i+3]; int eidx0 = V_ITa[5*i+3];
int eidx1 = V_ITa[5*i+4]; int eidx1 = V_ITa[5*i+4];
float weight = (pass==1) ? V_W[i] : 1.0f - V_W[i]; float weight = (pass==1) ? V_W[i] : 1.0f - V_W[i];
// In the case of fractional weight, the weight must be inverted since // In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the // the value is shared with the k_Smooth kernel (statistically the
// k_Smooth kernel runs much more often than this one) // k_Smooth kernel runs much more often than this one)
if (weight>0.0f && weight<1.0f && n > 0) if (weight>0.0f && weight<1.0f && n > 0)
weight=1.0f-weight; weight=1.0f-weight;
int dstIndex = offset + i; int dstIndex = offset + i;
if(not pass) if(not pass)
vdesc->Clear(vertex, varying, dstIndex); vdesc->Clear(vertex, varying, dstIndex);
if (eidx0==-1 || (pass==0 && (n==-1)) ) { if (eidx0==-1 || (pass==0 && (n==-1)) ) {
vdesc->AddWithWeight(vertex, dstIndex, p, weight); vdesc->AddWithWeight(vertex, dstIndex, p, weight);
} else { } else {
@ -165,14 +165,14 @@ void computeVertexB(const VertexDescriptor *vdesc, float *vertex, float *varying
int h = V_ITa[5*i]; int h = V_ITa[5*i];
int n = V_ITa[5*i+1]; int n = V_ITa[5*i+1];
int p = V_ITa[5*i+2]; int p = V_ITa[5*i+2];
float weight = V_W[i]; float weight = V_W[i];
float wp = 1.0f/float(n*n); float wp = 1.0f/float(n*n);
float wv = (n-2.0f) * n * wp; float wv = (n-2.0f) * n * wp;
int dstIndex = offset + i; int dstIndex = offset + i;
vdesc->Clear(vertex, varying, dstIndex); vdesc->Clear(vertex, varying, dstIndex);
vdesc->AddWithWeight(vertex, dstIndex, p, weight * wv); vdesc->AddWithWeight(vertex, dstIndex, p, weight * wv);
for (int j = 0; j < n; ++j) { for (int j = 0; j < n; ++j) {
@ -192,16 +192,16 @@ void computeLoopVertexB(const VertexDescriptor *vdesc, float *vertex, float *var
int h = V_ITa[5*i]; int h = V_ITa[5*i];
int n = V_ITa[5*i+1]; int n = V_ITa[5*i+1];
int p = V_ITa[5*i+2]; int p = V_ITa[5*i+2];
float weight = V_W[i]; float weight = V_W[i];
float wp = 1.0f/float(n); float wp = 1.0f/float(n);
float beta = 0.25f * cosf(float(M_PI) * 2.0f * wp) + 0.375f; float beta = 0.25f * cosf(float(M_PI) * 2.0f * wp) + 0.375f;
beta = beta * beta; beta = beta * beta;
beta = (0.625f - beta) * wp; beta = (0.625f - beta) * wp;
int dstIndex = offset + i; int dstIndex = offset + i;
vdesc->Clear(vertex, varying, dstIndex); vdesc->Clear(vertex, varying, dstIndex);
vdesc->AddWithWeight(vertex, dstIndex, p, weight * (1.0f - (beta * n))); vdesc->AddWithWeight(vertex, dstIndex, p, weight * (1.0f - (beta * n)));
for (int j = 0; j < n; ++j) for (int j = 0; j < n; ++j)
@ -219,13 +219,13 @@ void computeBilinearEdge(const VertexDescriptor *vdesc, float *vertex, float *va
for (int i = start; i < end; i++) { for (int i = start; i < end; i++) {
int eidx0 = E_IT[2*i+0]; int eidx0 = E_IT[2*i+0];
int eidx1 = E_IT[2*i+1]; int eidx1 = E_IT[2*i+1];
int dstIndex = offset + i; int dstIndex = offset + i;
vdesc->Clear(vertex, varying, dstIndex); vdesc->Clear(vertex, varying, dstIndex);
vdesc->AddWithWeight(vertex, dstIndex, eidx0, 0.5f); vdesc->AddWithWeight(vertex, dstIndex, eidx0, 0.5f);
vdesc->AddWithWeight(vertex, dstIndex, eidx1, 0.5f); vdesc->AddWithWeight(vertex, dstIndex, eidx1, 0.5f);
vdesc->AddVaryingWithWeight(varying, dstIndex, eidx0, 0.5f); vdesc->AddVaryingWithWeight(varying, dstIndex, eidx0, 0.5f);
vdesc->AddVaryingWithWeight(varying, dstIndex, eidx1, 0.5f); vdesc->AddVaryingWithWeight(varying, dstIndex, eidx1, 0.5f);
} }
@ -238,14 +238,24 @@ void computeBilinearVertex(const VertexDescriptor *vdesc, float *vertex, float *
#endif #endif
for (int i = start; i < end; i++) { for (int i = start; i < end; i++) {
int p = V_ITa[i]; int p = V_ITa[i];
int dstIndex = offset + i; int dstIndex = offset + i;
vdesc->Clear(vertex, varying, dstIndex); vdesc->Clear(vertex, varying, dstIndex);
vdesc->AddWithWeight(vertex, dstIndex, p, 1.0f); vdesc->AddWithWeight(vertex, dstIndex, p, 1.0f);
vdesc->AddVaryingWithWeight(varying, dstIndex, p, 1.0f); vdesc->AddVaryingWithWeight(varying, dstIndex, p, 1.0f);
} }
} }
void editVertexAdd(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->ApplyVertexEditAdd(vertex, primVarOffset, primVarWidth, editIndices[i], &editValues[i*primVarWidth]);
}
}
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv } // end namespace OpenSubdiv

View File

@ -58,13 +58,14 @@
#define OSD_CPU_KERNEL_H #define OSD_CPU_KERNEL_H
#include "../version.h" #include "../version.h"
#include <stdio.h>
namespace OpenSubdiv { namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION { namespace OPENSUBDIV_VERSION {
struct VertexDescriptor { struct VertexDescriptor {
VertexDescriptor(int numVertexElem, int numVaryingElem) VertexDescriptor(int numVertexElem, int numVaryingElem)
: numVertexElements(numVertexElem), numVaryingElements(numVaryingElem) { } : numVertexElements(numVertexElem), numVaryingElements(numVaryingElem) { }
void Clear(float *vertex, float *varying, int index) const { void Clear(float *vertex, float *varying, int index) const {
@ -90,7 +91,14 @@ struct VertexDescriptor {
for (int i = 0; i < numVaryingElements; ++i) for (int i = 0; i < numVaryingElements; ++i)
varying[d++] += varying[s++] * weight; varying[d++] += varying[s++] * weight;
} }
void ApplyVertexEditAdd(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 numVertexElements;
int numVaryingElements; int numVaryingElements;
}; };
@ -111,6 +119,10 @@ void computeBilinearEdge(const VertexDescriptor *vdesc, float *vertex, float * v
void computeBilinearVertex(const VertexDescriptor *vdesc, float *vertex, float * varying, const int *V_ITa, int offset, int start, int end); void computeBilinearVertex(const VertexDescriptor *vdesc, float *vertex, float * varying, const int *V_ITa, int offset, int start, int end);
void editVertexAdd(const VertexDescriptor *vdesc, float *vertex, int primVarOffset, int primVarWidth, int count, const int *editIndices, const float *editValues);
void editVertexSet(const VertexDescriptor *vdesc, float *vertex, int primVarOffset, int primVarWidth, int count, const int *editIndices, const float *editValues);
} }
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION

View File

@ -76,6 +76,8 @@ void OsdCudaComputeBilinearEdge(float *vertex, float *varying, int numUserVertex
void OsdCudaComputeBilinearVertex(float *vertex, float *varying, int numUserVertexElements, int numVaryingElements, int *V_ITa, int offset, int start, int end); void OsdCudaComputeBilinearVertex(float *vertex, float *varying, int numUserVertexElements, int numVaryingElements, int *V_ITa, int offset, int start, int end);
void OsdCudaEditVertexAdd(float *vertex, int numUserVertexElements, int primVarOffset, int primVarWidth, int numVertices, int *editIndices, float *editValues);
} }
namespace OpenSubdiv { namespace OpenSubdiv {
@ -145,7 +147,34 @@ OsdCudaKernelDispatcher::~OsdCudaKernelDispatcher() {
void void
OsdCudaKernelDispatcher::CopyTable(int tableIndex, size_t size, const void *ptr) { OsdCudaKernelDispatcher::CopyTable(int tableIndex, size_t size, const void *ptr) {
_tables[tableIndex].Copy(size, ptr); _tables[tableIndex].Copy((int)size, ptr);
}
void
OsdCudaKernelDispatcher::AllocateEditTables(int n) {
_editTables.resize(n*2);
_edits.resize(n);
}
void
OsdCudaKernelDispatcher::UpdateEditTable(int tableIndex, const FarTable<unsigned int> &offsets, const FarTable<float> &values,
int operation, int primVarOffset, int primVarWidth) {
_editTables[tableIndex*2+0].Copy(offsets.GetMemoryUsed(), offsets[0]);
_editTables[tableIndex*2+1].Copy(values.GetMemoryUsed(), values[0]);
_edits[tableIndex].offsetOffsets.resize(_maxLevel);
_edits[tableIndex].valueOffsets.resize(_maxLevel);
_edits[tableIndex].numEdits.resize(_maxLevel);
for (int i = 0; i < _maxLevel; ++i) {
_edits[tableIndex].offsetOffsets[i] = (int)(offsets[i] - offsets[0]);
_edits[tableIndex].valueOffsets[i] = (int)(values[i] - values[0]);
_edits[tableIndex].numEdits[i] = offsets.GetNumElements(i);
}
_edits[tableIndex].operation = operation;
_edits[tableIndex].primVarOffset = primVarOffset;
_edits[tableIndex].primVarWidth = primVarWidth;
} }
OsdVertexBuffer * OsdVertexBuffer *
@ -174,7 +203,7 @@ OsdCudaKernelDispatcher::BindVertexBuffer(OsdVertexBuffer *vertex, OsdVertexBuff
} else { } else {
_numVertexElements = 0; _numVertexElements = 0;
} }
if (_currentVaryingBuffer) { if (_currentVaryingBuffer) {
_deviceVaryings = (float*)_currentVaryingBuffer->Map(); _deviceVaryings = (float*)_currentVaryingBuffer->Map();
_numVaryingElements = _currentVaryingBuffer->GetNumElements(); _numVaryingElements = _currentVaryingBuffer->GetNumElements();
@ -222,7 +251,7 @@ OsdCudaKernelDispatcher::ApplyBilinearEdgeVerticesKernel(FarMesh<OsdVertex> * me
void void
OsdCudaKernelDispatcher::ApplyBilinearVertexVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { OsdCudaKernelDispatcher::ApplyBilinearVertexVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
OsdCudaComputeBilinearVertex(_deviceVertices, _deviceVaryings, OsdCudaComputeBilinearVertex(_deviceVertices, _deviceVaryings,
_numVertexElements-3, _numVaryingElements, _numVertexElements-3, _numVaryingElements,
(int*)_tables[V_ITa].devicePtr + _tableOffsets[V_ITa][level-1], (int*)_tables[V_ITa].devicePtr + _tableOffsets[V_ITa][level-1],
@ -299,5 +328,21 @@ OsdCudaKernelDispatcher::ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mes
offset, start, end, pass); offset, start, end, pass);
} }
void
OsdCudaKernelDispatcher::ApplyVertexEdit(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) {
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:
}
}
}
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv } // end namespace OpenSubdiv

View File

@ -92,32 +92,40 @@ public:
virtual void ApplyBilinearFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyBilinearFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyBilinearEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyBilinearEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyBilinearVertexVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyBilinearVertexVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyCatmarkFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyCatmarkEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyCatmarkVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const; virtual void ApplyCatmarkVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const;
virtual void ApplyLoopEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyLoopEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyLoopVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyLoopVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const; 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 CopyTable(int tableIndex, size_t size, const void *ptr); virtual void CopyTable(int tableIndex, size_t size, const void *ptr);
virtual void AllocateEditTables(int n);
virtual void UpdateEditTable(int tableIndex, const FarTable<unsigned int> &offsets, const FarTable<float> &values,
int operation, int primVarOffset, int primVarWidth);
virtual void OnKernelLaunch() {} virtual void OnKernelLaunch() {}
virtual void OnKernelFinish() {} virtual void OnKernelFinish() {}
@ -125,7 +133,7 @@ public:
virtual OsdVertexBuffer *InitializeVertexBuffer(int numElements, int numVertices); virtual OsdVertexBuffer *InitializeVertexBuffer(int numElements, int numVertices);
virtual void BindVertexBuffer(OsdVertexBuffer *vertex, OsdVertexBuffer *varying); virtual void BindVertexBuffer(OsdVertexBuffer *vertex, OsdVertexBuffer *varying);
virtual void UnbindVertexBuffer(); virtual void UnbindVertexBuffer();
virtual void Synchronize(); virtual void Synchronize();
@ -138,7 +146,7 @@ public:
} }
protected: protected:
struct DeviceTable struct DeviceTable
{ {
DeviceTable() : devicePtr(NULL) {} DeviceTable() : devicePtr(NULL) {}
~DeviceTable(); ~DeviceTable();
@ -149,6 +157,7 @@ protected:
}; };
std::vector<DeviceTable> _tables; std::vector<DeviceTable> _tables;
std::vector<DeviceTable> _editTables;
OsdCudaVertexBuffer *_currentVertexBuffer, OsdCudaVertexBuffer *_currentVertexBuffer,
*_currentVaryingBuffer; *_currentVaryingBuffer;
@ -156,7 +165,7 @@ protected:
float *_deviceVertices, float *_deviceVertices,
*_deviceVaryings; *_deviceVaryings;
int _numVertexElements, int _numVertexElements,
_numVaryingElements; _numVaryingElements;
}; };

View File

@ -141,14 +141,14 @@ computeFace(float *fVertex, float *fVaryings, int *F0_IT, int *F0_ITa, int offse
int h = F0_ITa[2*i]; int h = F0_ITa[2*i];
int n = F0_ITa[2*i+1]; int n = F0_ITa[2*i+1];
float weight = 1.0f/n; float weight = 1.0f/n;
DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst; DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst;
dst.clear(); dst.clear();
if(NUM_VARYING_ELEMENTS > 0){ if(NUM_VARYING_ELEMENTS > 0){
DeviceVarying<NUM_VARYING_ELEMENTS> dstVarying; DeviceVarying<NUM_VARYING_ELEMENTS> dstVarying;
dstVarying.clear(); dstVarying.clear();
for(int j=0; j<n; ++j){ for(int j=0; j<n; ++j){
int index = F0_IT[h+j]; int index = F0_IT[h+j];
dst.addWithWeight(&vertex[index], weight); dst.addWithWeight(&vertex[index], weight);
@ -197,21 +197,21 @@ computeEdge(float *fVertex, float *fVaryings, int *E0_IT, float *E0_S, int offse
for(int i = start + threadIdx.x + blockIdx.x*blockDim.x; i < end; i+= blockDim.x * gridDim.x){ for(int i = start + threadIdx.x + blockIdx.x*blockDim.x; i < end; i+= blockDim.x * gridDim.x){
int eidx0 = E0_IT[4*i+0]; int eidx0 = E0_IT[4*i+0];
int eidx1 = E0_IT[4*i+1]; int eidx1 = E0_IT[4*i+1];
int eidx2 = E0_IT[4*i+2]; int eidx2 = E0_IT[4*i+2];
int eidx3 = E0_IT[4*i+3]; int eidx3 = E0_IT[4*i+3];
float vertWeight = E0_S[i*2+0]; float vertWeight = E0_S[i*2+0];
// Fully sharp edge : vertWeight = 0.5f; // Fully sharp edge : vertWeight = 0.5f;
DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst; DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst;
dst.clear(); dst.clear();
dst.addWithWeight(&vertex[eidx0], vertWeight); dst.addWithWeight(&vertex[eidx0], vertWeight);
dst.addWithWeight(&vertex[eidx1], vertWeight); dst.addWithWeight(&vertex[eidx1], vertWeight);
if(eidx2 > -1){ if(eidx2 > -1){
float faceWeight = E0_S[i*2+1]; float faceWeight = E0_S[i*2+1];
dst.addWithWeight(&vertex[eidx2], faceWeight); dst.addWithWeight(&vertex[eidx2], faceWeight);
dst.addWithWeight(&vertex[eidx3], faceWeight); dst.addWithWeight(&vertex[eidx3], faceWeight);
} }
@ -228,27 +228,27 @@ computeEdge(float *fVertex, float *fVaryings, int *E0_IT, float *E0_S, int offse
} }
__global__ void __global__ void
computeEdge(float *fVertex, int numVertexElements, float *fVarying, int numVaryingElements, computeEdge(float *fVertex, int numVertexElements, float *fVarying, int numVaryingElements,
int *E0_IT, float *E0_S, int offset, int start, int end) int *E0_IT, float *E0_S, int offset, int start, int end)
{ {
for(int i = start + threadIdx.x + blockIdx.x*blockDim.x; i < end; i+= blockDim.x * gridDim.x){ for(int i = start + threadIdx.x + blockIdx.x*blockDim.x; i < end; i+= blockDim.x * gridDim.x){
int eidx0 = E0_IT[4*i+0]; int eidx0 = E0_IT[4*i+0];
int eidx1 = E0_IT[4*i+1]; int eidx1 = E0_IT[4*i+1];
int eidx2 = E0_IT[4*i+2]; int eidx2 = E0_IT[4*i+2];
int eidx3 = E0_IT[4*i+3]; int eidx3 = E0_IT[4*i+3];
float vertWeight = E0_S[i*2+0]; float vertWeight = E0_S[i*2+0];
// Fully sharp edge : vertWeight = 0.5f; // Fully sharp edge : vertWeight = 0.5f;
float *dstVertex = fVertex + (i+offset)*numVertexElements; float *dstVertex = fVertex + (i+offset)*numVertexElements;
clear(dstVertex, numVertexElements); clear(dstVertex, numVertexElements);
addWithWeight(dstVertex, fVertex + eidx0*numVertexElements, vertWeight, numVertexElements); addWithWeight(dstVertex, fVertex + eidx0*numVertexElements, vertWeight, numVertexElements);
addWithWeight(dstVertex, fVertex + eidx1*numVertexElements, vertWeight, numVertexElements); addWithWeight(dstVertex, fVertex + eidx1*numVertexElements, vertWeight, numVertexElements);
if(eidx2 > -1){ if(eidx2 > -1){
float faceWeight = E0_S[i*2+1]; float faceWeight = E0_S[i*2+1];
addWithWeight(dstVertex, fVertex + eidx2*numVertexElements, faceWeight, numVertexElements); addWithWeight(dstVertex, fVertex + eidx2*numVertexElements, faceWeight, numVertexElements);
addWithWeight(dstVertex, fVertex + eidx3*numVertexElements, faceWeight, numVertexElements); addWithWeight(dstVertex, fVertex + eidx3*numVertexElements, faceWeight, numVertexElements);
} }
@ -273,22 +273,22 @@ computeVertexA(float *fVertex, float *fVaryings, int *V0_ITa, float *V0_S, int o
int p = V0_ITa[5*i+2]; int p = V0_ITa[5*i+2];
int eidx0 = V0_ITa[5*i+3]; int eidx0 = V0_ITa[5*i+3];
int eidx1 = V0_ITa[5*i+4]; int eidx1 = V0_ITa[5*i+4];
float weight = (pass==1) ? V0_S[i] : 1.0f - V0_S[i]; float weight = (pass==1) ? V0_S[i] : 1.0f - V0_S[i];
// In the case of fractional weight, the weight must be inverted since // In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the // the value is shared with the k_Smooth kernel (statistically the
// k_Smooth kernel runs much more often than this one) // k_Smooth kernel runs much more often than this one)
if (weight>0.0f && weight<1.0f && n > 0) if (weight>0.0f && weight<1.0f && n > 0)
weight=1.0f-weight; weight=1.0f-weight;
DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst; DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst;
if (not pass) { if (not pass) {
dst.clear(); dst.clear();
} else { } else {
dst = vertex[i+offset]; dst = vertex[i+offset];
} }
if (eidx0==-1 || (pass==0 && (n==-1)) ) { if (eidx0==-1 || (pass==0 && (n==-1)) ) {
dst.addWithWeight(&vertex[p], weight); dst.addWithWeight(&vertex[p], weight);
} else { } else {
@ -318,11 +318,11 @@ computeVertexA(float *fVertex, int numVertexElements, float *fVaryings, int numV
int p = V0_ITa[5*i+2]; int p = V0_ITa[5*i+2];
int eidx0 = V0_ITa[5*i+3]; int eidx0 = V0_ITa[5*i+3];
int eidx1 = V0_ITa[5*i+4]; int eidx1 = V0_ITa[5*i+4];
float weight = (pass==1) ? V0_S[i] : 1.0f - V0_S[i]; float weight = (pass==1) ? V0_S[i] : 1.0f - V0_S[i];
// In the case of fractional weight, the weight must be inverted since // In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the // the value is shared with the k_Smooth kernel (statistically the
// k_Smooth kernel runs much more often than this one) // k_Smooth kernel runs much more often than this one)
if (weight>0.0f && weight<1.0f && n > 0) if (weight>0.0f && weight<1.0f && n > 0)
weight=1.0f-weight; weight=1.0f-weight;
@ -331,7 +331,7 @@ computeVertexA(float *fVertex, int numVertexElements, float *fVaryings, int numV
if (not pass) { if (not pass) {
clear(dstVertex, numVertexElements); clear(dstVertex, numVertexElements);
} }
if (eidx0==-1 || (pass==0 && (n==-1)) ) { if (eidx0==-1 || (pass==0 && (n==-1)) ) {
addWithWeight(dstVertex, fVertex + p*numVertexElements, weight, numVertexElements); addWithWeight(dstVertex, fVertex + p*numVertexElements, weight, numVertexElements);
} else { } else {
@ -348,7 +348,7 @@ computeVertexA(float *fVertex, int numVertexElements, float *fVaryings, int numV
} }
} }
} }
} }
@ -364,11 +364,11 @@ computeVertexB(float *fVertex, float *fVaryings,
int h = V0_ITa[5*i]; int h = V0_ITa[5*i];
int n = V0_ITa[5*i+1]; int n = V0_ITa[5*i+1];
int p = V0_ITa[5*i+2]; int p = V0_ITa[5*i+2];
float weight = V0_S[i]; float weight = V0_S[i];
float wp = 1.0f/float(n*n); float wp = 1.0f/float(n*n);
float wv = (n-2.0f) * n * wp; float wv = (n-2.0f) * n * wp;
DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst; DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst;
dst.clear(); dst.clear();
dst.addWithWeight(&vertex[p], weight * wv); dst.addWithWeight(&vertex[p], weight * wv);
@ -381,7 +381,7 @@ computeVertexB(float *fVertex, float *fVaryings,
// dst.addWithWeight(&vertex[idx0], weight * wp); // dst.addWithWeight(&vertex[idx0], weight * wp);
// dst.addWithWeight(&vertex[idx1], weight * wp); // dst.addWithWeight(&vertex[idx1], weight * wp);
} }
vertex[i+offset] = dst; vertex[i+offset] = dst;
if(NUM_VARYING_ELEMENTS > 0){ if(NUM_VARYING_ELEMENTS > 0){
DeviceVarying<NUM_VARYING_ELEMENTS> dstVarying; DeviceVarying<NUM_VARYING_ELEMENTS> dstVarying;
@ -400,11 +400,11 @@ computeVertexB(float *fVertex, int numVertexElements, float *fVaryings, int numV
int h = V0_ITa[5*i]; int h = V0_ITa[5*i];
int n = V0_ITa[5*i+1]; int n = V0_ITa[5*i+1];
int p = V0_ITa[5*i+2]; int p = V0_ITa[5*i+2];
float weight = V0_S[i]; float weight = V0_S[i];
float wp = 1.0f/float(n*n); float wp = 1.0f/float(n*n);
float wv = (n-2.0f) * n * wp; float wv = (n-2.0f) * n * wp;
float *dstVertex = fVertex + (i+offset)*numVertexElements; float *dstVertex = fVertex + (i+offset)*numVertexElements;
clear(dstVertex, numVertexElements); clear(dstVertex, numVertexElements);
addWithWeight(dstVertex, fVertex + p*numVertexElements, weight*wv, numVertexElements); addWithWeight(dstVertex, fVertex + p*numVertexElements, weight*wv, numVertexElements);
@ -421,7 +421,7 @@ computeVertexB(float *fVertex, int numVertexElements, float *fVaryings, int numV
} }
} }
} }
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
@ -434,22 +434,22 @@ computeLoopVertexB(float *fVertex, float *fVaryings, int *V0_ITa, int *V0_IT, fl
int h = V0_ITa[5*i]; int h = V0_ITa[5*i];
int n = V0_ITa[5*i+1]; int n = V0_ITa[5*i+1];
int p = V0_ITa[5*i+2]; int p = V0_ITa[5*i+2];
float weight = V0_S[i]; float weight = V0_S[i];
float wp = 1.0f/float(n); float wp = 1.0f/float(n);
float beta = 0.25f * __cosf(float(M_PI) * 2.0f * wp) + 0.375f; float beta = 0.25f * __cosf(float(M_PI) * 2.0f * wp) + 0.375f;
beta = beta * beta; beta = beta * beta;
beta = (0.625f - beta) * wp; beta = (0.625f - beta) * wp;
DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst; DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst;
dst.clear(); dst.clear();
dst.addWithWeight(&vertex[p], weight * (1.0f - (beta * n))); dst.addWithWeight(&vertex[p], weight * (1.0f - (beta * n)));
for(int j = 0; j < n; ++j){ for(int j = 0; j < n; ++j){
dst.addWithWeight(&vertex[V0_IT[h+j]], weight * beta); dst.addWithWeight(&vertex[V0_IT[h+j]], weight * beta);
} }
vertex[i+offset] = dst; vertex[i+offset] = dst;
if(NUM_VARYING_ELEMENTS > 0){ if(NUM_VARYING_ELEMENTS > 0){
DeviceVarying<NUM_VARYING_ELEMENTS> dstVarying; DeviceVarying<NUM_VARYING_ELEMENTS> dstVarying;
@ -468,13 +468,13 @@ computeLoopVertexB(float *fVertex, int numVertexElements, float *fVaryings, int
int h = V0_ITa[5*i]; int h = V0_ITa[5*i];
int n = V0_ITa[5*i+1]; int n = V0_ITa[5*i+1];
int p = V0_ITa[5*i+2]; int p = V0_ITa[5*i+2];
float weight = V0_S[i]; float weight = V0_S[i];
float wp = 1.0f/float(n); float wp = 1.0f/float(n);
float beta = 0.25f * __cosf(float(M_PI) * 2.0f * wp) + 0.375f; float beta = 0.25f * __cosf(float(M_PI) * 2.0f * wp) + 0.375f;
beta = beta * beta; beta = beta * beta;
beta = (0.625f - beta) * wp; beta = (0.625f - beta) * wp;
float *dstVertex = fVertex + (i+offset)*numVertexElements; float *dstVertex = fVertex + (i+offset)*numVertexElements;
clear(dstVertex, numVertexElements); clear(dstVertex, numVertexElements);
addWithWeight(dstVertex, fVertex + p*numVertexElements, weight*(1.0f-(beta*n)), numVertexElements); addWithWeight(dstVertex, fVertex + p*numVertexElements, weight*(1.0f-(beta*n)), numVertexElements);
@ -490,7 +490,7 @@ computeLoopVertexB(float *fVertex, int numVertexElements, float *fVaryings, int
} }
} }
} }
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
template <int NUM_USER_VERTEX_ELEMENTS, int NUM_VARYING_ELEMENTS> __global__ void template <int NUM_USER_VERTEX_ELEMENTS, int NUM_VARYING_ELEMENTS> __global__ void
@ -501,13 +501,13 @@ computeBilinearEdge(float *fVertex, float *fVaryings, int *E0_IT, int offset, in
for(int i = start + threadIdx.x + blockIdx.x*blockDim.x; i < end; i+= blockDim.x * gridDim.x){ for(int i = start + threadIdx.x + blockIdx.x*blockDim.x; i < end; i+= blockDim.x * gridDim.x){
int eidx0 = E0_IT[2*i+0]; int eidx0 = E0_IT[2*i+0];
int eidx1 = E0_IT[2*i+1]; int eidx1 = E0_IT[2*i+1];
DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst; DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst;
dst.clear(); dst.clear();
dst.addWithWeight(&vertex[eidx0], 0.5f); dst.addWithWeight(&vertex[eidx0], 0.5f);
dst.addWithWeight(&vertex[eidx1], 0.5f); dst.addWithWeight(&vertex[eidx1], 0.5f);
vertex[offset+i] = dst; vertex[offset+i] = dst;
if(NUM_VARYING_ELEMENTS > 0){ if(NUM_VARYING_ELEMENTS > 0){
@ -521,19 +521,19 @@ computeBilinearEdge(float *fVertex, float *fVaryings, int *E0_IT, int offset, in
} }
__global__ void __global__ void
computeBilinearEdge(float *fVertex, int numVertexElements, float *fVarying, int numVaryingElements, computeBilinearEdge(float *fVertex, int numVertexElements, float *fVarying, int numVaryingElements,
int *E0_IT, int offset, int start, int end) int *E0_IT, int offset, int start, int end)
{ {
for(int i = start + threadIdx.x + blockIdx.x*blockDim.x; i < end; i+= blockDim.x * gridDim.x){ for(int i = start + threadIdx.x + blockIdx.x*blockDim.x; i < end; i+= blockDim.x * gridDim.x){
int eidx0 = E0_IT[2*i+0]; int eidx0 = E0_IT[2*i+0];
int eidx1 = E0_IT[2*i+1]; int eidx1 = E0_IT[2*i+1];
float *dstVertex = fVertex + (i+offset)*numVertexElements; float *dstVertex = fVertex + (i+offset)*numVertexElements;
clear(dstVertex, numVertexElements); clear(dstVertex, numVertexElements);
addWithWeight(dstVertex, fVertex + eidx0*numVertexElements, 0.5f, numVertexElements); addWithWeight(dstVertex, fVertex + eidx0*numVertexElements, 0.5f, numVertexElements);
addWithWeight(dstVertex, fVertex + eidx1*numVertexElements, 0.5f, numVertexElements); addWithWeight(dstVertex, fVertex + eidx1*numVertexElements, 0.5f, numVertexElements);
if(numVaryingElements > 0){ if(numVaryingElements > 0){
float *dstVarying = fVarying + i*numVaryingElements; float *dstVarying = fVarying + i*numVaryingElements;
clear(dstVarying, numVaryingElements); clear(dstVarying, numVaryingElements);
@ -551,12 +551,12 @@ computeBilinearVertex(float *fVertex, float *fVaryings, int *V0_ITa, int offset,
DeviceVarying<NUM_VARYING_ELEMENTS> *varyings = (DeviceVarying<NUM_VARYING_ELEMENTS>*)fVaryings; DeviceVarying<NUM_VARYING_ELEMENTS> *varyings = (DeviceVarying<NUM_VARYING_ELEMENTS>*)fVaryings;
for(int i = start + threadIdx.x + blockIdx.x*blockDim.x; i < end; i += blockDim.x * gridDim.x){ for(int i = start + threadIdx.x + blockIdx.x*blockDim.x; i < end; i += blockDim.x * gridDim.x){
int p = V0_ITa[i]; int p = V0_ITa[i];
DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst; DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst;
dst.clear(); dst.clear();
dst.addWithWeight(&vertex[p], 1.0f); dst.addWithWeight(&vertex[p], 1.0f);
vertex[i+offset] = dst; vertex[i+offset] = dst;
if(NUM_VARYING_ELEMENTS > 0){ if(NUM_VARYING_ELEMENTS > 0){
DeviceVarying<NUM_VARYING_ELEMENTS> dstVarying; DeviceVarying<NUM_VARYING_ELEMENTS> dstVarying;
@ -573,7 +573,7 @@ computeBilinearVertex(float *fVertex, int numVertexElements, float *fVaryings, i
{ {
for(int i = start + threadIdx.x + blockIdx.x*blockDim.x; i < end; i += blockDim.x * gridDim.x){ for(int i = start + threadIdx.x + blockIdx.x*blockDim.x; i < end; i += blockDim.x * gridDim.x){
int p = V0_ITa[i]; int p = V0_ITa[i];
float *dstVertex = fVertex + (i+offset)*numVertexElements; float *dstVertex = fVertex + (i+offset)*numVertexElements;
clear(dstVertex, numVertexElements); clear(dstVertex, numVertexElements);
addWithWeight(dstVertex, fVertex + p*numVertexElements, 1.0f, numVertexElements); addWithWeight(dstVertex, fVertex + p*numVertexElements, 1.0f, numVertexElements);
@ -585,14 +585,27 @@ computeBilinearVertex(float *fVertex, int numVertexElements, float *fVaryings, i
} }
} }
} }
// --------------------------------------------------------------------------------------------
__global__ void
editVertexAdd(float *fVertex, int numVertexElements, int primVarOffset, int primVarWidth,
int numVertices, const int *editIndices, const float *editValues)
{
for(int i = threadIdx.x + blockIdx.x*blockDim.x; i < numVertices; i += blockDim.x * gridDim.x) {
float *dstVertex = fVertex + editIndices[i] * numVertexElements + primVarOffset;
for(int j = 0; j < primVarWidth; j++) {
*dstVertex++ += editValues[j];
}
}
}
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
#include "../version.h" #include "../version.h"
// XXX: this macro usage is tentative. Since cuda kernel can't be dynamically configured, // XXX: this macro usage is tentative. Since cuda kernel can't be dynamically configured,
// still trying to find better way to have optimized kernel.. // still trying to find better way to have optimized kernel..
#define OPT_KERNEL(NUM_USER_VERTEX_ELEMENTS, NUM_VARYING_ELEMENTS, KERNEL, X, Y, ARG) \ #define OPT_KERNEL(NUM_USER_VERTEX_ELEMENTS, NUM_VARYING_ELEMENTS, KERNEL, X, Y, ARG) \
@ -632,7 +645,7 @@ void OsdCudaComputeEdge(float *vertex, float *varying,
E_IT, E_W, offset, start, end); E_IT, E_W, offset, start, end);
} }
void OsdCudaComputeVertexA(float *vertex, float *varying, void OsdCudaComputeVertexA(float *vertex, float *varying,
int numUserVertexElements, int numVaryingElements, int numUserVertexElements, int numVaryingElements,
int *V_ITa, float *V_W, int offset, int start, int end, int pass) int *V_ITa, float *V_W, int offset, int start, int end, int pass)
{ {
@ -688,7 +701,7 @@ void OsdCudaComputeBilinearEdge(float *vertex, float *varying,
E_IT, offset, start, end); E_IT, offset, start, end);
} }
void OsdCudaComputeBilinearVertex(float *vertex, float *varying, void OsdCudaComputeBilinearVertex(float *vertex, float *varying,
int numUserVertexElements, int numVaryingElements, int numUserVertexElements, int numVaryingElements,
int *V_ITa, int offset, int start, int end) int *V_ITa, int offset, int start, int end)
{ {
@ -702,4 +715,11 @@ void OsdCudaComputeBilinearVertex(float *vertex, float *varying,
V_ITa, offset, start, end); V_ITa, offset, start, end);
} }
void OsdCudaEditVertexAdd(float *vertex, int numUserVertexElements,
int primVarOffset, int primVarWidth, int numVertices, int *editIndices, float *editValues)
{
editVertexAdd<<<512, 32>>>(vertex, 3+numUserVertexElements, primVarOffset, primVarWidth,
numVertices, editIndices, editValues);
}
} }

View File

@ -59,7 +59,7 @@
#if not defined(__APPLE__) #if not defined(__APPLE__)
#include <GL/glew.h> #include <GL/glew.h>
#else #else
#include <OpenGL/gl.h> #include <OpenGL/gl3.h>
#endif #endif
#include "../osd/glslDispatcher.h" #include "../osd/glslDispatcher.h"
@ -97,7 +97,7 @@ static const char *shaderDefines = ""
; ;
std::vector<OsdGlslKernelDispatcher::ComputeShader> OsdGlslKernelDispatcher::shaderRegistry; std::vector<OsdGlslKernelDispatcher::ComputeShader> OsdGlslKernelDispatcher::shaderRegistry;
OsdGlslKernelDispatcher::OsdGlslKernelDispatcher(int levels) OsdGlslKernelDispatcher::OsdGlslKernelDispatcher(int levels)
: OsdKernelDispatcher(levels) : OsdKernelDispatcher(levels)
{ {
@ -200,7 +200,7 @@ OsdGlslKernelDispatcher::BindVertexBuffer(OsdVertexBuffer *vertex, OsdVertexBuff
if (vertex) if (vertex)
_currentVertexBuffer = dynamic_cast<OsdGpuVertexBuffer *>(vertex); _currentVertexBuffer = dynamic_cast<OsdGpuVertexBuffer *>(vertex);
else else
_currentVertexBuffer = NULL; _currentVertexBuffer = NULL;
if (varying) if (varying)
@ -310,7 +310,7 @@ OsdGlslKernelDispatcher::ApplyBilinearFaceVerticesKernel(
void void
OsdGlslKernelDispatcher::ApplyBilinearEdgeVerticesKernel( OsdGlslKernelDispatcher::ApplyBilinearEdgeVerticesKernel(
FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
_shader->ApplyBilinearEdgeVerticesKernel(_currentVertexBuffer, _currentVaryingBuffer, _shader->ApplyBilinearEdgeVerticesKernel(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[E_IT][level-1], _tableOffsets[E_IT][level-1],
offset, start, end); offset, start, end);
@ -319,7 +319,7 @@ OsdGlslKernelDispatcher::ApplyBilinearEdgeVerticesKernel(
void void
OsdGlslKernelDispatcher::ApplyBilinearVertexVerticesKernel( OsdGlslKernelDispatcher::ApplyBilinearVertexVerticesKernel(
FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
_shader->ApplyBilinearVertexVerticesKernel(_currentVertexBuffer, _currentVaryingBuffer, _shader->ApplyBilinearVertexVerticesKernel(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[V_ITa][level-1], _tableOffsets[V_ITa][level-1],
offset, start, end); offset, start, end);
@ -341,7 +341,7 @@ OsdGlslKernelDispatcher::ApplyCatmarkFaceVerticesKernel(
void void
OsdGlslKernelDispatcher::ApplyCatmarkEdgeVerticesKernel( OsdGlslKernelDispatcher::ApplyCatmarkEdgeVerticesKernel(
FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
_shader->ApplyCatmarkEdgeVerticesKernel(_currentVertexBuffer, _currentVaryingBuffer, _shader->ApplyCatmarkEdgeVerticesKernel(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[E_IT][level-1], _tableOffsets[E_IT][level-1],
_tableOffsets[E_W][level-1], _tableOffsets[E_W][level-1],
@ -351,7 +351,7 @@ OsdGlslKernelDispatcher::ApplyCatmarkEdgeVerticesKernel(
void void
OsdGlslKernelDispatcher::ApplyCatmarkVertexVerticesKernelB( OsdGlslKernelDispatcher::ApplyCatmarkVertexVerticesKernelB(
FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
_shader->ApplyCatmarkVertexVerticesKernelB(_currentVertexBuffer, _currentVaryingBuffer, _shader->ApplyCatmarkVertexVerticesKernelB(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[V_IT][level-1], _tableOffsets[V_IT][level-1],
_tableOffsets[V_ITa][level-1], _tableOffsets[V_ITa][level-1],
@ -362,7 +362,7 @@ OsdGlslKernelDispatcher::ApplyCatmarkVertexVerticesKernelB(
void void
OsdGlslKernelDispatcher::ApplyCatmarkVertexVerticesKernelA( OsdGlslKernelDispatcher::ApplyCatmarkVertexVerticesKernelA(
FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const { FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const {
_shader->ApplyCatmarkVertexVerticesKernelA(_currentVertexBuffer, _currentVaryingBuffer, _shader->ApplyCatmarkVertexVerticesKernelA(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[V_ITa][level-1], _tableOffsets[V_ITa][level-1],
_tableOffsets[V_W][level-1], _tableOffsets[V_W][level-1],
@ -374,7 +374,7 @@ OsdGlslKernelDispatcher::ApplyCatmarkVertexVerticesKernelA(
void void
OsdGlslKernelDispatcher::ApplyLoopEdgeVerticesKernel( OsdGlslKernelDispatcher::ApplyLoopEdgeVerticesKernel(
FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
_shader->ApplyLoopEdgeVerticesKernel(_currentVertexBuffer, _currentVaryingBuffer, _shader->ApplyLoopEdgeVerticesKernel(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[E_IT][level-1], _tableOffsets[E_IT][level-1],
_tableOffsets[E_W][level-1], _tableOffsets[E_W][level-1],
@ -384,7 +384,7 @@ OsdGlslKernelDispatcher::ApplyLoopEdgeVerticesKernel(
void void
OsdGlslKernelDispatcher::ApplyLoopVertexVerticesKernelB( OsdGlslKernelDispatcher::ApplyLoopVertexVerticesKernelB(
FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const { FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
_shader->ApplyLoopVertexVerticesKernelB(_currentVertexBuffer, _currentVaryingBuffer, _shader->ApplyLoopVertexVerticesKernelB(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[V_IT][level-1], _tableOffsets[V_IT][level-1],
_tableOffsets[V_ITa][level-1], _tableOffsets[V_ITa][level-1],
@ -395,7 +395,7 @@ OsdGlslKernelDispatcher::ApplyLoopVertexVerticesKernelB(
void void
OsdGlslKernelDispatcher::ApplyLoopVertexVerticesKernelA( OsdGlslKernelDispatcher::ApplyLoopVertexVerticesKernelA(
FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const { FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const {
_shader->ApplyLoopVertexVerticesKernelA(_currentVertexBuffer, _currentVaryingBuffer, _shader->ApplyLoopVertexVerticesKernelA(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[V_ITa][level-1], _tableOffsets[V_ITa][level-1],
_tableOffsets[V_W][level-1], _tableOffsets[V_W][level-1],
@ -411,7 +411,7 @@ OsdGlslKernelDispatcher::ComputeShader::ComputeShader() :
OsdGlslKernelDispatcher::ComputeShader::~ComputeShader() OsdGlslKernelDispatcher::ComputeShader::~ComputeShader()
{ {
if (_program) if (_program)
glDeleteProgram(_program); glDeleteProgram(_program);
} }
@ -439,10 +439,10 @@ OsdGlslKernelDispatcher::ComputeShader::Compile(int numVertexElements, int numVa
glCompileShader(shader); glCompileShader(shader);
glAttachShader(_program, shader); glAttachShader(_program, shader);
const char *outputs[] = { "outPosition", const char *outputs[] = { "outPosition",
"outNormal", "outNormal",
"gl_NextBuffer", "gl_NextBuffer",
"outVaryingData" }; "outVaryingData" };
int nOutputs = numVaryingElements > 0 ? 4 : 2; int nOutputs = numVaryingElements > 0 ? 4 : 2;
@ -463,7 +463,7 @@ OsdGlslKernelDispatcher::ComputeShader::Compile(int numVertexElements, int numVa
glGetProgramInfoLog(_program, 1024, NULL, buffer); glGetProgramInfoLog(_program, 1024, NULL, buffer);
OSD_ERROR(buffer); OSD_ERROR(buffer);
glDeleteProgram(_program); glDeleteProgram(_program);
_program = 0; _program = 0;
// XXX ERROR HANDLE // XXX ERROR HANDLE
@ -539,7 +539,7 @@ OsdGlslKernelDispatcher::ComputeShader::transformGpuBufferData(OsdGpuVertexBuffe
glBeginTransformFeedback(GL_POINTS); glBeginTransformFeedback(GL_POINTS);
CHECK_GL_ERROR("transformGpuBufferData glBeginTransformFeedback\n"); CHECK_GL_ERROR("transformGpuBufferData glBeginTransformFeedback\n");
// draw array ----------------------------------------- // draw array -----------------------------------------
glDrawArrays(GL_POINTS, 0, count); glDrawArrays(GL_POINTS, 0, count);
CHECK_GL_ERROR("transformGpuBufferData DrawArray (%d)\n", count); CHECK_GL_ERROR("transformGpuBufferData DrawArray (%d)\n", count);
@ -578,7 +578,7 @@ void
OsdGlslKernelDispatcher::ComputeShader::ApplyBilinearVertexVerticesKernel( OsdGlslKernelDispatcher::ComputeShader::ApplyBilinearVertexVerticesKernel(
OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
int V_ITa_ofs, int offset, int start, int end) { int V_ITa_ofs, int offset, int start, int end) {
glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeVertex); glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeVertex);
glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs); glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs);
transformGpuBufferData(vertex, varying, offset, start, end); transformGpuBufferData(vertex, varying, offset, start, end);
@ -611,7 +611,7 @@ void
OsdGlslKernelDispatcher::ComputeShader::ApplyCatmarkVertexVerticesKernelB( OsdGlslKernelDispatcher::ComputeShader::ApplyCatmarkVertexVerticesKernelB(
OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
int V_IT_ofs, int V_ITa_ofs, int V_W_ofs, int offset, int start, int end) { int V_IT_ofs, int V_ITa_ofs, int V_W_ofs, int offset, int start, int end) {
glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeCatmarkVertexB); glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeCatmarkVertexB);
glUniform1i(_tableOffsetUniforms[V_IT], V_IT_ofs); glUniform1i(_tableOffsetUniforms[V_IT], V_IT_ofs);
glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs); glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs);
@ -623,7 +623,7 @@ void
OsdGlslKernelDispatcher::ComputeShader::ApplyCatmarkVertexVerticesKernelA( OsdGlslKernelDispatcher::ComputeShader::ApplyCatmarkVertexVerticesKernelA(
OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
int V_ITa_ofs, int V_W_ofs, int offset, bool pass, int start, int end) { int V_ITa_ofs, int V_W_ofs, int offset, bool pass, int start, int end) {
glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeVertexA); glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeVertexA);
glUniform1i(_uniformVertexPass, pass ? 1 : 0); glUniform1i(_uniformVertexPass, pass ? 1 : 0);
glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs); glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs);
@ -635,7 +635,7 @@ void
OsdGlslKernelDispatcher::ComputeShader::ApplyLoopEdgeVerticesKernel( OsdGlslKernelDispatcher::ComputeShader::ApplyLoopEdgeVerticesKernel(
OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
int E_IT_ofs, int E_W_ofs, int offset, int start, int end) { int E_IT_ofs, int E_W_ofs, int offset, int start, int end) {
glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeEdge); glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeEdge);
glUniform1i(_tableOffsetUniforms[E_IT], E_IT_ofs); glUniform1i(_tableOffsetUniforms[E_IT], E_IT_ofs);
glUniform1i(_tableOffsetUniforms[E_W], E_W_ofs); glUniform1i(_tableOffsetUniforms[E_W], E_W_ofs);
@ -646,7 +646,7 @@ void
OsdGlslKernelDispatcher::ComputeShader::ApplyLoopVertexVerticesKernelB( OsdGlslKernelDispatcher::ComputeShader::ApplyLoopVertexVerticesKernelB(
OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
int V_IT_ofs, int V_ITa_ofs, int V_W_ofs, int offset, int start, int end) { int V_IT_ofs, int V_ITa_ofs, int V_W_ofs, int offset, int start, int end) {
glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeLoopVertexB); glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeLoopVertexB);
glUniform1i(_tableOffsetUniforms[V_IT], V_IT_ofs); glUniform1i(_tableOffsetUniforms[V_IT], V_IT_ofs);
glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs); glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs);
@ -658,7 +658,7 @@ void
OsdGlslKernelDispatcher::ComputeShader::ApplyLoopVertexVerticesKernelA( OsdGlslKernelDispatcher::ComputeShader::ApplyLoopVertexVerticesKernelA(
OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
int V_ITa_ofs, int V_W_ofs, int offset, bool pass, int start, int end) { int V_ITa_ofs, int V_W_ofs, int offset, bool pass, int start, int end) {
glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeVertexA); glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeVertexA);
glUniform1i(_uniformVertexPass, pass ? 1 : 0); glUniform1i(_uniformVertexPass, pass ? 1 : 0);
glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs); glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs);

View File

@ -60,7 +60,7 @@
#if not defined(__APPLE__) #if not defined(__APPLE__)
#include <GL/gl.h> #include <GL/gl.h>
#else #else
#include <OpenGL/gl.h> #include <OpenGL/gl3.h>
#endif #endif
#include "../version.h" #include "../version.h"
@ -73,34 +73,41 @@ class OsdGlslKernelDispatcher : public OsdKernelDispatcher {
public: public:
OsdGlslKernelDispatcher(int levels); OsdGlslKernelDispatcher(int levels);
virtual ~OsdGlslKernelDispatcher(); virtual ~OsdGlslKernelDispatcher();
virtual void ApplyBilinearFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyBilinearFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyBilinearEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyBilinearEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyBilinearVertexVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyBilinearVertexVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyCatmarkFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyCatmarkEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyCatmarkVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyCatmarkVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const; virtual void ApplyCatmarkVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const;
virtual void ApplyLoopEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyLoopEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyLoopVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const; virtual void ApplyLoopVertexVerticesKernelB(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const;
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const; 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 CopyTable(int tableIndex, size_t size, const void *ptr); virtual void CopyTable(int tableIndex, size_t size, const void *ptr);
virtual void AllocateEditTables(int n) {}
virtual void UpdateEditTable(int tableIndex, const FarTable<unsigned int> &offsets, const FarTable<float> &values,
int operation, int primVarOffset, int primVarWidth) {}
virtual void OnKernelLaunch(); virtual void OnKernelLaunch();
virtual void OnKernelFinish(); virtual void OnKernelFinish();
@ -154,33 +161,33 @@ protected:
void ApplyCatmarkVertexVerticesKernelA(OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, int V_ITa_ofs, int V_W_ofs, int offset, bool pass, int start, int end); void ApplyCatmarkVertexVerticesKernelA(OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, int V_ITa_ofs, int V_W_ofs, int offset, bool pass, int start, int end);
void ApplyLoopEdgeVerticesKernel(OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, int E_IT_ofs, int E_W_ofs, int offset, int start, int end); void ApplyLoopEdgeVerticesKernel(OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, int E_IT_ofs, int E_W_ofs, int offset, int start, int end);
void ApplyLoopVertexVerticesKernelB(OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, int V_IT_ofs, int V_ITa_ofs, int V_W_ofs, int offset, int start, int end); void ApplyLoopVertexVerticesKernelB(OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, int V_IT_ofs, int V_ITa_ofs, int V_W_ofs, int offset, int start, int end);
void ApplyLoopVertexVerticesKernelA(OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, int V_ITa_ofs, int V_W_ofs, int offset, bool pass, int start, int end); void ApplyLoopVertexVerticesKernelA(OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, int V_ITa_ofs, int V_W_ofs, int offset, bool pass, int start, int end);
void UseProgram () const; void UseProgram () const;
struct Match { struct Match {
Match(int numVertexElements, int numVaryingElements) : Match(int numVertexElements, int numVaryingElements) :
_numVertexElements(numVertexElements), _numVaryingElements(numVaryingElements) { } _numVertexElements(numVertexElements), _numVaryingElements(numVaryingElements) { }
bool operator() (ComputeShader const & shader) { bool operator() (ComputeShader const & shader) {
return (shader._numVertexElements == _numVertexElements return (shader._numVertexElements == _numVertexElements
&& shader._numVaryingElements == _numVaryingElements); && shader._numVaryingElements == _numVaryingElements);
} }
int _numVertexElements, int _numVertexElements,
_numVaryingElements; _numVaryingElements;
}; };
friend struct Match; friend struct Match;
private: private:
void transformGpuBufferData(OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, void transformGpuBufferData(OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
GLint offset, int start, int end) const; GLint offset, int start, int end) const;
int _numVertexElements; int _numVertexElements;
@ -191,10 +198,10 @@ protected:
GLuint _uniformVertexPass; GLuint _uniformVertexPass;
GLuint _uniformIndexStart; GLuint _uniformIndexStart;
GLuint _uniformIndexOffset; GLuint _uniformIndexOffset;
GLuint _vertexUniform, GLuint _vertexUniform,
_varyingUniform; _varyingUniform;
// shader locations // shader locations
GLuint _subComputeFace, // general face-vertex kernel (all schemes) GLuint _subComputeFace, // general face-vertex kernel (all schemes)
_subComputeEdge, // edge-vertex kernel (catmark + loop schemes) _subComputeEdge, // edge-vertex kernel (catmark + loop schemes)
@ -216,9 +223,9 @@ protected:
ComputeShader * _shader; ComputeShader * _shader;
// texture for vertex // texture for vertex
GLuint _vertexTexture, GLuint _vertexTexture,
_varyingTexture; _varyingTexture;
OsdGpuVertexBuffer *_currentVertexBuffer, OsdGpuVertexBuffer *_currentVertexBuffer,
*_currentVaryingBuffer; *_currentVaryingBuffer;

View File

@ -68,8 +68,8 @@ uniform samplerBuffer _E0_S;
uniform samplerBuffer _V0_S; uniform samplerBuffer _V0_S;
uniform bool vertexPass; uniform bool vertexPass;
uniform int indexOffset = 0; // index offset for the level uniform int indexOffset = 0; // index offset for the level
uniform int indexStart = 0; // start index for given batch uniform int indexStart = 0; // start index for given batch
uniform int F_IT_ofs; uniform int F_IT_ofs;
uniform int F_ITa_ofs; uniform int F_ITa_ofs;
@ -83,8 +83,8 @@ uniform int V_W_ofs;
+-----+---------------------------------+----- +-----+---------------------------------+-----
n-1 | Level n |<batch range>| | n+1 n-1 | Level n |<batch range>| | n+1
+-----+---------------------------------+----- +-----+---------------------------------+-----
^ ^ ^ ^
indexOffset | indexOffset |
indexStart indexStart
*/ */
@ -107,9 +107,9 @@ uniform samplerBuffer varyingData; // float[NUM_VARYING]
out vec3 outPosition; out vec3 outPosition;
out vec3 outNormal; out vec3 outNormal;
#if NUM_VARYING > 0 #if NUM_VARYING > 0
out float outVaryingData[NUM_VARYING]; // output feedback (mapped as a subrange of vertices) out float outVaryingData[NUM_VARYING]; // output feedback (mapped as a subrange of vertices)
#endif #endif
//out vec3 outVaryingData; // output feedback (mapped as a subrange of vertices) //out vec3 outVaryingData; // output feedback (mapped as a subrange of vertices)
void clear(out Vertex v) void clear(out Vertex v)
{ {
@ -221,7 +221,7 @@ void catmarkComputeEdge()
#ifdef OPT_E0_S_VEC2 #ifdef OPT_E0_S_VEC2
float faceWeight = weight.y; float faceWeight = weight.y;
#else #else
float faceWeight = texelFetch(_E0_S, E_W_ofs/2+i*2+1).x; float faceWeight = texelFetch(_E0_S, E_W_ofs+i*2+1).x;
#endif #endif
addWithWeight(dst, readVertex(eidx.z), faceWeight); addWithWeight(dst, readVertex(eidx.z), faceWeight);
@ -292,8 +292,8 @@ void catmarkComputeVertexA()
? texelFetch(_V0_S, V_W_ofs+i).x ? texelFetch(_V0_S, V_W_ofs+i).x
: 1.0 - texelFetch(_V0_S, V_W_ofs+i).x; : 1.0 - texelFetch(_V0_S, V_W_ofs+i).x;
// In the case of fractional weight, the weight must be inverted since // In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the // the value is shared with the k_Smooth kernel (statistically the
// k_Smooth kernel runs much more often than this one) // k_Smooth kernel runs much more often than this one)
if (weight>0.0 && weight<1.0 && n > 0) if (weight>0.0 && weight<1.0 && n > 0)
weight=1.0-weight; weight=1.0-weight;
@ -336,7 +336,7 @@ void catmarkComputeVertexB()
Vertex dst; Vertex dst;
clear(dst); clear(dst);
addWithWeight(dst, readVertex(p), weight * wv); addWithWeight(dst, readVertex(p), weight * wv);
for(int j = 0; j < n; ++j){ for(int j = 0; j < n; ++j){
@ -372,7 +372,7 @@ void loopComputeVertexB()
Vertex dst; Vertex dst;
clear(dst); clear(dst);
addWithWeight(dst, readVertex(p), weight * (1.0-(beta*n))); addWithWeight(dst, readVertex(p), weight * (1.0-(beta*n)));
for(int j = 0; j < n; ++j){ for(int j = 0; j < n; ++j){

View File

@ -87,9 +87,14 @@ public:
virtual void CopyTable(int tableIndex, size_t size, const void *ptr) = 0; virtual void CopyTable(int tableIndex, size_t size, const void *ptr) = 0;
virtual void AllocateEditTables(int n) = 0;
virtual void UpdateEditTable(int tableIndex, const FarTable<unsigned int> &offsets, const FarTable<float> &values,
int operation, int primVarOffset, int primVarWidth) = 0;
virtual void OnKernelLaunch() = 0; virtual void OnKernelLaunch() = 0;
virtual void OnKernelFinish() = 0; virtual void OnKernelFinish() = 0;
virtual OsdVertexBuffer *InitializeVertexBuffer(int numElements, int count) = 0; virtual OsdVertexBuffer *InitializeVertexBuffer(int numElements, int count) = 0;
@ -101,12 +106,12 @@ public:
virtual void Synchronize() = 0; virtual void Synchronize() = 0;
template<class T> void UpdateTable(int tableIndex, const T & table) { template<class T> void UpdateTable(int tableIndex, const T & table) {
CopyTable(tableIndex, table.GetMemoryUsed(), table[0]); CopyTable(tableIndex, table.GetMemoryUsed(), table[0]);
_tableOffsets[tableIndex].resize(_maxLevel); _tableOffsets[tableIndex].resize(_maxLevel);
for (int i = 0; i < _maxLevel; ++i) for (int i = 0; i < _maxLevel; ++i)
_tableOffsets[tableIndex][i] = table[i] - table[0]; _tableOffsets[tableIndex][i] = (int)(table[i] - table[0]);
} }
static OsdKernelDispatcher *CreateKernelDispatcher( int levels, int kernel ) { static OsdKernelDispatcher *CreateKernelDispatcher( int levels, int kernel ) {
@ -123,7 +128,7 @@ public:
enum { E_IT, enum { E_IT,
E_W, E_W,
V_ITa, V_ITa,
V_IT, V_IT,
V_W, V_W,
F_IT, F_IT,
@ -165,7 +170,7 @@ protected:
static Factory &GetInstance() { static Factory &GetInstance() {
return _instance; return _instance;
} }
static Factory _instance; static Factory _instance;
protected: protected:
@ -187,6 +192,16 @@ protected:
protected: protected:
int _maxLevel; int _maxLevel;
std::vector<int> _tableOffsets[TABLE_MAX]; std::vector<int> _tableOffsets[TABLE_MAX];
struct VertexEditArrayInfo {
std::vector<int> offsetOffsets;
std::vector<int> valueOffsets;
std::vector<int> numEdits;
int operation;
int primVarOffset;
int primVarWidth;
};
std::vector<VertexEditArrayInfo> _edits;
}; };
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION

View File

@ -15,7 +15,7 @@
#define OSD_ERROR(...) printf(__VA_ARGS__); #define OSD_ERROR(...) printf(__VA_ARGS__);
//#define OSD_DEBUG(...) printf(__VA_ARGS__); //#define OSD_DEBUG(...) printf(__VA_ARGS__);
#define OSD_DEBUG(...) #define OSD_DEBUG(...)
#endif // OSD_LOCAL_H #endif // OSD_LOCAL_H

View File

@ -54,6 +54,13 @@
// exclude the implied warranties of merchantability, fitness for // exclude the implied warranties of merchantability, fitness for
// a particular purpose and non-infringement. // a particular purpose and non-infringement.
// //
#if not defined(__APPLE__)
#include <GL/glew.h>
#else
#include <OpenGL/gl3.h>
#endif
#include <string.h> #include <string.h>
#include "../version.h" #include "../version.h"
@ -67,15 +74,21 @@
namespace OpenSubdiv { namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION { namespace OPENSUBDIV_VERSION {
OsdMesh::OsdMesh() : _fMesh(NULL), _dispatcher(NULL) { } OsdMesh::OsdMesh() : _farMesh(NULL), _dispatcher(NULL) { }
OsdMesh::~OsdMesh() { OsdMesh::~OsdMesh() {
if(_dispatcher) if(_dispatcher)
delete _dispatcher; delete _dispatcher;
if(_fMesh) if(_farMesh)
delete _fMesh; delete _farMesh;
// delete ptex coordinates
for (int i=0; i<(int)_ptexCoordinates.size(); ++i) {
if (glIsTexture(_ptexCoordinates[i]))
glDeleteTextures(1,&_ptexCoordinates[i]);
}
} }
void void
@ -87,12 +100,12 @@ OsdMesh::createTables( FarSubdivisionTables<OsdVertex> const * tables ) {
_dispatcher->UpdateTable(OsdKernelDispatcher::E_W, tables->Get_E_W()); _dispatcher->UpdateTable(OsdKernelDispatcher::E_W, tables->Get_E_W());
_dispatcher->UpdateTable(OsdKernelDispatcher::V_W, tables->Get_V_W()); _dispatcher->UpdateTable(OsdKernelDispatcher::V_W, tables->Get_V_W());
if ( const FarCatmarkSubdivisionTables<OsdVertex> * cctable = if ( const FarCatmarkSubdivisionTables<OsdVertex> * cctable =
dynamic_cast<const FarCatmarkSubdivisionTables<OsdVertex>*>(tables) ) { dynamic_cast<const FarCatmarkSubdivisionTables<OsdVertex>*>(tables) ) {
// catmark // catmark
_dispatcher->UpdateTable(OsdKernelDispatcher::F_IT, cctable->Get_F_IT()); _dispatcher->UpdateTable(OsdKernelDispatcher::F_IT, cctable->Get_F_IT());
_dispatcher->UpdateTable(OsdKernelDispatcher::F_ITa, cctable->Get_F_ITa()); _dispatcher->UpdateTable(OsdKernelDispatcher::F_ITa, cctable->Get_F_ITa());
} else if ( const FarBilinearSubdivisionTables<OsdVertex> * btable = } else if ( const FarBilinearSubdivisionTables<OsdVertex> * btable =
dynamic_cast<const FarBilinearSubdivisionTables<OsdVertex>*>(tables) ) { dynamic_cast<const FarBilinearSubdivisionTables<OsdVertex>*>(tables) ) {
// bilinear // bilinear
_dispatcher->UpdateTable(OsdKernelDispatcher::F_IT, btable->Get_F_IT()); _dispatcher->UpdateTable(OsdKernelDispatcher::F_IT, btable->Get_F_IT());
@ -102,8 +115,20 @@ OsdMesh::createTables( FarSubdivisionTables<OsdVertex> const * tables ) {
_dispatcher->CopyTable(OsdKernelDispatcher::F_IT, 0, NULL); _dispatcher->CopyTable(OsdKernelDispatcher::F_IT, 0, NULL);
_dispatcher->CopyTable(OsdKernelDispatcher::F_ITa, 0, NULL); _dispatcher->CopyTable(OsdKernelDispatcher::F_ITa, 0, NULL);
} }
}
CHECK_GL_ERROR("Mesh, update tables\n"); void
OsdMesh::createEditTables( FarVertexEditTables<OsdVertex> const *editTables ) {
int numEditBatches = editTables->GetNumBatches();
_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());
}
} }
bool bool
@ -119,31 +144,60 @@ OsdMesh::Create(OsdHbrMesh *hbrMesh, int level, int kernel, std::vector<int> * r
} }
_level = level; _level = level;
// create Far mesh // create Far mesh
OSD_DEBUG("Create MeshFactory\n"); OSD_DEBUG("Create MeshFactory\n");
FarMeshFactory<OsdVertex> meshFactory(hbrMesh, _level); FarMeshFactory<OsdVertex> meshFactory(hbrMesh, _level);
_fMesh = meshFactory.Create(_dispatcher); _farMesh = meshFactory.Create(_dispatcher);
OSD_DEBUG("PREP: NumCoarseVertex = %d\n", _fMesh->GetNumCoarseVertices()); OSD_DEBUG("PREP: NumCoarseVertex = %d\n", _farMesh->GetNumCoarseVertices());
OSD_DEBUG("PREP: NumVertex = %d\n", _fMesh->GetNumVertices()); OSD_DEBUG("PREP: NumVertex = %d\n", _farMesh->GetNumVertices());
createTables( _farMesh->GetSubdivision() );
FarVertexEditTables<OsdVertex> const *editTables = _farMesh->GetVertexEdit();
if (editTables)
createEditTables( editTables );
createTables( _fMesh->GetSubdivision() );
// copy the remapping table if the client needs to remap vertex indices from // copy the remapping table if the client needs to remap vertex indices from
// Osd to Hbr for comparison / regression purposes. // Osd to Hbr for comparison / regression purposes.
if (remap) if (remap)
(*remap)=meshFactory.GetRemappingTable(); (*remap)=meshFactory.GetRemappingTable();
// create ptex coordinates if exists in hbr
for (int i=0; i<(int)_ptexCoordinates.size(); ++i) {
if (glIsTexture(_ptexCoordinates[i]))
glDeleteTextures(1,&_ptexCoordinates[i]);
}
_ptexCoordinates.resize(level, 0);
for (int i=0; i<level; ++i) {
const std::vector<int> & ptexCoordinates = _farMesh->GetPtexCoordinates(i+1);
if (ptexCoordinates.empty())
continue;
int size = (int)ptexCoordinates.size() * sizeof(GLint);
const void *data = &ptexCoordinates[0];
GLuint buffer;
glGenBuffers(1, & buffer );
glBindBuffer( GL_TEXTURE_BUFFER, buffer );
glBufferData( GL_TEXTURE_BUFFER, size, data, GL_STATIC_DRAW);
glGenTextures(1, & _ptexCoordinates[i]);
glBindTexture( GL_TEXTURE_BUFFER, _ptexCoordinates[i]);
glTexBuffer( GL_TEXTURE_BUFFER, GL_RG32I, buffer);
glDeleteBuffers(1, & buffer );
}
return true; return true;
} }
OsdVertexBuffer * OsdVertexBuffer *
OsdMesh::InitializeVertexBuffer(int numElements) OsdMesh::InitializeVertexBuffer(int numElements) {
{
if (!_dispatcher) return NULL; if (!_dispatcher)
return NULL;
return _dispatcher->InitializeVertexBuffer(numElements, GetTotalVertices()); return _dispatcher->InitializeVertexBuffer(numElements, GetTotalVertices());
} }
@ -154,7 +208,7 @@ OsdMesh::Subdivide(OsdVertexBuffer *vertex, OsdVertexBuffer *varying) {
_dispatcher->OnKernelLaunch(); _dispatcher->OnKernelLaunch();
_fMesh->Subdivide(_level+1); _farMesh->Subdivide(_level+1);
_dispatcher->OnKernelFinish(); _dispatcher->OnKernelFinish();

View File

@ -83,6 +83,8 @@ typedef HbrVertex<OsdVertex> OsdHbrVertex;
typedef HbrHalfedge<OsdVertex> OsdHbrHalfedge; typedef HbrHalfedge<OsdVertex> OsdHbrHalfedge;
typedef HbrFace<OsdVertex> OsdHbrFace; typedef HbrFace<OsdVertex> OsdHbrFace;
class OsdPtexIndicesBuffer;
class OsdMesh { class OsdMesh {
public: public:
@ -90,16 +92,18 @@ public:
virtual ~OsdMesh(); virtual ~OsdMesh();
// Given a valid HbrMesh, create an OsdMesh // Given a valid HbrMesh, create an OsdMesh
// - cappable of densely refining up to 'level' // - capable of densely refining up to 'level'
// - subdivision kernel one of (kCPU, kOPENMP, kCUDA, kGLSL, kCL) // - subdivision kernel one of (kCPU, kOPENMP, kCUDA, kGLSL, kCL)
// - optional "remapping" vector that connects Osd and Hbr vertex indices // - optional "remapping" vector that connects Osd and Hbr vertex indices
// (for regression) // (for regression)
bool Create(OsdHbrMesh *hbrMesh, int level, int kernel, std::vector<int> * remap=0); bool Create(OsdHbrMesh *hbrMesh, int level, int kernel, std::vector<int> * remap=0);
FarMesh<OsdVertex> *GetFarMesh() { return _fMesh; } FarMesh<OsdVertex> *GetFarMesh() { return _farMesh; }
OsdVertexBuffer *InitializeVertexBuffer(int numElements); int GetLevel() const { return _level; }
OsdVertexBuffer * InitializeVertexBuffer(int numElements);
// for non-interleaved vertex data // for non-interleaved vertex data
void Subdivide(OsdVertexBuffer *vertex, OsdVertexBuffer *varying = NULL); void Subdivide(OsdVertexBuffer *vertex, OsdVertexBuffer *varying = NULL);
@ -111,19 +115,28 @@ public:
void Synchronize(); void Synchronize();
int GetTotalVertices() const { return _fMesh->GetNumVertices(); } int GetTotalVertices() const { return _farMesh->GetNumVertices(); }
int GetNumCoarseVertices() const { return _fMesh->GetNumCoarseVertices(); } int GetNumCoarseVertices() const { return _farMesh->GetNumCoarseVertices(); }
// Returns the texture buffer containing the ptex face index for each face of
// the mesh.
GLuint GetPtexCoordinatesTextureBuffer(int level) const { return _ptexCoordinates[level-1]; }
protected: protected:
void createTables( FarSubdivisionTables<OsdVertex> const * tables ); void createTables( FarSubdivisionTables<OsdVertex> const * tables );
FarMesh<OsdVertex> *_fMesh; void createEditTables( FarVertexEditTables<OsdVertex> const * editTables );
FarMesh<OsdVertex> *_farMesh;
int _level; int _level;
OsdKernelDispatcher * _dispatcher; OsdKernelDispatcher * _dispatcher;
std::vector<GLuint> _ptexCoordinates; // index of the coarse parent face + sub-face coordinates (cf. far)
}; };
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION

1062
opensubdiv/osd/pTexture.cpp Normal file

File diff suppressed because it is too large Load Diff

159
opensubdiv/osd/pTexture.h Normal file
View File

@ -0,0 +1,159 @@
//
// 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 OSD_PTEXTURE_H
#define OSD_PTEXTURE_H
#if not defined(__APPLE__)
#if defined(_WIN32)
#include <windows.h>
#endif
#include <GL/gl.h>
#else
#include <OpenGL/gl3.h>
#endif
#include "../version.h"
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
class PtexTexture;
class OsdMesh;
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
// OsdPTexture : implements simple support for ptex textures
//
// The current implementation declares _texels as a GL_TEXTURE_2D_ARRAY of
// n pages of a resolution that matches that of the largest face in the PTex file.
//
// Two GL_TEXTURE_BUFFER constructs are used
// as lookup tables :
// * _pages stores the array index in which a given face is located
// * _layout stores 4 float coordinates : top-left corner and width/height for each face
//
// GLSL fragments use gl_PrimitiveID and gl_TessCoords to access the _pages and _layout
// indirection tables, which provide then texture coordinates for the texels stored in
// the _texels texture array.
//
// Hbr provides per-face support for a ptex face indexing scheme. This
// class provides a container that can be initialized by an OsdMesh and
// instantiated in GPU memory as a texture buffer object that can be
// accessed by GLSL shaders.
//
class OsdPTexture {
public:
static OsdPTexture * Create( PtexTexture * reader, unsigned long int targetMemory );
// Returns the texture buffer containing the lookup table associate each ptex
// face index with its 3D texture page in the texels texture array.
GLuint GetPagesTextureBuffer() const { return _pages; }
// Returns the texture buffer containing the layout of the ptex faces in the
// texels texture array.
GLuint GetLayoutTextureBuffer() const { return _layout; }
// Returns the texels texture array.
GLuint GetTexelsTexture() const { return _texels; }
~OsdPTexture( );
// get/set guttering control variables
static int GetGutterWidth() { return _gutterWidth; }
static int GetPageMargin() { return _pageMargin; }
static int GetGutterDebug() { return _gutterDebug; }
static void SetGutterWidth(int width) { _gutterWidth = width; }
static void SetPageMargin(int margin) { _pageMargin = margin; }
static void SetGutterDebug(int debug) { _gutterDebug = debug; }
private:
OsdPTexture();
// Non-copyable, so these are not implemented:
OsdPTexture(OsdPTexture const &);
OsdPTexture & operator=(OsdPTexture const &);
GLsizei _width, // widht / height / depth of the 3D texel buffer
_height,
_depth;
GLint _format; // texel color format
GLuint _pages, // per-face page indices into the texel array
_layout, // per-face lookup table (vec4 : top-left corner & width / height)
_texels; // texel data
static int _gutterWidth, _pageMargin, _gutterDebug;
};
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif // OSD_PTEXTURE_H

View File

@ -1,7 +1,9 @@
#ifndef GSD_VERTEX_H #ifndef OSD_VERTEX_H
#define GSD_VERTEX_H #define OSD_VERTEX_H
#include "../version.h" #include "../version.h"
#include "../hbr/face.h"
#include "../hbr/vertexEdit.h"
namespace OpenSubdiv { namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION { namespace OPENSUBDIV_VERSION {
@ -13,8 +15,10 @@ public:
OsdVertex(const OsdVertex &src) {} OsdVertex(const OsdVertex &src) {}
void AddWithWeight(const OsdVertex & i, float weight, void * = 0) {} void AddWithWeight(const OsdVertex & i, float weight, void * = 0) {}
void AddVaryingWithWeight(const OsdVertex & i, float weight, void * = 0) {} void AddVaryingWithWeight(const OsdVertex & i, float weight, void * = 0) {}
void Clear(void * = 0) {} void Clear(void * = 0) {}
void ApplyVertexEdit(const OpenSubdiv::HbrVertexEdit<OsdVertex> &) { }
void ApplyMovingVertexEdit(const OpenSubdiv::HbrMovingVertexEdit<OsdVertex> &) { }
}; };
} // end namespace OPENSUBDIV_VERSION } // end namespace OPENSUBDIV_VERSION
@ -22,4 +26,4 @@ using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv } // end namespace OpenSubdiv
#endif // GSD_VERTEX_H #endif // OSD_VERTEX_H

View File

@ -1,20 +1,75 @@
//
// 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.
//
#include "../version.h" #include "../version.h"
#if not defined(__APPLE__) #if not defined(__APPLE__)
#include <GL/glew.h> #include <GL/glew.h>
#else #else
#include <OpenGL/gl.h> #include <OpenGL/gl3.h>
#endif #endif
#include "vertexBuffer.h" #include "../osd/vertexBuffer.h"
#include <iostream> #include <iostream>
namespace OpenSubdiv { namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION { namespace OPENSUBDIV_VERSION {
OsdVertexBuffer::~OsdVertexBuffer() OsdVertexBuffer::~OsdVertexBuffer() {
{
} }
OsdGpuVertexBuffer::OsdGpuVertexBuffer(int numElements, int numVertices) : OsdGpuVertexBuffer::OsdGpuVertexBuffer(int numElements, int numVertices) :
@ -28,21 +83,30 @@ OsdGpuVertexBuffer::OsdGpuVertexBuffer(int numElements, int numVertices) :
} }
void void
OsdGpuVertexBuffer::UpdateData(const float *src, int numVertices) OsdGpuVertexBuffer::UpdateData(const float *src, int numVertices) {
{
glBindBuffer(GL_ARRAY_BUFFER, _vbo); glBindBuffer(GL_ARRAY_BUFFER, GetGpuBuffer());
float * pointer = (float*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); float * pointer = (float*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
memcpy(pointer, src, _numElements * numVertices * sizeof(float)); memcpy(pointer, src, GetNumElements() * numVertices * sizeof(float));
glUnmapBuffer(GL_ARRAY_BUFFER); glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
} }
OsdGpuVertexBuffer::~OsdGpuVertexBuffer() void
{ OsdGpuVertexBuffer::GetBufferData(float * data, int firstVert, int numVerts) {
glDeleteBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, GetGpuBuffer());
glGetBufferSubData(GL_ARRAY_BUFFER, GetNumElements() * firstVert * sizeof(float),
GetNumElements() * numVerts * sizeof(float),
data);
glBindBuffer(GL_ARRAY_BUFFER, 0);
} }
OsdGpuVertexBuffer::~OsdGpuVertexBuffer() {
glDeleteBuffers(1, &_vbo);
}
OsdCpuVertexBuffer::OsdCpuVertexBuffer(int numElements, int numVertices) : OsdCpuVertexBuffer::OsdCpuVertexBuffer(int numElements, int numVertices) :
OsdVertexBuffer(numElements), _cpuVbo(NULL), _vboSize(0), _vbo(0) OsdVertexBuffer(numElements), _cpuVbo(NULL), _vboSize(0), _vbo(0)
@ -51,27 +115,29 @@ OsdCpuVertexBuffer::OsdCpuVertexBuffer(int numElements, int numVertices) :
_cpuVbo = new float[numElements * numVertices]; _cpuVbo = new float[numElements * numVertices];
} }
OsdCpuVertexBuffer::~OsdCpuVertexBuffer() OsdCpuVertexBuffer::~OsdCpuVertexBuffer() {
{
delete [] _cpuVbo; delete [] _cpuVbo;
if (_vbo) if (_vbo)
glDeleteBuffers(1, &_vbo); glDeleteBuffers(1, &_vbo);
} }
void void
OsdCpuVertexBuffer::UpdateData(const float *src, int numVertices) OsdCpuVertexBuffer::UpdateData(const float *src, int numVertices) {
{
memcpy(_cpuVbo, src, _numElements * numVertices * sizeof(float)); memcpy(_cpuVbo, src, _numElements * numVertices * sizeof(float));
} }
GLuint GLuint
OsdCpuVertexBuffer::GetGpuBuffer() OsdCpuVertexBuffer::GetGpuBuffer() {
{
if (!_vbo) if (!_vbo)
glGenBuffers(1, &_vbo); glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo); glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, _vboSize * sizeof(float), _cpuVbo, GL_STREAM_DRAW); glBufferData(GL_ARRAY_BUFFER, _vboSize * sizeof(float), _cpuVbo, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
return _vbo; return _vbo;
} }

View File

@ -1,3 +1,59 @@
//
// 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 OSD_VERTEX_BUFFER_H #ifndef OSD_VERTEX_BUFFER_H
#define OSD_VERTEX_BUFFER_H #define OSD_VERTEX_BUFFER_H
@ -7,7 +63,7 @@
#endif #endif
#include <GL/gl.h> #include <GL/gl.h>
#else #else
#include <OpenGL/gl.h> #include <OpenGL/gl3.h>
#endif #endif
#include <string.h> // memcpy (tobe moved to cpp) #include <string.h> // memcpy (tobe moved to cpp)
@ -44,6 +100,10 @@ public:
return _vbo; return _vbo;
} }
// Copies the vertex data from the compute device into
// the pointer.
void GetBufferData(float * data, int firstVert, int numVerts);
protected: protected:
GLuint _vbo; GLuint _vbo;
}; };
@ -51,7 +111,7 @@ protected:
class OsdCpuVertexBuffer : public OsdVertexBuffer { class OsdCpuVertexBuffer : public OsdVertexBuffer {
public: public:
OsdCpuVertexBuffer(int numElements, int numVertices); OsdCpuVertexBuffer(int numElements, int numVertices);
virtual ~OsdCpuVertexBuffer(); virtual ~OsdCpuVertexBuffer();
virtual void UpdateData(const float *src, int numVertices); virtual void UpdateData(const float *src, int numVertices);

View File

@ -69,11 +69,11 @@ std::string stringify( std::string const & line ) {
for (int i=0; i<(int)line.size(); ++i) { for (int i=0; i<(int)line.size(); ++i) {
// escape double quotes // escape double quotes
if (line[i]=='"') { if (line[i]=='"') {
s << '\\' ; s << '\\' ;
inconstant = inconstant ? false : true; inconstant = inconstant ? false : true;
} }
// escape backslash // escape backslash
if (inconstant and line[i]=='\\') if (inconstant and line[i]=='\\')
s << '\\' ; s << '\\' ;

View File

@ -58,6 +58,6 @@
#ifndef OPENSUBDIV_VERSION_H #ifndef OPENSUBDIV_VERSION_H
#define OPENSUBDIV_VERSION_H #define OPENSUBDIV_VERSION_H
#define OPENSUBDIV_VERSION v1_0 #define OPENSUBDIV_VERSION v1_1
#endif /* OPENSUBDIV_VERSION_H */ #endif /* OPENSUBDIV_VERSION_H */

View File

@ -57,4 +57,28 @@
add_subdirectory(far_regression) add_subdirectory(far_regression)
add_subdirectory(osd_regression) if( OPENGL_FOUND AND GLEW_FOUND AND GLUT_FOUND)
add_subdirectory(osd_regression)
else()
set(MISSING "")
if (NOT OPENGL_FOUND)
list(APPEND MISSING OpenGL)
endif()
if (NOT GLEW_FOUND)
list(APPEND MISSING glew)
endif()
if (NOT GLUT_FOUND)
list(APPEND MISSING glut)
endif()
message(WARNING
"The following libraries could not be found : ${MISSING}. "
"The osd regression test will not be available. "
"If you have these libraries installed, please specify their "
"path to cmake (through the GLEW_LOCATION and GLUT_LOCATION "
"command line arguments or environment variables)."
)
endif()

View File

@ -57,6 +57,9 @@
#ifndef SHAPE_UTILS_H #ifndef SHAPE_UTILS_H
#define SHAPE_UTILS_H #define SHAPE_UTILS_H
#include <hbr/vertexEdit.h>
#include <hbr/cornerEdit.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -64,14 +67,14 @@
#include <string> #include <string>
#include <vector> #include <vector>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static char const * sgets( char * s, int size, char ** stream ) { static char const * sgets( char * s, int size, char ** stream ) {
for (int i=0; i<size; ++i) { for (int i=0; i<size; ++i) {
if ( (*stream)[i]=='\n' or (*stream)[i]=='\0') { if ( (*stream)[i]=='\n' or (*stream)[i]=='\0') {
memcpy(s, *stream, i); memcpy(s, *stream, i);
s[i]='\0'; s[i]='\0';
if ((*stream)[i]=='\0') if ((*stream)[i]=='\0')
return 0; return 0;
else { else {
@ -83,57 +86,57 @@ static char const * sgets( char * s, int size, char ** stream ) {
return 0; return 0;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
struct shape { struct shape {
struct tag { struct tag {
static tag * parseTag( char const * stream ); static tag * parseTag( char const * stream );
std::string name; std::string name;
std::vector<int> intargs; std::vector<int> intargs;
std::vector<float> floatargs; std::vector<float> floatargs;
std::vector<std::string> stringargs; std::vector<std::string> stringargs;
}; };
static shape * parseShape(char const * shapestr, int axis=1); static shape * parseShape(char const * shapestr, int axis=1);
~shape(); ~shape();
int getNverts() const { return (int)verts.size()/3; } int getNverts() const { return (int)verts.size()/3; }
int getNfaces() const { return (int)nvertsPerFace.size(); } int getNfaces() const { return (int)nvertsPerFace.size(); }
std::vector<float> verts; std::vector<float> verts;
std::vector<float> uvs; std::vector<float> uvs;
std::vector<int> nvertsPerFace; std::vector<int> nvertsPerFace;
std::vector<int> faceverts; std::vector<int> faceverts;
std::vector<int> faceuvs; std::vector<int> faceuvs;
std::vector<tag *> tags; std::vector<tag *> tags;
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
shape::~shape() { shape::~shape() {
for (int i=0; i<(int)tags.size(); ++i) for (int i=0; i<(int)tags.size(); ++i)
delete tags[i]; delete tags[i];
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
shape::tag * shape::tag::parseTag(char const * line) { shape::tag * shape::tag::parseTag(char const * line) {
tag * t = 0; tag * t = 0;
const char* cp = &line[2]; const char* cp = &line[2];
char name[50]; char name[50];
while (*cp == ' ') cp++; while (*cp == ' ') cp++;
if (sscanf(cp, "%s", &name )!=1) return t; if (sscanf(cp, "%s", name )!=1) return t;
while (*cp && *cp != ' ') cp++; while (*cp && *cp != ' ') cp++;
int nints=0, nfloats=0, nstrings=0; int nints=0, nfloats=0, nstrings=0;
while (*cp == ' ') cp++; while (*cp == ' ') cp++;
if (sscanf(cp, "%d/%d/%d", &nints, &nfloats, &nstrings)!=3) return t; if (sscanf(cp, "%d/%d/%d", &nints, &nfloats, &nstrings)!=3) return t;
while (*cp && *cp != ' ') cp++; while (*cp && *cp != ' ') cp++;
std::vector<int> intargs; std::vector<int> intargs;
for (int i=0; i<nints; ++i) { for (int i=0; i<nints; ++i) {
@ -141,7 +144,7 @@ shape::tag * shape::tag::parseTag(char const * line) {
while (*cp == ' ') cp++; while (*cp == ' ') cp++;
if (sscanf(cp, "%d", &val)!=1) return t; if (sscanf(cp, "%d", &val)!=1) return t;
intargs.push_back(val); intargs.push_back(val);
while (*cp && *cp != ' ') cp++; while (*cp && *cp != ' ') cp++;
} }
std::vector<float> floatargs; std::vector<float> floatargs;
@ -150,16 +153,16 @@ shape::tag * shape::tag::parseTag(char const * line) {
while (*cp == ' ') cp++; while (*cp == ' ') cp++;
if (sscanf(cp, "%f", &val)!=1) return t; if (sscanf(cp, "%f", &val)!=1) return t;
floatargs.push_back(val); floatargs.push_back(val);
while (*cp && *cp != ' ') cp++; while (*cp && *cp != ' ') cp++;
} }
std::vector<std::string> stringargs; std::vector<std::string> stringargs;
for (int i=0; i<nstrings; ++i) { for (int i=0; i<nstrings; ++i) {
char * val; char val[512];
while (*cp == ' ') cp++; while (*cp == ' ') cp++;
if (sscanf(cp, "%s", &val)!=1) return t; if (sscanf(cp, "%s", val)!=1) return t;
stringargs.push_back(val); stringargs.push_back(val);
while (*cp && *cp != ' ') cp++; while (*cp && *cp != ' ') cp++;
} }
t = new shape::tag; t = new shape::tag;
@ -167,53 +170,53 @@ shape::tag * shape::tag::parseTag(char const * line) {
t->intargs = intargs; t->intargs = intargs;
t->floatargs = floatargs; t->floatargs = floatargs;
t->stringargs = stringargs; t->stringargs = stringargs;
return t; return t;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
shape * shape::parseShape(char const * shapestr, int axis ) { shape * shape::parseShape(char const * shapestr, int axis ) {
shape * s = new shape; shape * s = new shape;
char * str=const_cast<char *>(shapestr), line[256]; char * str=const_cast<char *>(shapestr), line[256];
bool done = false; bool done = false;
while( not done ) while( not done )
{ done = sgets(line, sizeof(line), &str)==0; { done = sgets(line, sizeof(line), &str)==0;
char* end = &line[strlen(line)-1]; char* end = &line[strlen(line)-1];
if (*end == '\n') *end = '\0'; // strip trailing nl if (*end == '\n') *end = '\0'; // strip trailing nl
float x, y, z, u, v; float x, y, z, u, v;
switch (line[0]) { switch (line[0]) {
case 'v': switch (line[1]) case 'v': switch (line[1])
{ case ' ': if(sscanf(line, "v %f %f %f", &x, &y, &z) == 3) { case ' ': if(sscanf(line, "v %f %f %f", &x, &y, &z) == 3)
s->verts.push_back(x); s->verts.push_back(x);
switch( axis ) { switch( axis ) {
case 0 : s->verts.push_back(-z); case 0 : s->verts.push_back(-z);
s->verts.push_back(y); break; s->verts.push_back(y); break;
case 1 : s->verts.push_back(y); case 1 : s->verts.push_back(y);
s->verts.push_back(z); break; s->verts.push_back(z); break;
} break; } break;
case 't': if(sscanf(line, "vt %f %f", &u, &v) == 2) { case 't': if(sscanf(line, "vt %f %f", &u, &v) == 2) {
s->uvs.push_back(u); s->uvs.push_back(u);
s->uvs.push_back(v); s->uvs.push_back(v);
} break; } break;
case 'n' : break; // skip normals for now case 'n' : break; // skip normals for now
} }
break; break;
case 'f': if(line[1] == ' ') { case 'f': if(line[1] == ' ') {
int vi, ti, ni; int vi, ti, ni;
const char* cp = &line[2]; const char* cp = &line[2];
while (*cp == ' ') cp++; while (*cp == ' ') cp++;
int nverts = 0, nitems=0; int nverts = 0, nitems=0;
while( (nitems=sscanf(cp, "%d/%d/%d", &vi, &ti, &ni))>0) { while( (nitems=sscanf(cp, "%d/%d/%d", &vi, &ti, &ni))>0) {
nverts++; nverts++;
s->faceverts.push_back(vi-1); s->faceverts.push_back(vi-1);
if(nitems >= 1) s->faceuvs.push_back(ti-1); if(nitems >= 1) s->faceuvs.push_back(ti-1);
while (*cp && *cp != ' ') cp++; while (*cp && *cp != ' ') cp++;
while (*cp == ' ') cp++; while (*cp == ' ') cp++;
} }
s->nvertsPerFace.push_back(nverts); s->nvertsPerFace.push_back(nverts);
} }
break; break;
case 't' : if(line[1] == ' ') { case 't' : if(line[1] == ' ') {
@ -226,19 +229,19 @@ shape * shape::parseShape(char const * shapestr, int axis ) {
return s; return s;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template <class T> template <class T>
void applyTags( OpenSubdiv::HbrMesh<T> * mesh, shape const * sh ) { void applyTags( OpenSubdiv::HbrMesh<T> * mesh, shape const * sh ) {
for (int i=0; i<(int)sh->tags.size(); ++i) { for (int i=0; i<(int)sh->tags.size(); ++i) {
shape::tag * t = sh->tags[i]; shape::tag * t = sh->tags[i];
if (t->name=="crease") { if (t->name=="crease") {
for (int j=0; j<(int)t->intargs.size()-1; ++j) { for (int j=0; j<(int)t->intargs.size()-1; j += 2) {
OpenSubdiv::HbrVertex<T> * v = mesh->GetVertex( t->intargs[j] ), OpenSubdiv::HbrVertex<T> * v = mesh->GetVertex( t->intargs[j] ),
* w = mesh->GetVertex( t->intargs[j+1] ); * w = mesh->GetVertex( t->intargs[j+1] );
OpenSubdiv::HbrHalfedge<T> * e = 0; OpenSubdiv::HbrHalfedge<T> * e = 0;
if( v && w ) { if( v && w ) {
if( !(e = v->GetEdge(w) ) ) if( !(e = v->GetEdge(w) ) )
e = w->GetEdge(v); e = w->GetEdge(v);
if(e) { if(e) {
@ -270,7 +273,7 @@ void applyTags( OpenSubdiv::HbrMesh<T> * mesh, shape const * sh ) {
printf("expecting 1 integer for \"interpolateboundary\" tag n. %d\n", i); printf("expecting 1 integer for \"interpolateboundary\" tag n. %d\n", i);
continue; continue;
} }
switch( t->intargs[0] ) { switch( t->intargs[0] ) {
case 0 : mesh->SetInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryNone); break; case 0 : mesh->SetInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryNone); break;
case 1 : mesh->SetInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryEdgeAndCorner); break; case 1 : mesh->SetInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryEdgeAndCorner); break;
case 2 : mesh->SetInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryEdgeOnly); break; case 2 : mesh->SetInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryEdgeOnly); break;
@ -282,20 +285,20 @@ void applyTags( OpenSubdiv::HbrMesh<T> * mesh, shape const * sh ) {
else else
printf( "expecting single int argument for \"facevaryingpropagatecorners\"\n" ); printf( "expecting single int argument for \"facevaryingpropagatecorners\"\n" );
} else if (t->name=="creasemethod") { } else if (t->name=="creasemethod") {
OpenSubdiv::HbrCatmarkSubdivision<T> * scheme = OpenSubdiv::HbrCatmarkSubdivision<T> * scheme =
dynamic_cast<OpenSubdiv::HbrCatmarkSubdivision<T> *>( mesh->GetSubdivision() ); dynamic_cast<OpenSubdiv::HbrCatmarkSubdivision<T> *>( mesh->GetSubdivision() );
if (not scheme) { if (not scheme) {
printf("the \"creasemethod\" tag can only be applied to Catmark meshes\n"); printf("the \"creasemethod\" tag can only be applied to Catmark meshes\n");
continue; continue;
} }
if ((int)t->stringargs.size()==0) { if ((int)t->stringargs.size()==0) {
printf("the \"creasemethod\" tag expects a string argument\n"); printf("the \"creasemethod\" tag expects a string argument\n");
continue; continue;
} }
if( t->stringargs[0]=="normal" ) if( t->stringargs[0]=="normal" )
scheme->SetTriangleSubdivisionMethod( scheme->SetTriangleSubdivisionMethod(
OpenSubdiv::HbrCatmarkSubdivision<T>::k_Old); OpenSubdiv::HbrCatmarkSubdivision<T>::k_Old);
@ -304,12 +307,140 @@ void applyTags( OpenSubdiv::HbrMesh<T> * mesh, shape const * sh ) {
OpenSubdiv::HbrCatmarkSubdivision<T>::k_New); OpenSubdiv::HbrCatmarkSubdivision<T>::k_New);
else else
printf("the \"creasemethod\" tag only accepts \"normal\" or \"chaikin\" as value (%s)\n", t->stringargs[0].c_str()); printf("the \"creasemethod\" tag only accepts \"normal\" or \"chaikin\" as value (%s)\n", t->stringargs[0].c_str());
} else if (t->name=="vertexedit" or t->name=="edgeedit") { } else if (t->name=="vertexedit" or t->name=="edgeedit") {
printf("hierarchical edits not supported (yet)\n"); int nops = 0;
int floatstride = 0;
int maxfloatwidth = 0;
std::vector<typename OpenSubdiv::HbrHierarchicalEdit<T>::Operation > ops;
std::vector<std::string> opnames;
std::vector<std::string> varnames;
std::vector<typename OpenSubdiv::HbrHierarchicalEdit<T>::Operation > opmodifiers;
std::vector<int> floatwidths;
std::vector<bool> isP;
std::vector<int> vvindex;
for (int j=0; j<(int)t->stringargs.size(); j+=3) {
const std::string & opname = t->stringargs[j+2];
const std::string & opmodifiername = t->stringargs[j];
const std::string & varname = t->stringargs[j+1];
typename OpenSubdiv::HbrHierarchicalEdit<T>::Operation opmodifier = OpenSubdiv::HbrVertexEdit<T>::Set;
if (opmodifiername == "set") {
opmodifier = OpenSubdiv::HbrHierarchicalEdit<T>::Set;
} else if (opmodifiername == "add") {
opmodifier = OpenSubdiv::HbrHierarchicalEdit<T>::Add;
} else if (opmodifiername == "subtract") {
opmodifier = OpenSubdiv::HbrHierarchicalEdit<T>::Subtract;
} else {
printf("invalid modifier %s\n", opmodifiername.c_str());
continue;
}
if (t->name=="vertexedit" && opname=="value" || opname=="sharpness") {
nops++;
// only varname="P" is supported here for now.
if (varname != "P") continue;
vvindex.push_back(0);
isP.push_back(true);
opnames.push_back(opname);
opmodifiers.push_back(opmodifier);
varnames.push_back(varname);
if (opname=="sharpness") {
floatwidths.push_back(1);
floatstride += 1;
} else {
// assuming width of P == 3. should be replaced with 'P 0 3' like declaration
int numElements = 3;
maxfloatwidth = std::max(maxfloatwidth, numElements);
floatwidths.push_back(numElements);
floatstride += numElements;
}
} else {
printf("%s tag specifies invalid operation '%s %s' on Subdivmesh\n", t->name.c_str(), opmodifiername.c_str(), opname.c_str());
}
}
float *xformed = (float*)alloca(maxfloatwidth * sizeof(float));
int floatoffset = 0;
for(int j=0; j<nops; ++j) {
int floatidx = floatoffset;
for (int k=0; k < (int)t->intargs.size();) {
int pathlength = t->intargs[k];
int faceid = t->intargs[k+1];
int vertexid = t->intargs[k+pathlength];
int nsubfaces = pathlength - 2;
int *subfaces = &t->intargs[k+2];
OpenSubdiv::HbrFace<T> * f = mesh->GetFace(faceid);
if (!f) {
printf("Invalid face %d specified for %s tag on SubdivisionMesh.\n", faceid, t->name.c_str());
goto nexttag;
}
// Found the face. Do some preliminary error checking to make sure the path is
// correct. First value in path depends on the number of vertices of the face
// which we have in hand
if (nsubfaces && (subfaces[0] < 0 || subfaces[0] >= f->GetNumVertices()) ) {
printf("Invalid path component %d in %s tag on SubdivisionMesh.\n", subfaces[0], t->name.c_str());
goto nexttag;
}
// All subsequent values must be less than 4 (FIXME or 3 in the loop case?)
for (int l=1; l<nsubfaces; ++l) {
if (subfaces[l] < 0 || subfaces[l] > 3) {
printf("Invalid path component %d in %s tag on SubdivisionMesh.\n", subfaces[0], t->name.c_str());
goto nexttag;
}
}
if (vertexid < 0 || vertexid > 3) {
printf("Invalid path component (vertexid) %d in %s tag on SubdivisionMesh.\n", vertexid, t->name.c_str());
goto nexttag;
}
// Transform all the float values associated with the tag if needed
if(opnames[j] != "sharpness") {
for(int l=0; l<floatwidths[j]; ++l) {
xformed[l] = t->floatargs[l + floatidx];
}
// Edits of facevarying data are a different hierarchical edit type altogether
OpenSubdiv::HbrVertexEdit<T> * edit = new OpenSubdiv::HbrVertexEdit<T>(faceid, nsubfaces, subfaces,
vertexid, vvindex[j], floatwidths[j],
isP[j], opmodifiers[j], xformed);
mesh->AddHierarchicalEdit(edit);
} else {
if (t->name == "vertexedit") {
OpenSubdiv::HbrCornerEdit<T> * edit = new OpenSubdiv::HbrCornerEdit<T>(faceid, nsubfaces, subfaces,
vertexid, opmodifiers[j], t->floatargs[floatidx]);
mesh->AddHierarchicalEdit(edit);
} else {
OpenSubdiv::HbrCreaseEdit<T> * edit = new OpenSubdiv::HbrCreaseEdit<T>(faceid, nsubfaces, subfaces,
vertexid, opmodifiers[j], t->floatargs[floatidx]);
mesh->AddHierarchicalEdit(edit);
}
}
// Advance to next path
k += pathlength + 1;
// Advance to start of float data
floatidx += floatstride;
} // End of integer processing loop
// Next subop
floatoffset += floatwidths[j];
} // End of subop processing loop
} else if (t->name=="faceedit") {
printf("hierarchical face edits not supported (yet)\n");
} else { } else {
printf("Unknown tag : \"%s\" - skipping\n", t->name.c_str()); printf("Unknown tag : \"%s\" - skipping\n", t->name.c_str());
} }
nexttag: ;
} }
} }
@ -325,17 +456,17 @@ template <class T> OpenSubdiv::HbrMesh<T> *
createMesh( Scheme scheme=kCatmark) { createMesh( Scheme scheme=kCatmark) {
OpenSubdiv::HbrMesh<T> * mesh = 0; OpenSubdiv::HbrMesh<T> * mesh = 0;
static OpenSubdiv::HbrBilinearSubdivision<T> _bilinear; static OpenSubdiv::HbrBilinearSubdivision<T> _bilinear;
static OpenSubdiv::HbrLoopSubdivision<T> _loop; static OpenSubdiv::HbrLoopSubdivision<T> _loop;
static OpenSubdiv::HbrCatmarkSubdivision<T> _catmark; static OpenSubdiv::HbrCatmarkSubdivision<T> _catmark;
switch (scheme) { switch (scheme) {
case kBilinear : mesh = new OpenSubdiv::HbrMesh<T>( &_bilinear ); break; case kBilinear : mesh = new OpenSubdiv::HbrMesh<T>( &_bilinear ); break;
case kLoop : mesh = new OpenSubdiv::HbrMesh<T>( &_loop ); break; case kLoop : mesh = new OpenSubdiv::HbrMesh<T>( &_loop ); break;
case kCatmark : mesh = new OpenSubdiv::HbrMesh<T>( &_catmark ); break; case kCatmark : mesh = new OpenSubdiv::HbrMesh<T>( &_catmark ); break;
} }
return mesh; return mesh;
} }
@ -348,7 +479,7 @@ createVertices( shape const * sh, OpenSubdiv::HbrMesh<T> * mesh, std::vector<flo
v.SetPosition( sh->verts[i*3], sh->verts[i*3+1], sh->verts[i*3+2] ); v.SetPosition( sh->verts[i*3], sh->verts[i*3+1], sh->verts[i*3+2] );
mesh->NewVertex( i, v ); mesh->NewVertex( i, v );
} }
if (verts) if (verts)
*verts = sh->verts; *verts = sh->verts;
} }
@ -370,37 +501,37 @@ createTopology( shape const * sh, OpenSubdiv::HbrMesh<T> * mesh, Scheme scheme)
const int * fv=&(sh->faceverts[0]); const int * fv=&(sh->faceverts[0]);
for(int f=0, ptxidx=0;f<sh->getNfaces(); f++ ) { for(int f=0, ptxidx=0;f<sh->getNfaces(); f++ ) {
int nv = sh->nvertsPerFace[f]; int nv = sh->nvertsPerFace[f];
if ((scheme==kLoop) and (nv!=3)) { if ((scheme==kLoop) and (nv!=3)) {
printf("Trying to create a Loop surbd with non-triangle face\n"); printf("Trying to create a Loop surbd with non-triangle face\n");
exit(1); exit(1);
} }
for(int j=0;j<nv;j++) { for(int j=0;j<nv;j++) {
OpenSubdiv::HbrVertex<T> * origin = mesh->GetVertex( fv[j] ); OpenSubdiv::HbrVertex<T> * origin = mesh->GetVertex( fv[j] );
OpenSubdiv::HbrVertex<T> * destination = mesh->GetVertex( fv[ (j+1)%nv] ); OpenSubdiv::HbrVertex<T> * destination = mesh->GetVertex( fv[ (j+1)%nv] );
OpenSubdiv::HbrHalfedge<T> * opposite = destination->GetEdge(origin); OpenSubdiv::HbrHalfedge<T> * opposite = destination->GetEdge(origin);
if(origin==NULL || destination==NULL) { if(origin==NULL || destination==NULL) {
printf(" An edge was specified that connected a nonexistent vertex\n"); printf(" An edge was specified that connected a nonexistent vertex\n");
exit(1); exit(1);
} }
if(origin == destination) { if(origin == destination) {
printf(" An edge was specified that connected a vertex to itself\n"); printf(" An edge was specified that connected a vertex to itself\n");
exit(1); exit(1);
} }
if(opposite && opposite->GetOpposite() ) { if(opposite && opposite->GetOpposite() ) {
printf(" A non-manifold edge incident to more than 2 faces was found\n"); printf(" A non-manifold edge incident to more than 2 faces was found\n");
exit(1); exit(1);
} }
if(origin->GetEdge(destination)) { if(origin->GetEdge(destination)) {
printf(" An edge connecting two vertices was specified more than once." printf(" An edge connecting two vertices was specified more than once."
" It's likely that an incident face was flipped\n"); " It's likely that an incident face was flipped\n");
exit(1); exit(1);
} }
} }
@ -431,13 +562,13 @@ simpleHbr(char const * shapestr, Scheme scheme, std::vector<float> * verts=0) {
shape * sh = shape::parseShape( shapestr ); shape * sh = shape::parseShape( shapestr );
OpenSubdiv::HbrMesh<T> * mesh = createMesh<T>(scheme); OpenSubdiv::HbrMesh<T> * mesh = createMesh<T>(scheme);
createVertices<T>(sh, mesh, verts); createVertices<T>(sh, mesh, verts);
createTopology<T>(sh, mesh, scheme); createTopology<T>(sh, mesh, scheme);
delete sh; delete sh;
return mesh; return mesh;
} }
@ -448,13 +579,13 @@ simpleHbr(char const * shapestr, Scheme scheme, std::vector<float> & verts) {
shape * sh = shape::parseShape( shapestr ); shape * sh = shape::parseShape( shapestr );
OpenSubdiv::HbrMesh<T> * mesh = createMesh<T>(scheme); OpenSubdiv::HbrMesh<T> * mesh = createMesh<T>(scheme);
createVertices<T>(sh, mesh, verts); createVertices<T>(sh, mesh, verts);
createTopology<T>(sh, mesh, scheme); createTopology<T>(sh, mesh, scheme);
delete sh; delete sh;
return mesh; return mesh;
} }

View File

@ -55,18 +55,6 @@
# a particular purpose and non-infringement. # a particular purpose and non-infringement.
# #
find_package(IlmBase REQUIRED)
if(NOT ILMBASE_FOUND)
message(WARNING
"IlmBase could not be found, so the OpenSubdiv far library regression "
"will not be available. If you do have IlmBase installed and see this "
"message, please add your IlmBase path to cmake/FindIlmBase.cmake or set it "
"in the ILMBASE_LOCATION environment variable."
)
return()
endif()
include_directories( include_directories(
${ILMBASE_INCLUDE_DIR} ${ILMBASE_INCLUDE_DIR}
${PROJECT_SOURCE_DIR}/opensubdiv ${PROJECT_SOURCE_DIR}/opensubdiv
@ -82,6 +70,6 @@ add_executable(far_regression
) )
target_link_libraries(far_regression target_link_libraries(far_regression
${ILMBASE_LIBS_DIRECTORY} ${ILMBASE_LIBRARIES}
) )

View File

@ -76,7 +76,7 @@
// - precision is currently held at 1e-6 // - precision is currently held at 1e-6
// //
// - results cannot be bitwise identical as some vertex interpolations // - results cannot be bitwise identical as some vertex interpolations
// are not happening in the same order. // are not happening in the same order.
// //
// - only vertex interpolation is being tested at the moment. // - only vertex interpolation is being tested at the moment.
// //
@ -96,17 +96,38 @@ struct xyzVV {
void AddVaryingWithWeight(const xyzVV& , float, void * =0 ) { } void AddVaryingWithWeight(const xyzVV& , float, void * =0 ) { }
void Clear( void * =0 ) { _pos.setValue(0.f, 0.f, 0.f); } void Clear( void * =0 ) { _pos.setValue(0.f, 0.f, 0.f); }
void SetPosition(float x, float y, float z) { _pos=Imath::Vec3<float>(x,y,z); } void SetPosition(float x, float y, float z) { _pos=Imath::Vec3<float>(x,y,z); }
void ApplyVertexEdit(const OpenSubdiv::HbrVertexEdit<xyzVV> & edit) {
const float *src = edit.GetEdit();
switch(edit.GetOperation()) {
case OpenSubdiv::HbrHierarchicalEdit<xyzVV>::Set:
_pos.x = src[0];
_pos.y = src[1];
_pos.z = src[2];
break;
case OpenSubdiv::HbrHierarchicalEdit<xyzVV>::Add:
_pos.x += src[0];
_pos.y += src[1];
_pos.z += src[2];
break;
case OpenSubdiv::HbrHierarchicalEdit<xyzVV>::Subtract:
_pos.x -= src[0];
_pos.y -= src[1];
_pos.z -= src[2];
break;
}
}
void ApplyMovingVertexEdit(const OpenSubdiv::HbrMovingVertexEdit<xyzVV> &) { }
const Imath::Vec3<float>& GetPos() const { return _pos; } const Imath::Vec3<float>& GetPos() const { return _pos; }
private: private:
Imath::Vec3<float> _pos; Imath::Vec3<float> _pos;
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
class xyzFV; class xyzFV;
typedef OpenSubdiv::HbrMesh<xyzVV> xyzmesh; typedef OpenSubdiv::HbrMesh<xyzVV> xyzmesh;
typedef OpenSubdiv::HbrFace<xyzVV> xyzface; typedef OpenSubdiv::HbrFace<xyzVV> xyzface;
typedef OpenSubdiv::HbrVertex<xyzVV> xyzvertex; typedef OpenSubdiv::HbrVertex<xyzVV> xyzvertex;
typedef OpenSubdiv::HbrHalfedge<xyzVV> xyzhalfedge; typedef OpenSubdiv::HbrHalfedge<xyzVV> xyzhalfedge;
typedef OpenSubdiv::HbrFaceOperator<xyzVV> xyzFaceOperator; typedef OpenSubdiv::HbrFaceOperator<xyzVV> xyzFaceOperator;
typedef OpenSubdiv::HbrVertexOperator<xyzVV> xyzVertexOperator; typedef OpenSubdiv::HbrVertexOperator<xyzVV> xyzVertexOperator;
@ -119,9 +140,9 @@ static bool g_debugmode = false;
static bool g_dumphbr = false; static bool g_dumphbr = false;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// visual debugging using Maya // visual debugging using Maya
// python dictionary dump - requires the script createMesh.py to read into Maya // python dictionary dump - requires the script createMesh.py to read into Maya
// format is : [ { 'verts':[(1, 0, 0),(2, 0, 0)], // format is : [ { 'verts':[(1, 0, 0),(2, 0, 0)],
// 'faces':[[1 2 3 4],[5,6,7,8]] }, ... ] // 'faces':[[1 2 3 4],[5,6,7,8]] }, ... ]
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static void dumpVerts( xyzmesh * mesh, int level ) { static void dumpVerts( xyzmesh * mesh, int level ) {
@ -136,7 +157,7 @@ static void dumpVerts( xyzmesh * mesh, int level ) {
} }
if (counter!=0 and (counter+1)%6==0) printf("\n\t\t\t"); if (counter!=0 and (counter+1)%6==0) printf("\n\t\t\t");
} }
printf("],\n"); printf("],\n");
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -157,21 +178,21 @@ static void dumpFaces( xyzmesh * mesh, int level ) {
continue; continue;
if (f->GetDepth()==level) { if (f->GetDepth()==level) {
if (f->GetNumVertices()==4) if (f->GetNumVertices()==4)
printf("[%6d, %6d, %6d, %6d], ", f->GetVertex(0)->GetID()-vertofs, printf("[%6d, %6d, %6d, %6d], ", f->GetVertex(0)->GetID()-vertofs,
f->GetVertex(1)->GetID()-vertofs, f->GetVertex(1)->GetID()-vertofs,
f->GetVertex(2)->GetID()-vertofs, f->GetVertex(2)->GetID()-vertofs,
f->GetVertex(3)->GetID()-vertofs ); f->GetVertex(3)->GetID()-vertofs );
else if (f->GetNumVertices()==3) else if (f->GetNumVertices()==3)
printf("[%6d, %6d, %6d], ", f->GetVertex(0)->GetID()-vertofs, printf("[%6d, %6d, %6d], ", f->GetVertex(0)->GetID()-vertofs,
f->GetVertex(1)->GetID()-vertofs, f->GetVertex(1)->GetID()-vertofs,
f->GetVertex(2)->GetID()-vertofs ); f->GetVertex(2)->GetID()-vertofs );
++counter; ++counter;
if (counter!=0 and (counter+4)%32==0) if (counter!=0 and (counter+4)%32==0)
printf("\n\t\t\t"); printf("\n\t\t\t");
} }
} }
printf("]\n"); printf("]\n");
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -195,10 +216,10 @@ static void dumpVerts( fMesh * mesh, int level ) {
printf("(%10f, %10f, %10f), ",verts[i].GetPos()[0], printf("(%10f, %10f, %10f), ",verts[i].GetPos()[0],
verts[i].GetPos()[1], verts[i].GetPos()[1],
verts[i].GetPos()[2] ); verts[i].GetPos()[2] );
if (i!=0 and (i+1)%6==0) if (i!=0 and (i+1)%6==0)
printf("\n\t\t\t"); printf("\n\t\t\t");
} }
printf("],\n"); printf("],\n");
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -209,14 +230,14 @@ static void dumpQuadFaces( fMesh * mesh, int level ) {
printf("\t'faces':[\t"); printf("\t'faces':[\t");
for (size_t i=0; i<(fverts.size()); i+=4) { for (size_t i=0; i<(fverts.size()); i+=4) {
printf("[%6d, %6d, %6d, %6d], ", fverts[i ]-ofs, printf("[%6d, %6d, %6d, %6d], ", fverts[i ]-ofs,
fverts[i+1]-ofs, fverts[i+1]-ofs,
fverts[i+2]-ofs, fverts[i+2]-ofs,
fverts[i+3]-ofs ); fverts[i+3]-ofs );
if (i!=0 and (i+4)%32==0) if (i!=0 and (i+4)%32==0)
printf("\n\t\t\t"); printf("\n\t\t\t");
} }
printf("]\n"); printf("]\n");
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -228,10 +249,10 @@ static void dumpTriFaces( fMesh * mesh, int level ) {
printf("\t'faces':[\t"); printf("\t'faces':[\t");
for (size_t i=0; i<(fverts.size()); i+=3) { for (size_t i=0; i<(fverts.size()); i+=3) {
printf("[%6d, %6d, %6d], ", fverts[i]-ofs, fverts[i+1]-ofs, fverts[i+2]-ofs ); printf("[%6d, %6d, %6d], ", fverts[i]-ofs, fverts[i+1]-ofs, fverts[i+2]-ofs );
if (i!=0 and (i+4)%32==0) if (i!=0 and (i+4)%32==0)
printf("\n\t\t\t"); printf("\n\t\t\t");
} }
printf("]\n"); printf("]\n");
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -249,20 +270,20 @@ static void dumpMesh( fMesh * mesh, int level, Scheme scheme=kCatmark ) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Returns true if a vertex or any of its parents is on a boundary // Returns true if a vertex or any of its parents is on a boundary
bool VertexOnBoundary( xyzvertex const * v ) { bool VertexOnBoundary( xyzvertex const * v ) {
if (not v) if (not v)
return false; return false;
if (v->OnBoundary()) if (v->OnBoundary())
return true; return true;
xyzvertex const * pv = v->GetParentVertex(); xyzvertex const * pv = v->GetParentVertex();
if (pv) if (pv)
return VertexOnBoundary(pv); return VertexOnBoundary(pv);
else { else {
xyzhalfedge const * pe = v->GetParentEdge(); xyzhalfedge const * pe = v->GetParentEdge();
if (pe) { if (pe) {
return VertexOnBoundary(pe->GetOrgVertex()) or return VertexOnBoundary(pe->GetOrgVertex()) or
VertexOnBoundary(pe->GetDestVertex()); VertexOnBoundary(pe->GetDestVertex());
} else { } else {
xyzface const * pf = v->GetParentFace(), * rootf = pf; xyzface const * pf = v->GetParentFace(), * rootf = pf;
@ -285,8 +306,8 @@ int checkMesh( char const * msg, xyzmesh * hmesh, int levels, Scheme scheme=kCat
assert(msg); assert(msg);
int count=0; int count=0;
Imath::Vec3<float> deltaAvg(0.0, 0.0, 0.0); Imath::Vec3<float> deltaAvg(0.0, 0.0, 0.0);
Imath::Vec3<float> deltaCnt(0, 0, 0); Imath::Vec3<float> deltaCnt(0, 0, 0);
// subdivide on the Nsd side // subdivide on the Nsd side
@ -298,11 +319,11 @@ int checkMesh( char const * msg, xyzmesh * hmesh, int levels, Scheme scheme=kCat
for (int i=1; i<=levels; ++i) for (int i=1; i<=levels; ++i)
if (g_dumphbr) if (g_dumphbr)
dumpXYZMesh( hmesh, i, scheme ); dumpXYZMesh( hmesh, i, scheme );
else else
dumpMesh( m, i, scheme ); dumpMesh( m, i, scheme );
} else } else
printf("- %s (scheme=%d)\n", msg, scheme); printf("- %s (scheme=%d)\n", msg, scheme);
std::vector<int> const & remap = fact.GetRemappingTable(); std::vector<int> const & remap = fact.GetRemappingTable();
int nverts = m->GetNumVertices(); int nverts = m->GetNumVertices();
@ -318,13 +339,13 @@ int checkMesh( char const * msg, xyzmesh * hmesh, int levels, Scheme scheme=kCat
if ( hmesh->GetInterpolateBoundaryMethod()==xyzmesh::k_InterpolateBoundaryNone and if ( hmesh->GetInterpolateBoundaryMethod()==xyzmesh::k_InterpolateBoundaryNone and
VertexOnBoundary(hv) ) VertexOnBoundary(hv) )
continue; continue;
if ( hv->GetData().GetPos()[0] != nv.GetPos()[0] )
if ( hv->GetData().GetPos()[0] != nv.GetPos()[0] )
deltaCnt[0]++; deltaCnt[0]++;
if ( hv->GetData().GetPos()[1] != nv.GetPos()[1] ) if ( hv->GetData().GetPos()[1] != nv.GetPos()[1] )
deltaCnt[1]++; deltaCnt[1]++;
if ( hv->GetData().GetPos()[2] != nv.GetPos()[2] ) if ( hv->GetData().GetPos()[2] != nv.GetPos()[2] )
deltaCnt[2]++; deltaCnt[2]++;
Imath::Vec3<float> delta = hv->GetData().GetPos() - nv.GetPos(); Imath::Vec3<float> delta = hv->GetData().GetPos() - nv.GetPos();
@ -341,10 +362,10 @@ int checkMesh( char const * msg, xyzmesh * hmesh, int levels, Scheme scheme=kCat
nv.GetPos()[0], nv.GetPos()[0],
nv.GetPos()[1], nv.GetPos()[1],
nv.GetPos()[2] ); nv.GetPos()[2] );
count++; count++;
} }
} }
if (deltaCnt[0]) if (deltaCnt[0])
deltaAvg[0]/=deltaCnt[0]; deltaAvg[0]/=deltaCnt[0];
if (deltaCnt[1]) if (deltaCnt[1])
@ -353,20 +374,20 @@ int checkMesh( char const * msg, xyzmesh * hmesh, int levels, Scheme scheme=kCat
deltaAvg[2]/=deltaCnt[2]; deltaAvg[2]/=deltaCnt[2];
if (not g_debugmode) { if (not g_debugmode) {
printf(" delta ratio : (%d/%d %d/%d %d/%d)\n", (int)deltaCnt.x, nverts, printf(" delta ratio : (%d/%d %d/%d %d/%d)\n", (int)deltaCnt.x, nverts,
(int)deltaCnt.y, nverts, (int)deltaCnt.y, nverts,
(int)deltaCnt.x, nverts ); (int)deltaCnt.x, nverts );
printf(" average delta : (%.10f %.10f %.10f)\n", deltaAvg.x, printf(" average delta : (%.10f %.10f %.10f)\n", deltaAvg.x,
deltaAvg.y, deltaAvg.y,
deltaAvg.z ); deltaAvg.z );
if (count==0) if (count==0)
printf(" success !\n"); printf(" success !\n");
} }
delete hmesh; delete hmesh;
delete m; delete m;
return count; return count;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -411,6 +432,10 @@ int main(int argc, char ** argv) {
#define test_catmark_tent #define test_catmark_tent
#define test_catmark_tent_creases0 #define test_catmark_tent_creases0
#define test_catmark_tent_creases1 #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_edgeonly
#define test_loop_triangle_edgecorner #define test_loop_triangle_edgecorner
@ -428,141 +453,161 @@ int main(int argc, char ** argv) {
#ifdef test_catmark_edgeonly #ifdef test_catmark_edgeonly
#include "../shapes/catmark_edgeonly.h" #include "../shapes/catmark_edgeonly.h"
total += checkMesh( "test_catmark_edgeonly", simpleHbr<xyzVV>(catmark_edgeonly, kCatmark, 0), levels ); total += checkMesh( "test_catmark_edgeonly", simpleHbr<xyzVV>(catmark_edgeonly, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_edgecorner #ifdef test_catmark_edgecorner
#include "../shapes/catmark_edgecorner.h" #include "../shapes/catmark_edgecorner.h"
total += checkMesh( "test_catmark_edgeonly", simpleHbr<xyzVV>(catmark_edgecorner, kCatmark, 0), levels ); total += checkMesh( "test_catmark_edgeonly", simpleHbr<xyzVV>(catmark_edgecorner, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_pyramid #ifdef test_catmark_pyramid
#include "../shapes/catmark_pyramid.h" #include "../shapes/catmark_pyramid.h"
total += checkMesh( "test_catmark_pyramid", simpleHbr<xyzVV>(catmark_pyramid, kCatmark, 0), levels ); total += checkMesh( "test_catmark_pyramid", simpleHbr<xyzVV>(catmark_pyramid, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_pyramid_creases0 #ifdef test_catmark_pyramid_creases0
#include "../shapes/catmark_pyramid_creases0.h" #include "../shapes/catmark_pyramid_creases0.h"
total += checkMesh( "test_catmark_pyramid_creases0", simpleHbr<xyzVV>(catmark_pyramid_creases0, kCatmark, 0), levels ); total += checkMesh( "test_catmark_pyramid_creases0", simpleHbr<xyzVV>(catmark_pyramid_creases0, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_pyramid_creases1 #ifdef test_catmark_pyramid_creases1
#include "../shapes/catmark_pyramid_creases1.h" #include "../shapes/catmark_pyramid_creases1.h"
total += checkMesh( "test_catmark_pyramid_creases1", simpleHbr<xyzVV>(catmark_pyramid_creases1, kCatmark, 0), levels ); total += checkMesh( "test_catmark_pyramid_creases1", simpleHbr<xyzVV>(catmark_pyramid_creases1, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_cube #ifdef test_catmark_cube
#include "../shapes/catmark_cube.h" #include "../shapes/catmark_cube.h"
total += checkMesh( "test_catmark_cube", simpleHbr<xyzVV>(catmark_cube, kCatmark, 0), levels ); total += checkMesh( "test_catmark_cube", simpleHbr<xyzVV>(catmark_cube, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_cube_creases0 #ifdef test_catmark_cube_creases0
#include "../shapes/catmark_cube_creases0.h" #include "../shapes/catmark_cube_creases0.h"
total += checkMesh( "test_catmark_cube_creases0", simpleHbr<xyzVV>(catmark_cube_creases0, kCatmark, 0), levels ); total += checkMesh( "test_catmark_cube_creases0", simpleHbr<xyzVV>(catmark_cube_creases0, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_cube_creases1 #ifdef test_catmark_cube_creases1
#include "../shapes/catmark_cube_creases1.h" #include "../shapes/catmark_cube_creases1.h"
total += checkMesh( "test_catmark_cube_creases1", simpleHbr<xyzVV>(catmark_cube_creases1, kCatmark, 0), levels ); total += checkMesh( "test_catmark_cube_creases1", simpleHbr<xyzVV>(catmark_cube_creases1, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_cube_corner0 #ifdef test_catmark_cube_corner0
#include "../shapes/catmark_cube_corner0.h" #include "../shapes/catmark_cube_corner0.h"
total += checkMesh( "test_catmark_cube_corner0", simpleHbr<xyzVV>(catmark_cube_corner0, kCatmark, 0), levels ); total += checkMesh( "test_catmark_cube_corner0", simpleHbr<xyzVV>(catmark_cube_corner0, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_cube_corner1 #ifdef test_catmark_cube_corner1
#include "../shapes/catmark_cube_corner1.h" #include "../shapes/catmark_cube_corner1.h"
total += checkMesh( "test_catmark_cube_corner1", simpleHbr<xyzVV>(catmark_cube_corner1, kCatmark, 0), levels ); total += checkMesh( "test_catmark_cube_corner1", simpleHbr<xyzVV>(catmark_cube_corner1, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_cube_corner2 #ifdef test_catmark_cube_corner2
#include "../shapes/catmark_cube_corner2.h" #include "../shapes/catmark_cube_corner2.h"
total += checkMesh( "test_catmark_cube_corner2", simpleHbr<xyzVV>(catmark_cube_corner2, kCatmark, 0), levels ); total += checkMesh( "test_catmark_cube_corner2", simpleHbr<xyzVV>(catmark_cube_corner2, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_cube_corner3 #ifdef test_catmark_cube_corner3
#include "../shapes/catmark_cube_corner3.h" #include "../shapes/catmark_cube_corner3.h"
total += checkMesh( "test_catmark_cube_corner3", simpleHbr<xyzVV>(catmark_cube_corner3, kCatmark, 0), levels ); total += checkMesh( "test_catmark_cube_corner3", simpleHbr<xyzVV>(catmark_cube_corner3, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_cube_corner4 #ifdef test_catmark_cube_corner4
#include "../shapes/catmark_cube_corner4.h" #include "../shapes/catmark_cube_corner4.h"
total += checkMesh( "test_catmark_cube_corner4", simpleHbr<xyzVV>(catmark_cube_corner4, kCatmark, 0), levels ); total += checkMesh( "test_catmark_cube_corner4", simpleHbr<xyzVV>(catmark_cube_corner4, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_dart_edgecorner #ifdef test_catmark_dart_edgecorner
#include "../shapes/catmark_dart_edgecorner.h" #include "../shapes/catmark_dart_edgecorner.h"
total += checkMesh( "test_catmark_dart_edgecorner", simpleHbr<xyzVV>(catmark_dart_edgecorner, kCatmark, 0), levels ); total += checkMesh( "test_catmark_dart_edgecorner", simpleHbr<xyzVV>(catmark_dart_edgecorner, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_dart_edgeonly #ifdef test_catmark_dart_edgeonly
#include "../shapes/catmark_dart_edgeonly.h" #include "../shapes/catmark_dart_edgeonly.h"
total += checkMesh( "test_catmark_dart_edgeonly", simpleHbr<xyzVV>(catmark_dart_edgeonly, kCatmark, 0), levels ); total += checkMesh( "test_catmark_dart_edgeonly", simpleHbr<xyzVV>(catmark_dart_edgeonly, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_tent #ifdef test_catmark_tent
#include "../shapes/catmark_tent.h" #include "../shapes/catmark_tent.h"
total += checkMesh( "test_catmark_tent", simpleHbr<xyzVV>(catmark_tent, kCatmark, 0), levels ); total += checkMesh( "test_catmark_tent", simpleHbr<xyzVV>(catmark_tent, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_tent_creases0 #ifdef test_catmark_tent_creases0
#include "../shapes/catmark_tent_creases0.h" #include "../shapes/catmark_tent_creases0.h"
total += checkMesh( "test_catmark_tent_creases0", simpleHbr<xyzVV>(catmark_tent_creases0, kCatmark, 0), levels ); total += checkMesh( "test_catmark_tent_creases0", simpleHbr<xyzVV>(catmark_tent_creases0, kCatmark, 0), levels );
#endif #endif
#ifdef test_catmark_tent_creases1 #ifdef test_catmark_tent_creases1
#include "../shapes/catmark_tent_creases1.h" #include "../shapes/catmark_tent_creases1.h"
total += checkMesh( "test_catmark_tent_creases1", simpleHbr<xyzVV>(catmark_tent_creases1, kCatmark, NULL), levels ); total += checkMesh( "test_catmark_tent_creases1", simpleHbr<xyzVV>(catmark_tent_creases1, kCatmark, NULL), levels );
#endif
#ifdef test_catmark_square_hedit0
#include "../shapes/catmark_square_hedit0.h"
total += checkMesh( "test_catmark_square_hedit0", simpleHbr<xyzVV>(catmark_square_hedit0, kCatmark, 0), levels );
#endif
#ifdef test_catmark_square_hedit1
#include "../shapes/catmark_square_hedit1.h"
total += checkMesh( "test_catmark_square_hedit1", simpleHbr<xyzVV>(catmark_square_hedit1, kCatmark, 0), levels );
#endif
#ifdef test_catmark_square_hedit2
#include "../shapes/catmark_square_hedit2.h"
total += checkMesh( "test_catmark_square_hedit2", simpleHbr<xyzVV>(catmark_square_hedit2, kCatmark, 0), levels );
#endif
#ifdef test_catmark_square_hedit3
#include "../shapes/catmark_square_hedit3.h"
total += checkMesh( "test_catmark_square_hedit3", simpleHbr<xyzVV>(catmark_square_hedit3, kCatmark, 0), levels );
#endif #endif
#ifdef test_loop_triangle_edgeonly #ifdef test_loop_triangle_edgeonly
#include "../shapes/loop_triangle_edgeonly.h" #include "../shapes/loop_triangle_edgeonly.h"
total += checkMesh( "test_loop_triangle_edgeonly", simpleHbr<xyzVV>(loop_triangle_edgeonly, kLoop, 0), levels, kLoop ); total += checkMesh( "test_loop_triangle_edgeonly", simpleHbr<xyzVV>(loop_triangle_edgeonly, kLoop, 0), levels, kLoop );
#endif #endif
#ifdef test_loop_triangle_edgecorner #ifdef test_loop_triangle_edgecorner
#include "../shapes/loop_triangle_edgecorner.h" #include "../shapes/loop_triangle_edgecorner.h"
total += checkMesh( "test_loop_triangle_edgecorner", simpleHbr<xyzVV>(loop_triangle_edgecorner, kLoop, 0), levels, kLoop ); total += checkMesh( "test_loop_triangle_edgecorner", simpleHbr<xyzVV>(loop_triangle_edgecorner, kLoop, 0), levels, kLoop );
#endif #endif
#ifdef test_loop_saddle_edgeonly #ifdef test_loop_saddle_edgeonly
#include "../shapes/loop_saddle_edgeonly.h" #include "../shapes/loop_saddle_edgeonly.h"
total += checkMesh( "test_loop_saddle_edgeonly", simpleHbr<xyzVV>(loop_saddle_edgeonly, kLoop, 0), levels, kLoop ); total += checkMesh( "test_loop_saddle_edgeonly", simpleHbr<xyzVV>(loop_saddle_edgeonly, kLoop, 0), levels, kLoop );
#endif #endif
#ifdef test_loop_saddle_edgecorner #ifdef test_loop_saddle_edgecorner
#include "../shapes/loop_saddle_edgecorner.h" #include "../shapes/loop_saddle_edgecorner.h"
total += checkMesh( "test_loop_saddle_edgecorner", simpleHbr<xyzVV>(loop_saddle_edgecorner, kLoop, 0), levels, kLoop ); total += checkMesh( "test_loop_saddle_edgecorner", simpleHbr<xyzVV>(loop_saddle_edgecorner, kLoop, 0), levels, kLoop );
#endif #endif
#ifdef test_loop_icosahedron #ifdef test_loop_icosahedron
#include "../shapes/loop_icosahedron.h" #include "../shapes/loop_icosahedron.h"
total += checkMesh( "test_loop_icosahedron", simpleHbr<xyzVV>(loop_icosahedron, kLoop, 0), levels, kLoop ); total += checkMesh( "test_loop_icosahedron", simpleHbr<xyzVV>(loop_icosahedron, kLoop, 0), levels, kLoop );
#endif #endif
#ifdef test_loop_cube #ifdef test_loop_cube
#include "../shapes/loop_cube.h" #include "../shapes/loop_cube.h"
total += checkMesh( "test_loop_cube", simpleHbr<xyzVV>(loop_cube, kLoop, 0), levels, kLoop ); total += checkMesh( "test_loop_cube", simpleHbr<xyzVV>(loop_cube, kLoop, 0), levels, kLoop );
#endif #endif
#ifdef test_loop_cube_creases0 #ifdef test_loop_cube_creases0
#include "../shapes/loop_cube_creases0.h" #include "../shapes/loop_cube_creases0.h"
total += checkMesh( "test_loop_cube_creases0", simpleHbr<xyzVV>(loop_cube_creases0, kLoop, 0), levels, kLoop ); total += checkMesh( "test_loop_cube_creases0", simpleHbr<xyzVV>(loop_cube_creases0, kLoop, 0), levels, kLoop );
#endif #endif
#ifdef test_loop_cube_creases1 #ifdef test_loop_cube_creases1
#include "../shapes/loop_cube_creases1.h" #include "../shapes/loop_cube_creases1.h"
total += checkMesh( "test_loop_cube_creases1", simpleHbr<xyzVV>(loop_cube_creases1, kLoop, 0), levels, kLoop ); total += checkMesh( "test_loop_cube_creases1", simpleHbr<xyzVV>(loop_cube_creases1, kLoop, 0), levels, kLoop );
#endif #endif
#ifdef test_bilinear_cube #ifdef test_bilinear_cube
#include "../shapes/bilinear_cube.h" #include "../shapes/bilinear_cube.h"
total += checkMesh( "test_bilinear_cube", simpleHbr<xyzVV>(bilinear_cube, kBilinear, 0), levels, kBilinear ); total += checkMesh( "test_bilinear_cube", simpleHbr<xyzVV>(bilinear_cube, kBilinear, 0), levels, kBilinear );
#endif #endif

View File

@ -55,21 +55,11 @@
# a particular purpose and non-infringement. # a particular purpose and non-infringement.
# #
find_package(IlmBase REQUIRED)
if(NOT ILMBASE_FOUND)
message(WARNING
"IlmBase could not be found, so the OpenSubdiv osd library regression "
"will not be available. If you do have IlmBase installed and see this "
"message, please add your IlmBase path to cmake/FindIlmBase.cmake or set it "
"in the ILMBASE_LOCATION environment variable."
)
return()
endif()
include_directories( include_directories(
${ILMBASE_INCLUDE_DIR} ${ILMBASE_INCLUDE_DIR}
${PROJECT_SOURCE_DIR}/opensubdiv ${PROJECT_SOURCE_DIR}/opensubdiv
${GLEW_INCLUDE_DIR}
${GLUT_INCLUDE_DIR}
) )
set(SOURCE_FILES set(SOURCE_FILES
@ -83,6 +73,8 @@ add_executable(osd_regression
target_link_libraries(osd_regression target_link_libraries(osd_regression
${OSD_LINK_TARGET} ${OSD_LINK_TARGET}
${ILMBASE_LIBS_DIRECTORY} ${ILMBASE_LIBRARIES}
${OPENGL_LIBRARY}
${GLEW_LIBRARY}
${GLUT_LIBRARIES}
) )

View File

@ -54,6 +54,15 @@
// exclude the implied warranties of merchantability, fitness for // exclude the implied warranties of merchantability, fitness for
// a particular purpose and non-infringement. // a particular purpose and non-infringement.
// //
#if defined(__APPLE__)
#include <GLUT/glut.h>
#else
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>
#endif
#include <stdio.h> #include <stdio.h>
#include <cassert> #include <cassert>
@ -88,7 +97,7 @@
// - precision is currently held at 1e-6 // - precision is currently held at 1e-6
// //
// - results cannot be bitwise identical as some vertex interpolations // - results cannot be bitwise identical as some vertex interpolations
// are not happening in the same order. // are not happening in the same order.
// //
// - only vertex interpolation is being tested at the moment. // - only vertex interpolation is being tested at the moment.
// //
@ -108,17 +117,19 @@ struct xyzVV {
void AddVaryingWithWeight(const xyzVV& , float, void * =0 ) { } void AddVaryingWithWeight(const xyzVV& , float, void * =0 ) { }
void Clear( void * =0 ) { _pos.setValue(0.f, 0.f, 0.f); } void Clear( void * =0 ) { _pos.setValue(0.f, 0.f, 0.f); }
void SetPosition(float x, float y, float z) { _pos=Imath::Vec3<float>(x,y,z); } void SetPosition(float x, float y, float z) { _pos=Imath::Vec3<float>(x,y,z); }
void ApplyVertexEdit(const OpenSubdiv::HbrVertexEdit<xyzVV> &) { }
void ApplyMovingVertexEdit(const OpenSubdiv::HbrMovingVertexEdit<xyzVV> &) { }
const Imath::Vec3<float>& GetPos() const { return _pos; } const Imath::Vec3<float>& GetPos() const { return _pos; }
private: private:
Imath::Vec3<float> _pos; Imath::Vec3<float> _pos;
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
class xyzFV; class xyzFV;
typedef OpenSubdiv::HbrMesh<xyzVV> xyzmesh; typedef OpenSubdiv::HbrMesh<xyzVV> xyzmesh;
typedef OpenSubdiv::HbrFace<xyzVV> xyzface; typedef OpenSubdiv::HbrFace<xyzVV> xyzface;
typedef OpenSubdiv::HbrVertex<xyzVV> xyzvertex; typedef OpenSubdiv::HbrVertex<xyzVV> xyzvertex;
typedef OpenSubdiv::HbrHalfedge<xyzVV> xyzhalfedge; typedef OpenSubdiv::HbrHalfedge<xyzVV> xyzhalfedge;
typedef OpenSubdiv::HbrFaceOperator<xyzVV> xyzFaceOperator; typedef OpenSubdiv::HbrFaceOperator<xyzVV> xyzFaceOperator;
typedef OpenSubdiv::HbrVertexOperator<xyzVV> xyzVertexOperator; typedef OpenSubdiv::HbrVertexOperator<xyzVV> xyzVertexOperator;
@ -126,20 +137,20 @@ typedef OpenSubdiv::HbrVertexOperator<xyzVV> xyzVertexOperator;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Returns true if a vertex or any of its parents is on a boundary // Returns true if a vertex or any of its parents is on a boundary
bool VertexOnBoundary( xyzvertex const * v ) { bool VertexOnBoundary( xyzvertex const * v ) {
if (not v) if (not v)
return false; return false;
if (v->OnBoundary()) if (v->OnBoundary())
return true; return true;
xyzvertex const * pv = v->GetParentVertex(); xyzvertex const * pv = v->GetParentVertex();
if (pv) if (pv)
return VertexOnBoundary(pv); return VertexOnBoundary(pv);
else { else {
xyzhalfedge const * pe = v->GetParentEdge(); xyzhalfedge const * pe = v->GetParentEdge();
if (pe) { if (pe) {
return VertexOnBoundary(pe->GetOrgVertex()) or return VertexOnBoundary(pe->GetOrgVertex()) or
VertexOnBoundary(pe->GetDestVertex()); VertexOnBoundary(pe->GetDestVertex());
} else { } else {
xyzface const * pf = v->GetParentFace(), * rootf = pf; xyzface const * pf = v->GetParentFace(), * rootf = pf;
@ -159,18 +170,18 @@ bool VertexOnBoundary( xyzvertex const * v ) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
int checkVertexBuffer( xyzmesh * hmesh, int checkVertexBuffer( xyzmesh * hmesh,
OpenSubdiv::OsdCpuVertexBuffer * vb, OpenSubdiv::OsdCpuVertexBuffer * vb,
std::vector<int> const & remap) { std::vector<int> const & remap) {
int count=0; int count=0;
Imath::Vec3<float> deltaAvg(0.0, 0.0, 0.0); Imath::Vec3<float> deltaAvg(0.0, 0.0, 0.0);
Imath::Vec3<float> deltaCnt(0,0,0); Imath::Vec3<float> deltaCnt(0,0,0);
int nverts = hmesh->GetNumVertices(); int nverts = hmesh->GetNumVertices();
for (int i=0; i<nverts; ++i) { for (int i=0; i<nverts; ++i) {
xyzvertex * hv = hmesh->GetVertex(i); xyzvertex * hv = hmesh->GetVertex(i);
float * ov = & vb->GetCpuBuffer()[ remap[ hv->GetID() ] * vb->GetNumElements() ]; float * ov = & vb->GetCpuBuffer()[ remap[ hv->GetID() ] * vb->GetNumElements() ];
// boundary interpolation rules set to "none" produce "undefined" vertices on // boundary interpolation rules set to "none" produce "undefined" vertices on
@ -180,11 +191,11 @@ int checkVertexBuffer( xyzmesh * hmesh,
continue; continue;
if ( hv->GetData().GetPos()[0] != ov[0] ) if ( hv->GetData().GetPos()[0] != ov[0] )
deltaCnt[0]++; deltaCnt[0]++;
if ( hv->GetData().GetPos()[1] != ov[1] ) if ( hv->GetData().GetPos()[1] != ov[1] )
deltaCnt[1]++; deltaCnt[1]++;
if ( hv->GetData().GetPos()[2] != ov[2] ) if ( hv->GetData().GetPos()[2] != ov[2] )
deltaCnt[2]++; deltaCnt[2]++;
Imath::Vec3<float> delta = hv->GetData().GetPos() - Imath::Vec3<float>(ov[0],ov[1],ov[2]); Imath::Vec3<float> delta = hv->GetData().GetPos() - Imath::Vec3<float>(ov[0],ov[1],ov[2]);
@ -200,7 +211,7 @@ int checkVertexBuffer( xyzmesh * hmesh,
ov[0], ov[0],
ov[1], ov[1],
ov[2] ); ov[2] );
count++; count++;
} }
} }
@ -211,15 +222,15 @@ int checkVertexBuffer( xyzmesh * hmesh,
if (deltaCnt[2]) if (deltaCnt[2])
deltaAvg[2]/=deltaCnt[2]; deltaAvg[2]/=deltaCnt[2];
printf(" delta ratio : (%d/%d %d/%d %d/%d)\n", (int)deltaCnt.x, nverts, printf(" delta ratio : (%d/%d %d/%d %d/%d)\n", (int)deltaCnt.x, nverts,
(int)deltaCnt.y, nverts, (int)deltaCnt.y, nverts,
(int)deltaCnt.x, nverts ); (int)deltaCnt.x, nverts );
printf(" average delta : (%.10f %.10f %.10f)\n", deltaAvg.x, printf(" average delta : (%.10f %.10f %.10f)\n", deltaAvg.x,
deltaAvg.y, deltaAvg.y,
deltaAvg.z ); deltaAvg.z );
if (count==0) if (count==0)
printf(" success !\n"); printf(" success !\n");
return count; return count;
} }
@ -243,14 +254,14 @@ int checkMesh( char const * msg, char const * shape, int levels, Scheme scheme=k
int result =0; int result =0;
printf("- %s (scheme=%d)\n", msg, scheme); printf("- %s (scheme=%d)\n", msg, scheme);
xyzmesh * refmesh = simpleHbr<xyzVV>(shape, scheme, 0); xyzmesh * refmesh = simpleHbr<xyzVV>(shape, scheme, 0);
refine( refmesh, levels ); refine( refmesh, levels );
std::vector<float> coarseverts; std::vector<float> coarseverts;
OpenSubdiv::OsdHbrMesh * hmesh = simpleHbr<OpenSubdiv::OsdVertex>(shape, scheme, coarseverts); OpenSubdiv::OsdHbrMesh * hmesh = simpleHbr<OpenSubdiv::OsdVertex>(shape, scheme, coarseverts);
OpenSubdiv::OsdMesh * omesh = new OpenSubdiv::OsdMesh(); OpenSubdiv::OsdMesh * omesh = new OpenSubdiv::OsdMesh();
@ -258,29 +269,34 @@ int checkMesh( char const * msg, char const * shape, int levels, Scheme scheme=k
std::vector<int> remap; std::vector<int> remap;
{ {
omesh->Create(hmesh, levels, (int)OpenSubdiv::OsdKernelDispatcher::kCPU, &remap); omesh->Create(hmesh, levels, (int)OpenSubdiv::OsdKernelDispatcher::kCPU, &remap);
OpenSubdiv::OsdCpuVertexBuffer * vb = OpenSubdiv::OsdCpuVertexBuffer * vb =
dynamic_cast<OpenSubdiv::OsdCpuVertexBuffer *>(omesh->InitializeVertexBuffer(3)); dynamic_cast<OpenSubdiv::OsdCpuVertexBuffer *>(omesh->InitializeVertexBuffer(3));
vb->UpdateData( & coarseverts[0], (int)coarseverts.size() ); vb->UpdateData( & coarseverts[0], (int)coarseverts.size()/3 );
omesh->Subdivide( vb, NULL ); omesh->Subdivide( vb, NULL );
omesh->Synchronize(); omesh->Synchronize();
checkVertexBuffer(refmesh, vb, remap); checkVertexBuffer(refmesh, vb, remap);
} }
delete hmesh; delete hmesh;
return result; return result;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
int main(int argc, char ** argv) { int main(int argc, char ** argv) {
// Make sure we have an OpenGL context.
glutInit(&argc, argv);
glutCreateWindow("osd_regression");
glewInit();
int levels=5, total=0; int levels=5, total=0;
// Register Osd compute kernels // Register Osd compute kernels
@ -318,141 +334,141 @@ int main(int argc, char ** argv) {
#ifdef test_catmark_edgeonly #ifdef test_catmark_edgeonly
#include "../shapes/catmark_edgeonly.h" #include "../shapes/catmark_edgeonly.h"
total += checkMesh( "test_catmark_edgeonly", catmark_edgeonly, levels, kCatmark ); total += checkMesh( "test_catmark_edgeonly", catmark_edgeonly, levels, kCatmark );
#endif #endif
#ifdef test_catmark_edgecorner #ifdef test_catmark_edgecorner
#include "../shapes/catmark_edgecorner.h" #include "../shapes/catmark_edgecorner.h"
total += checkMesh( "test_catmark_edgeonly", catmark_edgecorner, levels, kCatmark ); total += checkMesh( "test_catmark_edgeonly", catmark_edgecorner, levels, kCatmark );
#endif #endif
#ifdef test_catmark_pyramid #ifdef test_catmark_pyramid
#include "../shapes/catmark_pyramid.h" #include "../shapes/catmark_pyramid.h"
total += checkMesh( "test_catmark_pyramid", catmark_pyramid, levels, kCatmark ); total += checkMesh( "test_catmark_pyramid", catmark_pyramid, levels, kCatmark );
#endif #endif
#ifdef test_catmark_pyramid_creases0 #ifdef test_catmark_pyramid_creases0
#include "../shapes/catmark_pyramid_creases0.h" #include "../shapes/catmark_pyramid_creases0.h"
total += checkMesh( "test_catmark_pyramid_creases0", catmark_pyramid_creases0, levels, kCatmark ); total += checkMesh( "test_catmark_pyramid_creases0", catmark_pyramid_creases0, levels, kCatmark );
#endif #endif
#ifdef test_catmark_pyramid_creases1 #ifdef test_catmark_pyramid_creases1
#include "../shapes/catmark_pyramid_creases1.h" #include "../shapes/catmark_pyramid_creases1.h"
total += checkMesh( "test_catmark_pyramid_creases1", catmark_pyramid_creases1, levels, kCatmark ); total += checkMesh( "test_catmark_pyramid_creases1", catmark_pyramid_creases1, levels, kCatmark );
#endif #endif
#ifdef test_catmark_cube #ifdef test_catmark_cube
#include "../shapes/catmark_cube.h" #include "../shapes/catmark_cube.h"
total += checkMesh( "test_catmark_cube", catmark_cube, levels, kCatmark ); total += checkMesh( "test_catmark_cube", catmark_cube, levels, kCatmark );
#endif #endif
#ifdef test_catmark_cube_creases0 #ifdef test_catmark_cube_creases0
#include "../shapes/catmark_cube_creases0.h" #include "../shapes/catmark_cube_creases0.h"
total += checkMesh( "test_catmark_cube_creases0", catmark_cube_creases0, levels, kCatmark ); total += checkMesh( "test_catmark_cube_creases0", catmark_cube_creases0, levels, kCatmark );
#endif #endif
#ifdef test_catmark_cube_creases1 #ifdef test_catmark_cube_creases1
#include "../shapes/catmark_cube_creases1.h" #include "../shapes/catmark_cube_creases1.h"
total += checkMesh( "test_catmark_cube_creases1", catmark_cube_creases1, levels, kCatmark ); total += checkMesh( "test_catmark_cube_creases1", catmark_cube_creases1, levels, kCatmark );
#endif #endif
#ifdef test_catmark_cube_corner0 #ifdef test_catmark_cube_corner0
#include "../shapes/catmark_cube_corner0.h" #include "../shapes/catmark_cube_corner0.h"
total += checkMesh( "test_catmark_cube_corner0", catmark_cube_corner0, levels, kCatmark ); total += checkMesh( "test_catmark_cube_corner0", catmark_cube_corner0, levels, kCatmark );
#endif #endif
#ifdef test_catmark_cube_corner1 #ifdef test_catmark_cube_corner1
#include "../shapes/catmark_cube_corner1.h" #include "../shapes/catmark_cube_corner1.h"
total += checkMesh( "test_catmark_cube_corner1", catmark_cube_corner1, levels, kCatmark ); total += checkMesh( "test_catmark_cube_corner1", catmark_cube_corner1, levels, kCatmark );
#endif #endif
#ifdef test_catmark_cube_corner2 #ifdef test_catmark_cube_corner2
#include "../shapes/catmark_cube_corner2.h" #include "../shapes/catmark_cube_corner2.h"
total += checkMesh( "test_catmark_cube_corner2", catmark_cube_corner2, levels, kCatmark ); total += checkMesh( "test_catmark_cube_corner2", catmark_cube_corner2, levels, kCatmark );
#endif #endif
#ifdef test_catmark_cube_corner3 #ifdef test_catmark_cube_corner3
#include "../shapes/catmark_cube_corner3.h" #include "../shapes/catmark_cube_corner3.h"
total += checkMesh( "test_catmark_cube_corner3", catmark_cube_corner3, levels, kCatmark ); total += checkMesh( "test_catmark_cube_corner3", catmark_cube_corner3, levels, kCatmark );
#endif #endif
#ifdef test_catmark_cube_corner4 #ifdef test_catmark_cube_corner4
#include "../shapes/catmark_cube_corner4.h" #include "../shapes/catmark_cube_corner4.h"
total += checkMesh( "test_catmark_cube_corner4", catmark_cube_corner4, levels, kCatmark ); total += checkMesh( "test_catmark_cube_corner4", catmark_cube_corner4, levels, kCatmark );
#endif #endif
#ifdef test_catmark_dart_edgecorner #ifdef test_catmark_dart_edgecorner
#include "../shapes/catmark_dart_edgecorner.h" #include "../shapes/catmark_dart_edgecorner.h"
total += checkMesh( "test_catmark_dart_edgecorner", catmark_dart_edgecorner, levels, kCatmark ); total += checkMesh( "test_catmark_dart_edgecorner", catmark_dart_edgecorner, levels, kCatmark );
#endif #endif
#ifdef test_catmark_dart_edgeonly #ifdef test_catmark_dart_edgeonly
#include "../shapes/catmark_dart_edgeonly.h" #include "../shapes/catmark_dart_edgeonly.h"
total += checkMesh( "test_catmark_dart_edgeonly", catmark_dart_edgeonly, levels, kCatmark ); total += checkMesh( "test_catmark_dart_edgeonly", catmark_dart_edgeonly, levels, kCatmark );
#endif #endif
#ifdef test_catmark_tent #ifdef test_catmark_tent
#include "../shapes/catmark_tent.h" #include "../shapes/catmark_tent.h"
total += checkMesh( "test_catmark_tent", catmark_tent, levels, kCatmark ); total += checkMesh( "test_catmark_tent", catmark_tent, levels, kCatmark );
#endif #endif
#ifdef test_catmark_tent_creases0 #ifdef test_catmark_tent_creases0
#include "../shapes/catmark_tent_creases0.h" #include "../shapes/catmark_tent_creases0.h"
total += checkMesh( "test_catmark_tent_creases0", catmark_tent_creases0, levels ); total += checkMesh( "test_catmark_tent_creases0", catmark_tent_creases0, levels );
#endif #endif
#ifdef test_catmark_tent_creases1 #ifdef test_catmark_tent_creases1
#include "../shapes/catmark_tent_creases1.h" #include "../shapes/catmark_tent_creases1.h"
total += checkMesh( "test_catmark_tent_creases1", catmark_tent_creases1, levels ); total += checkMesh( "test_catmark_tent_creases1", catmark_tent_creases1, levels );
#endif #endif
#ifdef test_loop_triangle_edgeonly #ifdef test_loop_triangle_edgeonly
#include "../shapes/loop_triangle_edgeonly.h" #include "../shapes/loop_triangle_edgeonly.h"
total += checkMesh( "test_loop_triangle_edgeonly", loop_triangle_edgeonly, levels, kLoop ); total += checkMesh( "test_loop_triangle_edgeonly", loop_triangle_edgeonly, levels, kLoop );
#endif #endif
#ifdef test_loop_triangle_edgecorner #ifdef test_loop_triangle_edgecorner
#include "../shapes/loop_triangle_edgecorner.h" #include "../shapes/loop_triangle_edgecorner.h"
total += checkMesh( "test_loop_triangle_edgecorner", loop_triangle_edgecorner, levels, kLoop ); total += checkMesh( "test_loop_triangle_edgecorner", loop_triangle_edgecorner, levels, kLoop );
#endif #endif
#ifdef test_loop_saddle_edgeonly #ifdef test_loop_saddle_edgeonly
#include "../shapes/loop_saddle_edgeonly.h" #include "../shapes/loop_saddle_edgeonly.h"
total += checkMesh( "test_loop_saddle_edgeonly", loop_saddle_edgeonly, levels, kLoop ); total += checkMesh( "test_loop_saddle_edgeonly", loop_saddle_edgeonly, levels, kLoop );
#endif #endif
#ifdef test_loop_saddle_edgecorner #ifdef test_loop_saddle_edgecorner
#include "../shapes/loop_saddle_edgecorner.h" #include "../shapes/loop_saddle_edgecorner.h"
total += checkMesh( "test_loop_saddle_edgecorner", loop_saddle_edgecorner, levels, kLoop ); total += checkMesh( "test_loop_saddle_edgecorner", loop_saddle_edgecorner, levels, kLoop );
#endif #endif
#ifdef test_loop_icosahedron #ifdef test_loop_icosahedron
#include "../shapes/loop_icosahedron.h" #include "../shapes/loop_icosahedron.h"
total += checkMesh( "test_loop_icosahedron", loop_icosahedron, levels, kLoop ); total += checkMesh( "test_loop_icosahedron", loop_icosahedron, levels, kLoop );
#endif #endif
#ifdef test_loop_cube #ifdef test_loop_cube
#include "../shapes/loop_cube.h" #include "../shapes/loop_cube.h"
total += checkMesh( "test_loop_cube", loop_cube, levels, kLoop ); total += checkMesh( "test_loop_cube", loop_cube, levels, kLoop );
#endif #endif
#ifdef test_loop_cube_creases0 #ifdef test_loop_cube_creases0
#include "../shapes/loop_cube_creases0.h" #include "../shapes/loop_cube_creases0.h"
total += checkMesh( "test_loop_cube_creases0", loop_cube_creases0,levels, kLoop ); total += checkMesh( "test_loop_cube_creases0", loop_cube_creases0,levels, kLoop );
#endif #endif
#ifdef test_loop_cube_creases1 #ifdef test_loop_cube_creases1
#include "../shapes/loop_cube_creases1.h" #include "../shapes/loop_cube_creases1.h"
total += checkMesh( "test_loop_cube_creases1", loop_cube_creases1, levels, kLoop ); total += checkMesh( "test_loop_cube_creases1", loop_cube_creases1, levels, kLoop );
#endif #endif
#ifdef test_bilinear_cube #ifdef test_bilinear_cube
#include "../shapes/bilinear_cube.h" #include "../shapes/bilinear_cube.h"
total += checkMesh( "test_bilinear_cube", bilinear_cube, levels, kBilinear ); total += checkMesh( "test_bilinear_cube", bilinear_cube, levels, kBilinear );
#endif #endif
if (total==0) if (total==0)

View File

@ -0,0 +1,92 @@
//
// 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.
//
static char const * catmark_square_hedit0 =
"# This file uses centimeters as units for non-parametric coordinates.\n"
"\n"
"v -1 -1 0\n"
"v -0.333333 -1 0\n"
"v 0.333333 -1 0\n"
"v 1 -1 0\n"
"v -1 -0.333333 0\n"
"v -0.333333 -0.333333 0\n"
"v 0.333333 -0.333333 0\n"
"v 1 -0.333333 0\n"
"v -1 0.333333 0\n"
"v -0.333333 0.333333 0\n"
"v 0.333333 0.333333 0\n"
"v 1 0.333333 0\n"
"v -1 1 0\n"
"v -0.333333 1 0\n"
"v 0.333333 1 0\n"
"v 1 1 0\n"
"vt 0.0 0.0\n"
"vn 0.0 0.0 0.0\n"
"s off\n"
"f 1/1/1 2/1/1 6/1/1 5/1/1\n"
"f 2/1/1 3/1/1 7/1/1 6/1/1\n"
"f 3/1/1 4/1/1 8/1/1 7/1/1\n"
"f 5/1/1 6/1/1 10/1/1 9/1/1\n"
"f 6/1/1 7/1/1 11/1/1 10/1/1\n"
"f 7/1/1 8/1/1 12/1/1 11/1/1\n"
"f 9/1/1 10/1/1 14/1/1 13/1/1\n"
"f 10/1/1 11/1/1 15/1/1 14/1/1\n"
"f 11/1/1 12/1/1 16/1/1 15/1/1\n"
"t interpolateboundary 1/0/0 2\n"
"t vertexedit 16/24/3 3 0 1 0 3 0 1 1 3 0 1 2 3 0 1 3 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 add P value\n"
"t vertexedit 20/24/3 4 4 1 1 0 4 4 1 1 1 4 4 1 1 2 4 4 1 1 3 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 add P value\n"
"t vertexedit 24/24/3 5 8 0 1 1 0 5 8 0 1 1 1 5 8 0 1 1 2 5 8 0 1 1 3 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 add P value\n"
;

View File

@ -0,0 +1,91 @@
//
// 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.
//
static char const * catmark_square_hedit1 =
"# This file uses centimeters as units for non-parametric coordinates.\n"
"\n"
"v -1 -1 0\n"
"v -0.333333 -1 0\n"
"v 0.333333 -1 0\n"
"v 1 -1 0\n"
"v -1 -0.333333 0\n"
"v -0.333333 -0.333333 0\n"
"v 0.333333 -0.333333 0\n"
"v 1 -0.333333 0\n"
"v -1 0.333333 0\n"
"v -0.333333 0.333333 0\n"
"v 0.333333 0.333333 0\n"
"v 1 0.333333 0\n"
"v -1 1 0\n"
"v -0.333333 1 0\n"
"v 0.333333 1 0\n"
"v 1 1 0\n"
"vt 0.0 0.0\n"
"vn 0.0 0.0 0.0\n"
"s off\n"
"f 1/1/1 2/1/1 6/1/1 5/1/1\n"
"f 2/1/1 3/1/1 7/1/1 6/1/1\n"
"f 3/1/1 4/1/1 8/1/1 7/1/1\n"
"f 5/1/1 6/1/1 10/1/1 9/1/1\n"
"f 6/1/1 7/1/1 11/1/1 10/1/1\n"
"f 7/1/1 8/1/1 12/1/1 11/1/1\n"
"f 9/1/1 10/1/1 14/1/1 13/1/1\n"
"f 10/1/1 11/1/1 15/1/1 14/1/1\n"
"f 11/1/1 12/1/1 16/1/1 15/1/1\n"
"t interpolateboundary 1/0/0 2\n"
"t vertexedit 16/24/3 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 add P value\n"
"t vertexedit 16/4/3 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3 10 10 10 10 set P sharpness\n"
;

View File

@ -0,0 +1,91 @@
//
// 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.
//
static char const * catmark_square_hedit2 =
"# This file uses centimeters as units for non-parametric coordinates.\n"
"\n"
"v -1 -1 0\n"
"v -0.333333 -1 0\n"
"v 0.333333 -1 0\n"
"v 1 -1 0\n"
"v -1 -0.333333 0\n"
"v -0.333333 -0.333333 0\n"
"v 0.333333 -0.333333 0\n"
"v 1 -0.333333 0\n"
"v -1 0.333333 0\n"
"v -0.333333 0.333333 0\n"
"v 0.333333 0.333333 0\n"
"v 1 0.333333 0\n"
"v -1 1 0\n"
"v -0.333333 1 0\n"
"v 0.333333 1 0\n"
"v 1 1 0\n"
"vt 0.0 0.0\n"
"vn 0.0 0.0 0.0\n"
"s off\n"
"f 1/1/1 2/1/1 6/1/1 5/1/1\n"
"f 2/1/1 3/1/1 7/1/1 6/1/1\n"
"f 3/1/1 4/1/1 8/1/1 7/1/1\n"
"f 5/1/1 6/1/1 10/1/1 9/1/1\n"
"f 6/1/1 7/1/1 11/1/1 10/1/1\n"
"f 7/1/1 8/1/1 12/1/1 11/1/1\n"
"f 9/1/1 10/1/1 14/1/1 13/1/1\n"
"f 10/1/1 11/1/1 15/1/1 14/1/1\n"
"f 11/1/1 12/1/1 16/1/1 15/1/1\n"
"t interpolateboundary 1/0/0 2\n"
"t vertexedit 16/24/3 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 add P value\n"
"t edgeedit 16/4/3 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3 10 10 10 10 set P sharpness\n"
;

View File

@ -0,0 +1,92 @@
//
// 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.
//
static char const * catmark_square_hedit3 =
"# This file uses centimeters as units for non-parametric coordinates.\n"
"\n"
"v -1 -1 0\n"
"v -0.333333 -1 0\n"
"v 0.333333 -1 0\n"
"v 1 -1 0\n"
"v -1 -0.333333 0\n"
"v -0.333333 -0.333333 0\n"
"v 0.333333 -0.333333 0\n"
"v 1 -0.333333 0\n"
"v -1 0.333333 0\n"
"v -0.333333 0.333333 0\n"
"v 0.333333 0.333333 0\n"
"v 1 0.333333 0\n"
"v -1 1 0\n"
"v -0.333333 1 0\n"
"v 0.333333 1 0\n"
"v 1 1 0\n"
"vt 0.0 0.0\n"
"vn 0.0 0.0 0.0\n"
"s off\n"
"f 1/1/1 2/1/1 6/1/1 5/1/1\n"
"f 2/1/1 3/1/1 7/1/1 6/1/1\n"
"f 3/1/1 4/1/1 8/1/1 7/1/1\n"
"f 5/1/1 6/1/1 10/1/1 9/1/1\n"
"f 6/1/1 7/1/1 11/1/1 10/1/1\n"
"f 7/1/1 8/1/1 12/1/1 11/1/1\n"
"f 9/1/1 10/1/1 14/1/1 13/1/1\n"
"f 10/1/1 11/1/1 15/1/1 14/1/1\n"
"f 11/1/1 12/1/1 16/1/1 15/1/1\n"
"t interpolateboundary 1/0/0 2\n"
"t vertexedit 16/24/3 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 add P value\n"
"t edgeedit 16/4/3 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3 10 10 10 10 set P sharpness\n"
"t vertexedit 16/4/3 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3 10 10 10 10 set P sharpness\n"
;