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(CUDA)
find_package(GLUT)
find_package(PTex)
if (NOT APPLE)
find_package(GLEW)
find_package(GLEW REQUIRED)
endif()
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
set( OSD_LINK_TARGET osd_dynamic )
if (WIN32)
add_definitions(
# GLEW gets built as a static library in Windows
# Link against the static version of GLEW.
-DGLEW_STATIC
)
# Link examples & regressions statically against Osd for
@ -178,9 +259,11 @@ if(MSVC)
)
endif(MSVC)
# Macro for adding a cuda executable if cuda is found and a regular
# executable otherwise.
macro(_add_executable target)
macro(_add_possibly_cuda_executable target)
if(CUDA_FOUND)
cuda_add_executable(${target} ${ARGN})
else()
@ -188,9 +271,10 @@ macro(_add_executable target)
endif()
endmacro()
# Macro for adding a cuda library if cuda is found and a regular
# library otherwise.
macro(_add_library target)
macro(_add_possibly_cuda_library target)
if(CUDA_FOUND)
cuda_add_library(${target} ${ARGN})
else()
@ -199,6 +283,29 @@ macro(_add_library target)
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)

View File

@ -1,6 +1,6 @@
# 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.
@ -39,7 +39,7 @@ Optional :
make
</code></pre>
### Useful cmake options ###
### Useful cmake options and environment variables ###
<pre><code>
-DCMAKE_BUILD_TYPE=[Debug|Release]
@ -48,8 +48,17 @@ Optional :
-DMAYA_LOCATION=[path to Maya]
-DPTEX_LOCATION=[path to Ptex]
-DGLUT_LOCATION=[path to GLUT]
-DGLEW_LOCATION=[path to GLEW]
</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 ###
<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.
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 ##
#### 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 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.
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 ##

View File

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

View File

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

View File

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

View File

@ -56,18 +56,18 @@
#
# - 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
# 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_EXECUTABLE Path to Maya's executable
# MAYA_<lib>_FOUND Defined if <lib> has been found
# MAYA_<lib>_LIBRARY Path to <lib> library
# 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>
@ -88,83 +88,97 @@ SET(MAYA_VERSION_2012 TRUE)
IF(APPLE)
FIND_PATH(MAYA_BASE_DIR include/maya/MFn.h PATH
ENV MAYA_LOCATION
"/Applications/Autodesk/maya2012.17/Maya.app/Contents"
"/Applications/Autodesk/maya2012/Maya.app/Contents"
"/Applications/Autodesk/maya2011/Maya.app/Contents"
"/Applications/Autodesk/maya2010/Maya.app/Contents"
)
${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
"/Applications/Autodesk/maya2013/Maya.app/Contents"
"/Applications/Autodesk/maya2012.17/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
PATHS
ENV MAYA_LOCATION
${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR}
PATH_SUFFIXES
Maya.app/contents/MacOS/
Maya.app/contents/MacOS/
DOC "Maya's libraries path"
)
ENDIF(APPLE)
IF(UNIX)
FIND_PATH(MAYA_BASE_DIR include/maya/MFn.h PATH
ENV MAYA_LOCATION
"/usr/autodesk/maya2012.17-x64"
"/usr/autodesk/maya2012-x64"
"/usr/autodesk/maya2011-x64"
"/usr/autodesk/maya2010-x64"
)
${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
"/usr/autodesk/maya2013-x64"
"/usr/autodesk/maya2012.17-x64"
"/usr/autodesk/maya2012-x64"
"/usr/autodesk/maya2011-x64"
"/usr/autodesk/maya2010-x64"
)
FIND_PATH(MAYA_LIBRARY_DIR libOpenMaya.so
PATHS
ENV MAYA_LOCATION
${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR}
PATH_SUFFIXES
lib/
lib/
DOC "Maya's libraries path"
)
ENDIF(UNIX)
IF(WIN32)
FIND_PATH(MAYA_BASE_DIR include/maya/MFn.h PATH
ENV MAYA_LOCATION
"C:/Program Files/Autodesk/Maya2012-x64"
"C:/Program Files/Autodesk/Maya2012"
"C:/Program Files (x86)/Autodesk/Maya2012"
"C:/Autodesk/maya-2012x64"
"C:/Program Files/Autodesk/Maya2011-x64"
"C:/Program Files/Autodesk/Maya2011"
"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"
)
${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
"C:/Program Files/Autodesk/Maya2013-x64"
"C:/Program Files/Autodesk/Maya2013"
"C:/Program Files (x86)/Autodesk/Maya2013"
"C:/Autodesk/maya-2013x64"
"C:/Program Files/Autodesk/Maya2012-x64"
"C:/Program Files/Autodesk/Maya2012"
"C:/Program Files (x86)/Autodesk/Maya2012"
"C:/Autodesk/maya-2012x64"
"C:/Program Files/Autodesk/Maya2011-x64"
"C:/Program Files/Autodesk/Maya2011"
"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
PATHS
ENV MAYA_LOCATION
${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR}
PATH_SUFFIXES
lib/
lib/
DOC "Maya's libraries path"
)
ENDIF(WIN32)
FIND_PATH(MAYA_INCLUDE_DIR maya/MFn.h
PATHS
ENV MAYA_LOCATION
${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR}
PATH_SUFFIXES
../../devkit/include/
include/
../../devkit/include/
include/
DOC "Maya's devkit headers path"
)
FIND_PATH(MAYA_LIBRARY_DIR OpenMaya
PATHS
ENV MAYA_LOCATION
${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR}
PATH_SUFFIXES
../../devkit/include/
include/
../../devkit/include/
include/
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
PATHS
ENV MAYA_LOCATION
${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR}
PATH_SUFFIXES
/devkit/plug-ins/
/devkit/plug-ins/
DOC "Maya's devkit headers path"
)
LIST(APPEND MAYA_INCLUDE_DIRS ${MAYA_DEVKIT_INC_DIR})
@ -185,7 +200,7 @@ FOREACH(MAYA_LIB
OpenMayaAnim
OpenMayaFX
OpenMayaRender
OpenMayaUI
OpenMayaUI
Image
Foundation
IMFbase
@ -195,24 +210,26 @@ FOREACH(MAYA_LIB
)
FIND_LIBRARY(MAYA_${MAYA_LIB}_LIBRARY ${MAYA_LIB}
PATHS
ENV MAYA_LOCATION
${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR}
PATH_SUFFIXES
MacOS/
lib/
MacOS/
lib/
DOC "Maya's ${MAYA_LIB} library path"
)
LIST(APPEND ${MAYA_LIBRARIES} MAYA_${MAYA_LIB}_LIBRARY)
ENDFOREACH(MAYA_LIB)
FIND_PROGRAM(MAYA_EXECUTABLE maya
PATHS
ENV MAYA_LOCATION
${MAYA_LOCATION}
$ENV{MAYA_LOCATION}
${MAYA_BASE_DIR}
PATH_SUFFIXES
MacOS/
bin/
MacOS/
bin/
DOC "Maya's executable path"
)

View File

@ -67,32 +67,32 @@ find_package(PackageHandleStandardArgs)
if (APPLE)
find_library( OPENCL_LIBRARIES
find_library( OPENCL_LIBRARIES
NAMES
OpenCL
OpenCL
DOC "OpenCL lib for OSX"
)
find_path( OPENCL_INCLUDE_DIRS
find_path( OPENCL_INCLUDE_DIRS
NAMES
OpenCL/cl.h
OpenCL/cl.h
DOC "Include for OpenCL on OSX"
)
find_path( _OPENCL_CPP_INCLUDE_DIRS
NAMES
OpenCL/cl.hpp
NAMES
OpenCL/cl.hpp
DOC "Include for OpenCL CPP bindings on OSX"
)
elseif (WIN32)
find_path( OPENCL_INCLUDE_DIRS
find_path( OPENCL_INCLUDE_DIRS
NAMES
CL/cl.h
CL/cl.h
)
find_path( _OPENCL_CPP_INCLUDE_DIRS
find_path( _OPENCL_CPP_INCLUDE_DIRS
NAMES
CL/cl.hpp
)
@ -103,39 +103,39 @@ elseif (WIN32)
set(OPENCL_LIB_DIR "$ENV{ATISTREAMSDKROOT}/lib/x86")
endif()
find_library( OPENCL_LIBRARIES
find_library( OPENCL_LIBRARIES
NAMES
OpenCL.lib
PATHS
${OPENCL_LIB_DIR}
OpenCL.lib
PATHS
${OPENCL_LIB_DIR}
ENV OpenCL_LIBPATH
)
get_filename_component( _OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE )
find_path( OPENCL_INCLUDE_DIRS
find_path( OPENCL_INCLUDE_DIRS
NAMES
CL/cl.h
PATHS
"${_OPENCL_INC_CAND}"
CL/cl.h
PATHS
"${_OPENCL_INC_CAND}"
ENV OpenCL_INCPATH
)
find_path( _OPENCL_CPP_INCLUDE_DIRS
find_path( _OPENCL_CPP_INCLUDE_DIRS
NAMES
CL/cl.hpp
PATHS
"${_OPENCL_INC_CAND}"
CL/cl.hpp
PATHS
"${_OPENCL_INC_CAND}"
ENV OpenCL_INCPATH
)
elseif (UNIX)
find_library( OPENCL_LIBRARIES
find_library( OPENCL_LIBRARIES
NAMES
OpenCL
PATHS
ENV LD_LIBRARY_PATH
PATHS
ENV LD_LIBRARY_PATH
ENV OpenCL_LIBPATH
)
@ -143,29 +143,29 @@ elseif (UNIX)
get_filename_component( _OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE )
find_path( OPENCL_INCLUDE_DIRS
NAMES
CL/cl.h
PATHS
${_OPENCL_INC_CAND}
"/usr/local/cuda/include"
"/opt/AMDAPP/include"
find_path( OPENCL_INCLUDE_DIRS
NAMES
CL/cl.h
PATHS
${_OPENCL_INC_CAND}
"/usr/local/cuda/include"
"/opt/AMDAPP/include"
ENV OpenCL_INCPATH
)
find_path( _OPENCL_CPP_INCLUDE_DIRS
find_path( _OPENCL_CPP_INCLUDE_DIRS
NAMES
CL/cl.hpp
PATHS
${_OPENCL_INC_CAND}
"/usr/local/cuda/include"
"/opt/AMDAPP/include"
CL/cl.hpp
PATHS
${_OPENCL_INC_CAND}
"/usr/local/cuda/include"
"/opt/AMDAPP/include"
ENV OpenCL_INCPATH
)
else ()
message( "Could not determine OpenCL platform" )
message( "Could not determine OpenCL platform" )
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.
#
if (APPLE)
message(STATUS "The OsX platform currently does not support all "
"the OpenGL features required by the glutViewer example : skipping.")
else()
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)"
)
if( OPENGL_FOUND AND (GLEW_FOUND AND GLUT_FOUND) OR (APPLE AND GLUT_FOUND))
add_subdirectory(glutViewer)
if(PTEX_FOUND AND (NOT APPLE))
add_subdirectory(ptexViewer)
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()
if(MAYA_FOUND)
add_subdirectory(mayaViewer)
else()
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."
)
if(PTEX_FOUND)
add_subdirectory(mayaPtexViewer_siggraph2012)
endif()
endif()

View File

@ -68,7 +68,7 @@ inline int _ConvertSMVer2Cores_local(int major, int minor)
int Cores;
} sSMtoCores;
sSMtoCores nGpuArchCoresPerSM[] =
sSMtoCores nGpuArchCoresPerSM[] =
{ { 0x10, 8 }, // Tesla Generation (SM 1.0) G80 class
{ 0x11, 8 }, // Tesla Generation (SM 1.1) G8x 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 ( best_SM_arch > 2 ) {
// 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_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:
#ifndef _WINDOWS
void Start() {
void Start() {
struct timeval l_rtime;
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() {
struct timeval l_rtime;
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;
}
double GetElapsed() const {
return _elapsed;
}
double GetTotalElapsed() const {
return _totalElapsed;
}
}
#else
Stopwatch() {
QueryPerformanceFrequency(&_frequency);
}
void Start()
{
void Start()
{
QueryPerformanceCounter(&_time);
}
void Stop()
{
void Stop()
{
LARGE_INTEGER currentTime;
QueryPerformanceCounter(&currentTime);
_elapsed = currentTime.QuadPart - _time.QuadPart;
@ -113,7 +113,7 @@ public:
double GetElapsed() const {
return (double) _elapsed / _frequency.QuadPart;
}
double GetTotalElapsed() const {
return (double) _totalElapsed / _frequency.QuadPart;
}

View File

@ -57,27 +57,18 @@
# *** glutViewer ***
set(PLATFORM_LIBRARIES
set(SHADER_FILES
shader.glsl
)
set(PLATFORM_LIBRARIES
${OSD_LINK_TARGET}
${ILMBASE_LIBS_DIRECTORY}
${ILMBASE_LIBRARIES}
${OPENGL_LIBRARY}
${GLEW_LIBRARY}
${GLUT_LIBRARIES}
)
if(OPENCL_FOUND)
add_definitions(
-DOPENSUBDIV_HAS_OPENCL
)
endif()
if(CUDA_FOUND)
add_definitions(
-DOPENSUBDIV_HAS_CUDA
)
endif()
include_directories(
${PROJECT_SOURCE_DIR}/opensubdiv
${PROJECT_SOURCE_DIR}/regression
@ -87,33 +78,38 @@ include_directories(
)
#-------------------------------------------------------------------------------
# Macro for adding a (potentially cuda) executable.
macro(_add_glut_executable target)
# 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})
_add_executable(${target} ${ARGN})
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" 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()
if(APPLE)
_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
${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__)
#include <GLUT/glut.h>
#else
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>
#endif
@ -81,17 +82,25 @@
#include <cuda_runtime_api.h>
#include <cuda_gl_interop.h>
#include "cudaInit.h"
#include "../common/cudaInit.h"
#endif
static const char *shaderSource =
#include "shader.inc"
;
#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) { }
};
@ -101,7 +110,7 @@ std::vector<SimpleShape> g_defaultShapes;
int g_currentShape = 0;
void
void
initializeShapes( ) {
#include <shapes/bilinear_cube.h>
@ -161,6 +170,20 @@ initializeShapes( ) {
#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));
@ -191,17 +214,22 @@ int g_frame = 0,
g_repeatCount = 0;
// GLUT GUI variables
int g_wire = 0,
int g_freeze = 0,
g_wire = 0,
g_drawCoarseMesh = 1,
g_drawNormals = 0,
g_mbutton;
g_drawHUD = 1,
g_mbutton[3] = {0, 0, 0};
float g_rx = 0,
g_ry = 0,
g_prev_x = 0,
float g_rotate[2] = {0, 0},
g_prev_x = 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;
// performance
@ -209,22 +237,33 @@ float g_cpuTime = 0;
float g_gpuTime = 0;
// geometry
std::vector<float> g_positions,
std::vector<float> g_orgPositions,
g_positions,
g_normals;
Scheme g_scheme;
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;
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::OsdVertexBuffer * g_vertexBuffer = 0;
//------------------------------------------------------------------------------
inline void
//------------------------------------------------------------------------------
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] };
@ -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[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
//------------------------------------------------------------------------------
inline void
normalize(float * p) {
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;
}
//------------------------------------------------------------------------------
inline void
multMatrix(float *d, const float *a, const float *b) {
//------------------------------------------------------------------------------
static void
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
@ -259,13 +314,13 @@ calcNormals(OpenSubdiv::OsdHbrMesh * mesh, std::vector<float> const & pos, std::
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 );
@ -281,30 +336,43 @@ calcNormals(OpenSubdiv::OsdHbrMesh * mesh, std::vector<float> const & pos, std::
}
//------------------------------------------------------------------------------
void
void
updateGeom() {
int nverts = (int)g_positions.size() / 3;
int nverts = (int)g_orgPositions.size() / 3;
std::vector<float> vertex;
vertex.reserve(nverts*6);
const float *p = &g_positions[0];
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]+move);
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)
if (!g_vertexBuffer)
g_vertexBuffer = g_osdmesh->InitializeVertexBuffer(6);
g_vertexBuffer->UpdateData(&vertex[0], nverts);
@ -324,41 +392,16 @@ updateGeom() {
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
//-------------------------------------------------------------------------------
void
fitFrame() {
g_pan[0] = g_pan[1] = 0;
g_dolly = g_size;
}
//------------------------------------------------------------------------------
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) {
g_width = width;
@ -369,29 +412,55 @@ reshape(int width, int height) {
#define snprintf _snprintf
#endif
#define drawString(x, y, fmt, ...) \
#define drawString(x, y, ...) \
{ char line[1024]; \
snprintf(line, 1024, fmt, __VA_ARGS__); \
snprintf(line, 1024, __VA_ARGS__); \
char *p = line; \
glWindowPos2f(x, y); \
glWindowPos2i(x, y); \
while(*p) { glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *p++); } }
//------------------------------------------------------------------------------
const char *getKernelName(int kernel) {
if (kernel == OpenSubdiv::OsdKernelDispatcher::kCPU)
if (kernel == OpenSubdiv::OsdKernelDispatcher::kCPU)
return "CPU";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kOPENMP)
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kOPENMP)
return "OpenMP";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kCUDA)
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kCUDA)
return "Cuda";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kGLSL)
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kGLSL)
return "GLSL";
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kCL)
else if (kernel == OpenSubdiv::OsdKernelDispatcher::kCL)
return "OpenCL";
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
drawNormals() {
@ -404,103 +473,312 @@ drawNormals() {
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],
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,
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
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() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
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;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, aspect, 0.001, 100.0);
gluPerspective(45.0, aspect, 0.01, 500.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -g_dolly);
glRotatef(g_ry, 1, 0, 0);
glRotatef(g_rx, 0, 1, 0);
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();
#ifdef VARYING_NORMAL
GLuint bVarying = g_varyingBuffer->GetGpuBuffer();
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, bVertex);
glVertexPointer(3, GL_FLOAT, 12, ((float*)(0)));
glBindBuffer(GL_ARRAY_BUFFER, bVarying);
glNormalPointer(GL_FLOAT, 12, ((float*)(0)));
#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);
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);
if (g_wire == 0) {
glColor3f(1.0f, 1.0f, 1.0f);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_LIGHTING);
glDrawElements(g_scheme==kLoop ? GL_TRIANGLES : GL_QUADS, g_numIndices, GL_UNSIGNED_INT, NULL);
GLenum primType = GL_LINES_ADJACENCY;
if (g_scheme == kLoop) {
primType = GL_TRIANGLES;
bindProgram(g_triFillProgram);
} else {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_LIGHTING);
glDrawElements(g_scheme==kLoop ? GL_TRIANGLES : GL_QUADS, g_numIndices, GL_UNSIGNED_INT, NULL);
bindProgram(g_quadFillProgram);
}
if(g_wire == 2){
glColor3f(0.0f, 0.0f, 0.5f);
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) {
glDrawElements(primType, g_numIndices, GL_UNSIGNED_INT, NULL);
}
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)
drawNormals();
if (g_drawCoarseMesh)
drawCoarseMesh(g_drawCoarseMesh);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
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();
glutSwapBuffers();
}
@ -508,11 +786,17 @@ display() {
//------------------------------------------------------------------------------
void motion(int x, int y) {
if(g_mbutton == 0){
g_rx += x - g_prev_x;
g_ry += y - g_prev_y;
}else if(g_mbutton == 1){
g_dolly -= 0.01f*(x - g_prev_x);
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;
}
@ -525,13 +809,13 @@ void mouse(int button, int state, int x, int y) {
g_prev_x = float(x);
g_prev_y = float(y);
g_mbutton = button;
g_mbutton[button] = !state;
}
//------------------------------------------------------------------------------
void quit() {
if(g_osdmesh)
if(g_osdmesh)
delete g_osdmesh;
if (g_vertexBuffer)
@ -551,24 +835,24 @@ void kernelMenu(int k) {
}
//------------------------------------------------------------------------------
void
void
modelMenu(int m) {
if (m < 0)
if (m < 0)
m = 0;
if (m >= (int)g_defaultShapes.size())
m = g_defaultShapes.size() - 1;
if (m >= (int)g_defaultShapes.size())
m = (int)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
void
levelMenu(int l) {
g_level = l;
@ -577,19 +861,23 @@ levelMenu(int l) {
}
//------------------------------------------------------------------------------
void
void
menu(int m) {
}
//------------------------------------------------------------------------------
void
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':
@ -599,23 +887,26 @@ keyboard(unsigned char key, int x, int y) {
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
void
idle() {
g_frame++;
if (not g_freeze)
g_frame++;
updateGeom();
glutPostRedisplay();
if(g_repeatCount != 0 && g_frame >= g_repeatCount)
if (g_repeatCount != 0 and g_frame >= g_repeatCount)
quit();
}
//------------------------------------------------------------------------------
void
void
initGL() {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
@ -626,7 +917,7 @@ initGL() {
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 ambient[4] = {0.0f, 0.0f, 0.0f, 1.0f};
GLfloat diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat shininess = 25.0;
@ -637,17 +928,37 @@ initGL() {
glLightfv(GL_LIGHT0, GL_POSITION, position);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
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) {
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);
@ -667,9 +978,9 @@ int main(int argc, char ** argv) {
OpenSubdiv::OsdGlslKernelDispatcher::Register();
#if OPENSUBDIV_HAS_OPENCL
OpenSubdiv::OsdClKernelDispatcher::Register();
#endif
OpenSubdiv::OsdClKernelDispatcher::Register();
#endif
#if OPENSUBDIV_HAS_CUDA
OpenSubdiv::OsdCudaKernelDispatcher::Register();
@ -691,7 +1002,7 @@ int main(int argc, char ** argv) {
glutAddSubMenu("Model", smenu);
glutAddSubMenu("Kernel", kmenu);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
@ -707,17 +1018,17 @@ int main(int argc, char ** argv) {
g_level = atoi(argv[++i]);
else if (!strcmp(argv[i], "-c"))
g_repeatCount = atoi(argv[++i]);
else
else
filename = argv[i];
}
glGenBuffers(1, &g_indexBuffer);
modelMenu(0);
glutIdleFunc(idle);
glutMainLoop();
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_tbb_LIBRARY}
${PLATFORM_LIBRARIES}
${ILMBASE_LIBRARIES}
${GLEW_LIBRARY}
)

View File

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

View File

@ -77,7 +77,7 @@ OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices,
static OpenSubdiv::HbrBilinearSubdivision<OpenSubdiv::OsdVertex> _bilinear;
static OpenSubdiv::HbrLoopSubdivision<OpenSubdiv::OsdVertex> _loop;
static OpenSubdiv::HbrCatmarkSubdivision<OpenSubdiv::OsdVertex> _catmark;
OpenSubdiv::OsdHbrMesh *hbrMesh;
if (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);
else
else
OSD_ERROR("Face %d will be ignored\n", i);
offset += numVertex;
@ -142,7 +142,7 @@ OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices,
// set edge crease in two different indexing way
int nEdgeCreases = (int)edgeCreases1.size();
for (int i = 0; i < nEdgeCreases; ++i) {
if( edgeCreases1[i] <= 0. )
if( edgeCreases1[i] <= 0. )
continue;
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();
for (int i = 0; i < nEdgeCreases; ++i) {
if( edgeCreases1[i] <= 0. )
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 ( v0 && v1 )
if ( ! (e = v0->GetEdge(v1)) )
e = v1->GetEdge(v0);
if (!e) {
@ -170,14 +170,14 @@ OpenSubdiv::OsdHbrMesh * ConvertToHBR(int nVertices,
}
e->SetSharpness( (float)edgeCreases2[i] );
}
// set corner
{
int nVertexCreases = (int)vtxCreases.size();
for ( int i = 0; i< nVertexCreases; ++i ) {
if( vtxCreases[i] <= 0. )
if( vtxCreases[i] <= 0. )
continue;
OpenSubdiv::OsdHbrVertex * v = hbrMesh->GetVertex(vtxCreaseIndices[i]);
OpenSubdiv::OsdHbrVertex * v = hbrMesh->GetVertex(vtxCreaseIndices[i]);
if (!v) {
OSD_ERROR("Can't find vertex %d\n", vtxCreaseIndices[i]);
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
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
mesh.h
subdivisionTables.h
table.h
vertexEditTables.h
)
install( FILES ${H_FILES}
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
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
// subdivision scheme.
@ -100,7 +100,7 @@ private:
friend class FarMeshFactory<T,U>;
friend class FarDispatcher<T,U>;
// Constructor : build level table at depth 'level'
FarBilinearSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int level );
@ -112,12 +112,12 @@ private:
// Compute-kernel applied to vertices resulting from the refinement of a vertex
void computeVertexPoints(int offset, int level, int start, int end, void * clientdata) const;
private:
typename FarSubdivisionTables<T,U>::template Table<int> _F_ITa;
typename FarSubdivisionTables<T,U>::template Table<unsigned int> _F_IT;
FarTable<int> _F_ITa;
FarTable<unsigned int> _F_IT;
};
template <class T, class U> int
@ -137,12 +137,12 @@ FarBilinearSubdivisionTables<T,U>::GetMemoryUsed() const {
// _F_ITa[1] : valence of the face
//
// _E_ITa[0] : index of the org / dest vertices of the parent edge
// _E_ITa[1] :
// _E_ITa[1] :
//
// _V_ITa[0] : index of the parent vertex
//
template <class T, class U>
FarBilinearSubdivisionTables<T,U>::FarBilinearSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int maxlevel ) :
FarBilinearSubdivisionTables<T,U>::FarBilinearSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int maxlevel ) :
FarSubdivisionTables<T,U>(mesh, maxlevel),
_F_ITa(maxlevel+1),
_F_IT(maxlevel+1)
@ -160,12 +160,12 @@ FarBilinearSubdivisionTables<T,U>::FarBilinearSubdivisionTables( FarMeshFactory<
for (int level=1; level<=maxlevel; ++level) {
// pointer to the first vertex corresponding to this level
this->_vertsOffsets[level] = factory._vertVertIdx[level-1] +
factory._vertVertsList[level-1].size();
this->_vertsOffsets[level] = factory._vertVertIdx[level-1] +
(int)factory._vertVertsList[level-1].size();
typename FarSubdivisionTables<T,U>::VertexKernelBatch * batch = & (this->_batches[level-1]);
// Face vertices
// Face vertices
// "For each vertex, gather all the vertices from the parent face."
int offset = 0;
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_IT.SetMarker(level, &F_IT[offset]);
// Edge vertices
// Edge vertices
// "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();
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]);
// Vertex vertices
// Vertex vertices
// "Pass down the parent vertex"
offset = 0;
@ -230,10 +230,10 @@ FarBilinearSubdivisionTables<T,U>::FarBilinearSubdivisionTables( FarMeshFactory<
}
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);
typename FarSubdivisionTables<T,U>::VertexKernelBatch const * batch = & (this->_batches[level-1]);
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
//
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 {
assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0),
* 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];
for (int i=start; i<end; ++i, ++vdst ) {
vdst->Clear(clientdata);
int h = F_ITa[2*i ],
int h = F_ITa[2*i ],
n = F_ITa[2*i+1];
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
//
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 {
assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0),
* 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 ) {
vdst->Clear(clientdata);
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
//
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 {
assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0),
* vdst = vsrc + offset + start;
@ -329,7 +329,7 @@ FarBilinearSubdivisionTables<T,U>::computeVertexPoints( int offset, int level, i
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->AddVaryingWithWeight( vsrc[p], 1.0f, clientdata );

View File

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

View File

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

View File

@ -82,14 +82,14 @@ template <class T, class U=T> class FarLoopSubdivisionTables : public FarSubdivi
public:
// Compute the positions of refined vertices using the specified kernels
virtual void Refine( int level, void * data=0 ) const;
private:
virtual void Apply( int level, void * data=0 ) const;
private:
friend class FarMeshFactory<T,U>;
friend class FarDispatcher<T,U>;
// Constructor : build level table at depth 'level'
FarLoopSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int level );
@ -100,7 +100,7 @@ private:
// Compute-kernel applied to vertices resulting from the refinement of a vertex
// 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;
// Compute-kernel applied to vertices resulting from the refinement of a vertex
// Kernel "B" Handles the k_Crease and k_Corner rules
void computeVertexPointsB(int offset,int level, int start, int end, void * clientdata) const;
@ -114,7 +114,7 @@ private:
// codices detail :
//
// _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[3] : of the parent edge
//
@ -125,8 +125,8 @@ private:
// _V_ITa[3] : index of adjacent edge 1 (k_Crease rule)
//
template <class T, class U>
FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int maxlevel )
: FarSubdivisionTables<T,U>(mesh, maxlevel)
FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> const & factory, FarMesh<T,U> * mesh, int maxlevel )
: FarSubdivisionTables<T,U>(mesh, maxlevel)
{
std::vector<int> const & remap = factory._remapTable;
@ -141,13 +141,13 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
for (int level=1; level<=maxlevel; ++level) {
// pointer to the first vertex corresponding to this level
this->_vertsOffsets[level] = factory._vertVertIdx[level-1] +
factory._vertVertsList[level-1].size();
this->_vertsOffsets[level] = factory._vertVertIdx[level-1] +
(int)factory._vertVertsList[level-1].size();
typename FarSubdivisionTables<T,U>::VertexKernelBatch * batch = & (this->_batches[level-1]);
// Edge vertices
unsigned int * E_IT = this->_E_IT[level-1];
// Edge vertices
int * E_IT = this->_E_IT[level-1];
float * E_W = this->_E_W[level-1];
batch->kernelE = (int)factory._edgeVertsList[level].size();
for (int i=0; i < batch->kernelE; ++i) {
@ -182,9 +182,9 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
this->_E_IT.SetMarker(level, &E_IT[4*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 * V_ITa = this->_V_ITa[level-1];
@ -198,19 +198,19 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
assert(v and pv);
// Look at HbrCatmarkSubdivision<T>::Subdivide for more details about
// the multi-pass interpolation
// the multi-pass interpolation
int masks[2], npasses;
float weights[2];
masks[0] = pv->GetMask(false);
masks[1] = pv->GetMask(true);
// If the masks are identical, only a single pass is necessary. If the
// vertex is transitionning to another rule, two passes are necessary,
// except when transitionning from k_Dart to k_Smooth : the same
// vertex is transitioning to another rule, two passes are necessary,
// except when transitioning from k_Dart to k_Smooth : the same
// compute kernel is applied twice. Combining this special case allows
// to batch the compute kernels into fewer calls.
if (masks[0] != masks[1] and (
not (masks[0]==HbrVertex<T>::k_Smooth and
not (masks[0]==HbrVertex<T>::k_Smooth and
masks[1]==HbrVertex<T>::k_Dart))) {
weights[1] = pv->GetFractionalMask();
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() ];
e = e->GetPrev()->GetOpposite();
if (e==start) 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+4] = remap[op.eidx[1]];
break;
}
}
case HbrVertex<T>::k_Corner :
// in the case of a k_Crease / k_Corner pass combination, we
// need to set the valence to -1 to tell the "B" Kernel to
@ -284,7 +284,7 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
}
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
V_W[i] = 0.0;
else
@ -302,11 +302,11 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
}
}
template <class T, class U> void
FarLoopSubdivisionTables<T,U>::Refine( int level, void * clientdata ) const
template <class T, class U> void
FarLoopSubdivisionTables<T,U>::Apply( int level, void * clientdata ) const
{
assert(this->_mesh and level>0);
typename FarSubdivisionTables<T,U>::VertexKernelBatch const * batch = & (this->_batches[level-1]);
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);
if (batch->kernelA2.first < batch->kernelA2.second)
dispatch->ApplyLoopVertexVerticesKernelA(this->_mesh, offset, true, level, batch->kernelA2.first, batch->kernelA2.second, clientdata);
}
}
//
// 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 {
assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0),
* 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];
for (int i=start; i<end; ++i, ++vdst ) {
vdst->Clear(clientdata);
int eidx0 = E_IT[4*i+0],
eidx1 = E_IT[4*i+1],
eidx2 = E_IT[4*i+2],
eidx3 = E_IT[4*i+3];
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[eidx1], endPtWeight, clientdata );
if (eidx2!=-1) {
// Apply fractional sharpness
float oppPtWeight = E_W[i*2+1];
vdst->AddWithWeight( vsrc[eidx2], 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
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 {
assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0),
* 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];
for (int i=start; i<end; ++i, ++vdst ) {
if (not pass)
vdst->Clear(clientdata);
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
eidx1=V_ITa[5*i+4]; // index of the second crease rule edge
float weight = pass ? V_W[i] : 1.0f - V_W[i];
// In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the
// In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the
// k_Smooth kernel runs much more often than this one)
if (weight>0.0f and weight<1.0f and n>0)
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
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 {
assert(this->_mesh);
U * vsrc = &this->_mesh->GetVertices().at(0),
* 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];
for (int i=start; i<end; ++i, ++vdst ) {
vdst->Clear(clientdata);
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)
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],
wp = 1.0f/n,
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;
vdst->AddWithWeight( vsrc[p], weight * (1.0f-(beta*n)), clientdata);
for (int j=0; j<n; ++j)
vdst->AddWithWeight( vsrc[V_IT[h+j]], weight * beta );
vdst->AddVaryingWithWeight( vsrc[p], 1.0f, clientdata );
}
}
}
} // 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 FarSubdivisionTables;
template <class T, class U> class FarDispatcher;
template <class T, class U> class FarVertexEditTables;
// Core serialized subdivision mesh class.
//
@ -79,7 +80,7 @@ template <class T, class U> class FarDispatcher;
template <class T, class U=T> class FarMesh {
public:
~FarMesh();
// returns the subdivision method
@ -93,18 +94,25 @@ public:
k_BilinearQuads,
k_Triangles,
};
// returns the type of patches described by the face vertices list
// returns the type of patches described by the face vertices list
PatchType GetPatchType() const { return _patchtype; }
// returns the list of vertices in the mesh (from subdiv level 0 to N)
std::vector<U> & GetVertices() { return _vertices; }
U & GetVertex(int index) { return _vertices[index]; }
// returns the list of indices of the vertices of the faces in the mesh
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
// buffer.
int GetNumCoarseVertices() const;
@ -112,14 +120,14 @@ public:
// returns the total number of vertices in the mesh across across all depths
int GetNumVertices() const { return (int)(_vertices.size()); }
// apply the subdivision tables to compute the positions of the vertices up
// apply the subdivision tables to compute the positions of the vertices up
// to 'level'
void Subdivide(int level=-1);
private:
private:
friend class FarMeshFactory<T,U>;
FarMesh() : _subdivision(0), _dispatcher(0) { }
FarMesh() : _subdivision(0), _dispatcher(0), _vertexEdit(0) { }
// non-copyable, so these are not implemented:
FarMesh(FarMesh<T,U> const &);
@ -130,13 +138,19 @@ private:
// customizable compute dispatcher class
FarDispatcher<T,U> * _dispatcher;
// list of vertices (up to N levels of subdivision)
std::vector<U> _vertices;
// list of vertex indices for each face
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
PatchType _patchtype;
@ -146,8 +160,9 @@ private:
template <class T, class U>
FarMesh<T,U>::~FarMesh()
{
{
delete _subdivision;
delete _vertexEdit;
}
template <class T, class U> int
@ -155,13 +170,21 @@ FarMesh<T,U>::GetNumCoarseVertices() const {
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 {
if ( (level>=0) and (level<(int)_faceverts.size()) )
return _faceverts[level];
return _faceverts[0];
}
template <class T, class U> std::vector<int> const &
FarMesh<T,U>::GetPtexCoordinates(int level) const {
if ( (level>=0) and (level<(int)_faceverts.size()) )
return _ptexcoordinates[level];
return _ptexcoordinates[0];
}
template <class T, class U> void
FarMesh<T,U>::Subdivide(int maxlevel) {
@ -172,8 +195,11 @@ FarMesh<T,U>::Subdivide(int maxlevel) {
else
maxlevel = std::min(maxlevel, _subdivision->GetMaxLevel());
for (int i=1; i<maxlevel; ++i)
_subdivision->Refine(i);
for (int i=1; i<maxlevel; ++i) {
_subdivision->Apply(i);
if (_vertexEdit)
_vertexEdit->Apply(i);
}
}
} // end namespace OPENSUBDIV_VERSION

View File

@ -95,7 +95,7 @@ public:
// Create a table-based mesh representation
// XXXX : this creator will take the options for adaptive patch meshes
FarMesh<T,U> * Create( FarDispatcher<T,U> * dispatch=0 );
// Maximum level of subidivision supported by this factory
int GetMaxLevel() const { return _maxlevel; }
@ -103,12 +103,12 @@ public:
int GetNumFaceVerticesTotal(int level) const {
return sumList<HbrVertex<T> *>(_faceVertsList, level);
}
// Total number of edge vertices up to 'level'
int GetNumEdgeVerticesTotal(int level) const {
return sumList<HbrVertex<T> *>(_edgeVertsList, level);
}
// Total number of vertex vertices up to 'level'
int GetNumVertexVerticesTotal(int level) const {
return sumList<HbrVertex<T> *>(_vertVertsList, level);
@ -116,12 +116,12 @@ public:
// Valence summation up to 'level'
int GetNumAdjacentVertVerticesTotal(int level) const;
// Total number of faces across up to a level
int GetNumFacesTotal(int level) const {
return sumList<HbrFace<T> *>(_facesList, level);
}
// Return the corresponding index of the HbrVertex<T> in the new mesh
int GetVertexID( HbrVertex<T> * v );
@ -132,6 +132,7 @@ private:
friend class FarBilinearSubdivisionTables<T,U>;
friend class FarCatmarkSubdivisionTables<T,U>;
friend class FarLoopSubdivisionTables<T,U>;
friend class FarVertexEditTables<T,U>;
// Non-copyable, so these are not implemented:
FarMeshFactory( FarMeshFactory const & );
@ -144,23 +145,29 @@ private:
static bool isLoop(HbrMesh<T> * mesh);
void copyTopology( std::vector<int> & vec, int level );
void generatePtexCoordinates( std::vector<int> & vec, int level );
FarVertexEditTables<T,U> * createVertexEdit(FarMesh<T,U> * mesh);
static void refine( HbrMesh<T> * mesh, int maxlevel );
template <class Type> static int sumList( std::vector<std::vector<Type> > const & list, int level );
static bool compareNSubfaces(HbrVertexEdit<T> const *a, HbrVertexEdit<T> const *b);
HbrMesh<T> * _hbrMesh;
int _maxlevel,
_numVertices,
int _maxlevel,
_numVertices,
_numFaces;
// per-level counters and offsets for each type of vertex (face,edge,vert)
std::vector<int> _faceVertIdx,
_edgeVertIdx,
_edgeVertIdx,
_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;
// remapping table to translate vertex ID's between Hbr indices and the
@ -168,7 +175,7 @@ private:
std::vector<int> _remapTable;
// lists of vertices sorted by type and level
std::vector<std::vector< HbrVertex<T> *> > _faceVertsList,
std::vector<std::vector< HbrVertex<T> *> > _faceVertsList,
_edgeVertsList,
_vertVertsList;
@ -176,21 +183,21 @@ private:
std::vector<std::vector< HbrFace<T> *> > _facesList;
};
template <class T, class U>
template <class Type> int
template <class T, class U>
template <class Type> int
FarMeshFactory<T,U>::sumList( std::vector<std::vector<Type> > const & list, int level) {
level = std::min(level, (int)list.size());
level = std::min(level, (int)list.size());
int total = 0;
for (int i=0; i<=level; ++i)
total += (int)list[i].size();
return total;
}
template <class T, class U> int
template <class T, class U> int
FarMeshFactory<T,U>::GetNumAdjacentVertVerticesTotal(int level) const {
level = std::min(level, GetMaxLevel());
level = std::min(level, GetMaxLevel());
int total = 0;
for (int i=0; i<=level; ++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
// random order, so the builder runs 2 passes over the entire vertex list to
// 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 ) :
_hbrMesh(mesh),
_maxlevel(maxlevel),
_numVertices(-1),
_numFaces(-1),
_faceVertIdx(maxlevel+1,0),
_edgeVertIdx(maxlevel+1,0),
_faceVertIdx(maxlevel+1,0),
_edgeVertIdx(maxlevel+1,0),
_vertVertIdx(maxlevel+1,0),
_vertVertsListSize(maxlevel+1,0),
_faceVertsList(maxlevel+1),
_faceVertsList(maxlevel+1),
_edgeVertsList(maxlevel+1),
_vertVertsList(maxlevel+1),
_facesList(maxlevel+1)
@ -235,11 +242,11 @@ FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel ) :
int numVertices = mesh->GetNumVertices();
int numFaces = mesh->GetNumFaces();
std::vector<int> faceCounts(maxlevel+1,0),
edgeCounts(maxlevel+1,0),
std::vector<int> faceCounts(maxlevel+1,0),
edgeCounts(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).
int maxvertid=-1;
for (int i=0; i<numVertices; ++i) {
@ -248,48 +255,48 @@ FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel ) :
assert(v);
int depth = v->GetFace()->GetDepth();
if (depth>maxlevel)
continue;
if (depth==0 )
vertCounts[depth]++;
if (v->GetID()>maxvertid)
if (v->GetID()>maxvertid)
maxvertid = v->GetID();
if (not v->OnBoundary())
_vertVertsListSize[depth] += v->GetValence();
else if (v->GetValence()!=2)
_vertVertsListSize[depth] ++;
if (v->GetParentFace())
if (v->GetParentFace())
faceCounts[depth]++;
else if (v->GetParentEdge())
else if (v->GetParentEdge())
edgeCounts[depth]++;
else if (v->GetParentVertex())
else if (v->GetParentVertex())
vertCounts[depth]++;
}
// Per-level offset to the first vertex of each type in the global vertex map
_vertVertsList[0].reserve( vertCounts[0] );
for (int l=1; l<(maxlevel+1); ++l) {
_faceVertIdx[l]= _vertVertIdx[l-1]+vertCounts[l-1];
_edgeVertIdx[l]= _faceVertIdx[l]+faceCounts[l];
_vertVertIdx[l]= _edgeVertIdx[l]+edgeCounts[l];
_faceVertsList[l].reserve( faceCounts[l] );
_edgeVertsList[l].reserve( edgeCounts[l] );
_vertVertsList[l].reserve( vertCounts[l] );
}
}
// reset counters
faceCounts.assign(maxlevel+1,0);
edgeCounts.assign(maxlevel+1,0);
_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.
for (int i=0; i<numVertices; ++i) {
@ -297,13 +304,13 @@ FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel ) :
assert(v);
int depth = v->GetFace()->GetDepth();
if (depth>maxlevel)
continue;
assert( _remapTable[ v->GetID() ] = -1 );
if (depth==0) {
if (depth==0) {
_vertVertsList[ depth ].push_back( v );
_remapTable[ v->GetID() ] = v->GetID();
} else if (v->GetParentFace()) {
@ -318,25 +325,25 @@ FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel ) :
_vertVertsList[ depth ].push_back( v );
}
}
// Sort the the vertices that are the child of a vertex based on their weight
// mask. The masks combinations are ordered so as to minimize the compute
// kernel switching ( more information on this in the HbrVertex<T> comparison
// function 'FarSubdivisionTables<T>::compareVertices' ).
// function 'FarSubdivisionTables<T>::compareVertices' ).
for (size_t i=1; i<_vertVertsList.size(); ++i)
std::sort(_vertVertsList[i].begin(), _vertVertsList[i].end(),
FarSubdivisionTables<T,U>::compareVertices);
FarSubdivisionTables<T,U>::compareVertices);
// These vertices still need a remapped index
for (int l=1; l<(maxlevel+1); ++l)
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.
int fsize=0;
for (int i=0; i<numFaces; ++i) {
HbrFace<T> * f = mesh->GetFace(i);
HbrFace<T> * f = mesh->GetFace(i);
assert(f);
if (f->GetDepth()==0)
fsize += mesh->GetSubdivision()->GetFaceChildrenCount( f->GetNumVertices() );
@ -359,12 +366,12 @@ FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel ) :
GetNumVertexVerticesTotal(maxlevel);
}
template <class T, class U> bool
template <class T, class U> bool
FarMeshFactory<T,U>::isBilinear(HbrMesh<T> * mesh) {
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) {
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 ) {
assert( _hbrMesh );
int nv=-1;
if ( isCatmark(_hbrMesh) or isBilinear(_hbrMesh) )
nv=4;
else if ( isLoop(_hbrMesh) )
nv=3;
assert(nv>0);
vec.resize( nv * _facesList[level].size(), -1 );
for (int i=0; i<(int)_facesList[level].size(); ++i) {
HbrFace<T> * f = _facesList[level][i];
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()];
}
}
template <class T, class U> void
copyVertex( T & dest, U const & src ) {
}
@ -406,14 +412,193 @@ copyVertex( T & dest, T const & 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 ) {
assert( _hbrMesh );
if (_maxlevel<1)
return 0;
FarMesh<T,U> * result = new FarMesh<T,U>();
if (dispatch)
@ -422,19 +607,19 @@ FarMeshFactory<T,U>::Create( FarDispatcher<T,U> * dispatch ) {
result->_dispatcher = & FarDispatcher<T,U>::_DefaultDispatcher;
if ( isBilinear( _hbrMesh ) ) {
result->_subdivision =
result->_subdivision =
new FarBilinearSubdivisionTables<T,U>( *this, result, _maxlevel );
} else if ( isCatmark( _hbrMesh ) ) {
result->_subdivision =
result->_subdivision =
new FarCatmarkSubdivisionTables<T,U>( *this, result, _maxlevel );
} else if ( isLoop(_hbrMesh) ) {
result->_subdivision =
result->_subdivision =
new FarLoopSubdivisionTables<T,U>( *this, result, _maxlevel );
} else
assert(0);
result->_numCoarseVertices = (int)_vertVertsList[0].size();
// Copy the data of the coarse vertices into the vertex buffer.
// XXXX : we should figure out a test to make sure that the vertex
// 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)
// XXXX : only k_BilinearQuads support for now - adaptive bicubic patches to come
result->_patchtype = FarMesh<T,U>::k_BilinearQuads;
// XXXX : we should let the client decide which levels to copy,
// they may only want vertices...
// XXXX : we should let the client control what to copy, most of this may be irrelevant
result->_faceverts.resize(_maxlevel+1);
for (int l=1; l<=_maxlevel; ++l)
for (int l=1; l<=_maxlevel; ++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;
}

View File

@ -62,6 +62,7 @@
#include <vector>
#include "../version.h"
#include "../far/table.h"
template <class T> class HbrFace;
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>_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
template <class T, class U=T> class FarSubdivisionTables {
public:
@ -102,17 +103,17 @@ public:
// Memory required to store the indexing tables
virtual int GetMemoryUsed() const;
// 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
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
// represented by this set of FarCatmarkSubdivisionTables
int GetFirstVertexOffset( int level ) const;
// Number of vertices children of a face at a given level (always 0 for Loop)
int GetNumFaceVertices( int level ) const;
@ -121,70 +122,27 @@ public:
// Number of vertices children of a vertex at a given level
int GetNumVertexVertices( int level ) const;
// Total number of vertices at a given level
int GetNumVertices( int level ) const;
// Indexing tables accessors
// 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
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
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
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
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
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
// subdivision scheme.
virtual int GetNumTables() const { return 5; }
@ -196,7 +154,7 @@ protected:
// Returns an integer based on the order in which the kernels are applied
static int getMaskRanking( unsigned char mask0, unsigned char mask1 );
// Compares to vertices based on the ranking of their hbr masks combination
static bool compareVertices( HbrVertex<T> const * x, HbrVertex<T> const * y );
@ -207,10 +165,10 @@ protected:
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> kernelA2; // first / last vertex vertex batch (kernel A pass 2)
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.second = kernelA1.second = kernelA2.second = b;
}
@ -218,21 +176,21 @@ protected:
void AddVertex( int index, int rank ) {
// expand the range of kernel batches based on vertex index and rank
if (rank<7) {
if (index < kernelB.first)
if (index < kernelB.first)
kernelB.first=index;
if (index > kernelB.second)
if (index > kernelB.second)
kernelB.second=index;
}
if ((rank>2) and (rank<8)) {
if (index < kernelA2.first)
if (index < kernelA2.first)
kernelA2.first=index;
if (index > kernelA2.second)
if (index > kernelA2.second)
kernelA2.second=index;
}
if (rank>6) {
if (index < kernelA1.first)
if (index < kernelA1.first)
kernelA1.first=index;
if (index > kernelA1.second)
if (index > kernelA1.second)
kernelA1.second=index;
}
}
@ -244,23 +202,23 @@ protected:
protected:
// mesh that owns this subdivisionTable
FarMesh<T,U> * _mesh;
FarMesh<T,U> * _mesh;
Table<unsigned int> _E_IT; // vertices from edge refinement
Table<float> _E_W; // weigths
FarTable<int> _E_IT; // vertices from edge refinement
FarTable<float> _E_W; // weigths
Table<int> _V_ITa; // vertices from vertex refinement
Table<unsigned int> _V_IT; // indices of adjacent vertices
Table<float> _V_W; // weights
FarTable<int> _V_ITa; // vertices from vertex refinement
FarTable<unsigned int> _V_IT; // indices of adjacent vertices
FarTable<float> _V_W; // weights
std::vector<VertexKernelBatch> _batches; // batches of vertices for kernel execution
std::vector<int> _vertsOffsets; // offset to the first vertex of each level
private:
};
template <class T, class U>
FarSubdivisionTables<T,U>::FarSubdivisionTables( FarMesh<T,U> * mesh, int maxlevel ) :
template <class T, class U>
FarSubdivisionTables<T,U>::FarSubdivisionTables( FarMesh<T,U> * mesh, int maxlevel ) :
_mesh(mesh),
_E_IT(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
// somewhat arbitrary as it is possible to perform some permutations in the
// 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.
//
// 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 |
// +----+----+----+----+----+----+----+----+----+----+
// with :
// with :
// - A : compute kernel applying k_Crease / k_Corner rules
// - B : compute kernel applying k_Smooth / k_Dart rules
template <class T, class U> int
template <class T, class U> int
FarSubdivisionTables<T,U>::getMaskRanking( unsigned char mask0, unsigned char mask1 ) {
static short masks[4][4] = { { 0, 1, 6, 4 },
{ 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 ) {
// Masks of the parent vertex decide for the current vertex.
HbrVertex<T> * px=x->GetParentVertex(),
HbrVertex<T> * px=x->GetParentVertex(),
* py=y->GetParentVertex();
assert( (getMaskRanking(px->GetMask(false), px->GetMask(true) )!=0xFF) and
(getMaskRanking(py->GetMask(false), py->GetMask(true) )!=0xFF) );
return getMaskRanking(px->GetMask(false), px->GetMask(true) ) <
return getMaskRanking(px->GetMask(false), px->GetMask(true) ) <
getMaskRanking(py->GetMask(false), py->GetMask(true) );
}
template <class T, class U> int
FarSubdivisionTables<T,U>::GetFirstVertexOffset( int level ) const {
template <class T, class U> int
FarSubdivisionTables<T,U>::GetFirstVertexOffset( int level ) const {
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 {
assert(level>=0 and level<=(int)_batches.size());
return _batches[level-1].kernelF;
}
template <class T, class U> int
template <class T, class U> int
FarSubdivisionTables<T,U>::GetNumEdgeVertices( int level ) const {
assert(level>=0 and level<=(int)_batches.size());
return _batches[level-1].kernelE;
}
template <class T, class U> int
template <class T, class U> int
FarSubdivisionTables<T,U>::GetNumVertexVertices( int level ) const {
assert(level>=0 and level<=(int)_batches.size());
if (level==0)
return _mesh->GetNumCoarseVertices();
else
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));
}
template <class T, class U> int
template <class T, class U> int
FarSubdivisionTables<T,U>::GetNumVertices( int level ) const {
assert(level>=0 and level<=(int)_batches.size());
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
vertexEdit.h
vertex.h
)
)
install( FILES ${H_FILES}
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 SetMemStatsDecrement(void (*decrement)(unsigned long bytes)) { m_decrement = decrement; }
private:
size_t *m_memorystat;
const int m_blocksize;
@ -111,10 +111,10 @@ private:
HbrMemStatFunction m_increment;
HbrMemStatFunction m_decrement;
};
template <typename T>
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>
@ -125,15 +125,15 @@ HbrAllocator<T>::~HbrAllocator() {
template <typename T>
void HbrAllocator<T>::Clear() {
for (int i = 0; i < m_nblocks; ++i) {
// Run the destructors (placement)
T* blockptr = m_blocks[i];
T* startblock = blockptr;
for (int j = 0; j < m_blocksize; ++j) {
blockptr->~T();
blockptr = (T*) ((char*) blockptr + m_elemsize);
}
free(startblock);
if (m_decrement) m_decrement(m_blocksize * m_elemsize);
// Run the destructors (placement)
T* blockptr = m_blocks[i];
T* startblock = blockptr;
for (int j = 0; j < m_blocksize; ++j) {
blockptr->~T();
blockptr = (T*) ((char*) blockptr + m_elemsize);
}
free(startblock);
if (m_decrement) m_decrement(m_blocksize * m_elemsize);
*m_memorystat -= m_blocksize * m_elemsize;
}
free(m_blocks);
@ -145,40 +145,40 @@ void HbrAllocator<T>::Clear() {
}
template <typename T>
T*
T*
HbrAllocator<T>::Allocate() {
if (!m_freecount) {
// Allocate a new block
T* block = (T*) malloc(m_blocksize * m_elemsize);
T* blockptr = block;
// Run the constructors on each element using placement new
for (int i = 0; i < m_blocksize; ++i) {
new (blockptr) T();
blockptr = (T*) ((char*) blockptr + m_elemsize);
}
if (m_increment) m_increment(m_blocksize * m_elemsize);
// Allocate a new block
T* block = (T*) malloc(m_blocksize * m_elemsize);
T* blockptr = block;
// Run the constructors on each element using placement new
for (int i = 0; i < m_blocksize; ++i) {
new (blockptr) T();
blockptr = (T*) ((char*) blockptr + m_elemsize);
}
if (m_increment) m_increment(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
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;
// 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
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;
m_freelist = obj->GetNext();

View File

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

View File

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

View File

@ -68,7 +68,7 @@ template <class T>
std::ostream& operator<<(std::ostream& out, const HbrCornerEdit<T>& path) {
out << "vertex path = (" << path.faceid << ' ';
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;
}
@ -79,39 +79,39 @@ class HbrCornerEdit : public HbrHierarchicalEdit<T> {
public:
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)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), op(_op), sharpness(_sharpness) {
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), op(_op), sharpness(_sharpness) {
}
virtual ~HbrCornerEdit() {}
friend std::ostream& operator<< <T> (std::ostream& out, const HbrCornerEdit<T>& path);
virtual void ApplyEditToFace(HbrFace<T>* face) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
// Modify vertex sharpness. Note that we could actually do
// this in ApplyEditToVertex as well!
float sharp;
if (op == HbrHierarchicalEdit<T>::Set) {
sharp = sharpness;
} else if (op == HbrHierarchicalEdit<T>::Add) {
sharp = face->GetVertex(vertexid)->GetSharpness() + sharpness;
} else if (op == HbrHierarchicalEdit<T>::Subtract) {
sharp = face->GetVertex(vertexid)->GetSharpness() - sharpness;
}
if (sharp < HbrVertex<T>::k_Smooth) {
sharp = HbrVertex<T>::k_Smooth;
}
if (sharp > HbrVertex<T>::k_InfinitelySharp) {
sharp = HbrVertex<T>::k_InfinitelySharp;
}
face->GetVertex(vertexid)->SetSharpness(sharp);
}
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
// Modify vertex sharpness. Note that we could actually do
// this in ApplyEditToVertex as well!
float sharp;
if (op == HbrHierarchicalEdit<T>::Set) {
sharp = sharpness;
} else if (op == HbrHierarchicalEdit<T>::Add) {
sharp = face->GetVertex(vertexid)->GetSharpness() + sharpness;
} else if (op == HbrHierarchicalEdit<T>::Subtract) {
sharp = face->GetVertex(vertexid)->GetSharpness() - sharpness;
}
if (sharp < HbrVertex<T>::k_Smooth) {
sharp = HbrVertex<T>::k_Smooth;
}
if (sharp > HbrVertex<T>::k_InfinitelySharp) {
sharp = HbrVertex<T>::k_InfinitelySharp;
}
face->GetVertex(vertexid)->SetSharpness(sharp);
}
}
private:
// ID of the edge (you can think of this also as the id of the
// 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) {
out << "edge path = (" << path.faceid << ' ';
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;
}
@ -79,41 +79,41 @@ class HbrCreaseEdit : public HbrHierarchicalEdit<T> {
public:
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)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), edgeid(_edgeid), op(_op), sharpness(_sharpness) {
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), edgeid(_edgeid), op(_op), sharpness(_sharpness) {
}
virtual ~HbrCreaseEdit() {}
friend std::ostream& operator<< <T> (std::ostream& out, const HbrCreaseEdit<T>& path);
virtual void ApplyEditToFace(HbrFace<T>* face) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
// Modify edge sharpness
float sharp;
if (op == HbrHierarchicalEdit<T>::Set) {
sharp = sharpness;
} else if (op == HbrHierarchicalEdit<T>::Add) {
sharp = face->GetEdge(edgeid)->GetSharpness() + sharpness;
} else if (op == HbrHierarchicalEdit<T>::Subtract) {
sharp = face->GetEdge(edgeid)->GetSharpness() - sharpness;
}
if (sharp < HbrHalfedge<T>::k_Smooth)
sharp = HbrHalfedge<T>::k_Smooth;
if (sharp > HbrHalfedge<T>::k_InfinitelySharp)
sharp = HbrHalfedge<T>::k_InfinitelySharp;
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
// Modify edge sharpness
float sharp;
if (op == HbrHierarchicalEdit<T>::Set) {
sharp = sharpness;
} else if (op == HbrHierarchicalEdit<T>::Add) {
sharp = face->GetEdge(edgeid)->GetSharpness() + sharpness;
} else if (op == HbrHierarchicalEdit<T>::Subtract) {
sharp = face->GetEdge(edgeid)->GetSharpness() - sharpness;
}
if (sharp < HbrHalfedge<T>::k_Smooth)
sharp = HbrHalfedge<T>::k_Smooth;
if (sharp > HbrHalfedge<T>::k_InfinitelySharp)
sharp = HbrHalfedge<T>::k_InfinitelySharp;
// We have to make sure the neighbor of the edge exists at
// this point. Otherwise, if it comes into being late, it
// will clobber the overriden sharpness and we will lose
// the edit.
face->GetEdge(edgeid)->GuaranteeNeighbor();
face->GetEdge(edgeid)->SetSharpness(sharp);
}
}
}
private:
// ID of the edge (you can think of this also as the id of the
// origin vertex of the two-vertex length edge)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -74,29 +74,30 @@ template <class T>
class HbrLoopSubdivision : public HbrSubdivision<T>{
public:
HbrLoopSubdivision<T>()
: HbrSubdivision<T>() {}
: HbrSubdivision<T>() {}
virtual HbrSubdivision<T>* Clone() const {
return new HbrLoopSubdivision<T>();
}
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 GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
virtual bool HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face);
virtual bool HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
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, HbrHalfedge<T>* edge);
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 FaceIsExtraordinary(HbrMesh<T>* /* mesh */, HbrFace<T>* face) { return face->GetNumVertices() != 3; }
virtual int GetFaceChildrenCount(int nvertices) const { return 4; }
private:
// 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
if (index == 3) {
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);
GuaranteeNeighbor(mesh, edge);
childVertex = child->GetVertex((i + 2) % 3);
@ -129,11 +130,11 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
if (!fvIsSmooth) {
childVertex->NewFVarData(child);
}
HbrFVarData<T>& fv = childVertex->GetFVarData(child);
HbrFVarData<T>& fv = childVertex->GetFVarData(child);
int fvarindex = 0;
for (int fvaritem = 0; fvaritem < fvarcount; ++fvaritem) {
const int fvarwidth = mesh->GetFVarWidths()[fvaritem];
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
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;
}
fv.SetInitialized();
}
return;
}
return;
}
HbrHalfedge<T>* edge;
HbrVertex<T>* v = face->GetVertex(index);
// Otherwise we proceed with one vertex and two edge subdivision
// applications. First the vertex subdivision rule. Analyze
// 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;
childVertex = child->GetVertex(index);
fv0IsSmooth = v->IsFVarAllSmooth();
if (!fv0IsSmooth) {
childVertex->NewFVarData(child);
}
HbrFVarData<T>& fv0 = childVertex->GetFVarData(child);
edge = face->GetEdge(index);
GuaranteeNeighbor(mesh, edge);
assert(edge->GetOrgVertex() == v);
@ -208,7 +209,7 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
HbrFVarData<T>& fv1 = childVertex->GetFVarData(child);
edge = edge->GetPrev();
GuaranteeNeighbor(mesh, edge);
GuaranteeNeighbor(mesh, edge);
assert(edge == face->GetEdge((index + 2) % 3));
assert(edge->GetDestVertex() == v);
childVertex = child->GetVertex((index + 2) % 3);
@ -217,13 +218,13 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
childVertex->NewFVarData(child);
}
HbrFVarData<T>& fv2 = childVertex->GetFVarData(child);
const int fvarcount = mesh->GetFVarCount();
int fvarindex = 0;
for (int fvaritem = 0; fvaritem < fvarcount; ++fvaritem) {
bool infcorner = false;
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 (fvarmask >= HbrVertex<T>::k_Corner) {
infcorner = true;
@ -295,11 +296,11 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
if (bestface->GetVertex(j) == w) break;
}
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
// to checking that it's sharper than a dart)
else if (fvarmask != 0) {
else if (fvarmask != 0) {
// Use 0.75 of the current vert
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;
w = 0;
if (HbrHalfedge<T>* e = starte) {
assert(starte->GetOrgVertex() == v);
assert(starte->GetOrgVertex() == v);
do {
if (e->GetFVarSharpness(fvaritem) || !e->GetRightFace()) {
bestface = e->GetLeftFace();
@ -365,10 +366,10 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
}
assert(j != bestface->GetNumVertices());
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
}
// Smooth rule
else if (!fv0IsSmooth || !fv0.IsInitialized()) {
else if (!fv0IsSmooth || !fv0.IsInitialized()) {
int valence = v->GetValence();
float invvalence = 1.0f / valence;
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;
edge = start;
while (edge) {
HbrFace<T>* g = edge->GetLeftFace();
HbrFace<T>* g = edge->GetLeftFace();
// .. and look for the edge on that face whose origin is
// 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 = edge->GetPrev();
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) {
// Sharp edge rule
// Sharp edge rule
fv2.SetWithWeight(face->GetFVarData((index + 2) % 3), fvarindex, fvarwidth, 0.5f);
fv2.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f);
} 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.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.375f);
// 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();
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);
break;
}
}
}
}
fvarindex += fvarwidth;
@ -463,15 +464,15 @@ HbrLoopSubdivision<T>::transferEditsToChild(HbrFace<T>* face, HbrFace<T>* child,
// Hand down pointers to hierarchical edits
if (HbrHierarchicalEdit<T>** edits = face->GetHierarchicalEdits()) {
while (HbrHierarchicalEdit<T>* edit = *edits) {
if (!edit->IsRelevantToFace(face)) break;
if (edit->GetNSubfaces() > face->GetDepth() &&
(edit->GetSubface(face->GetDepth()) == index)) {
child->SetHierarchicalEdits(edits);
break;
}
edits++;
}
while (HbrHierarchicalEdit<T>* edit = *edits) {
if (!edit->IsRelevantToFace(face)) break;
if (edit->GetNSubfaces() > face->GetDepth() &&
(edit->GetSubface(face->GetDepth()) == index)) {
child->SetHierarchicalEdits(edits);
break;
}
edits++;
}
}
}
@ -481,56 +482,56 @@ HbrLoopSubdivision<T>::Refine(HbrMesh<T>* mesh, HbrFace<T>* face) {
#ifdef HBR_DEBUG
std::cerr << "\n\nRefining face " << *face << "\n";
#endif
#endif
assert(face->GetNumVertices() == 3); // or triangulate it?
HbrHalfedge<T>* edge = face->GetFirstEdge();
HbrHalfedge<T>* prevedge = edge->GetPrev();
for (int i = 0; i < 3; ++i) {
HbrVertex<T>* vertex = edge->GetOrgVertex();
if (!face->GetChild(i)) {
HbrVertex<T>* vertex = edge->GetOrgVertex();
if (!face->GetChild(i)) {
#ifdef HBR_DEBUG
std::cerr << "Kid " << i << "\n";
std::cerr << "Kid " << i << "\n";
#endif
HbrFace<T>* child;
HbrVertex<T>* vertices[3];
HbrFace<T>* child;
HbrVertex<T>* vertices[3];
vertices[i] = vertex->Subdivide();
vertices[(i + 1) % 3] = edge->Subdivide();
vertices[(i + 2) % 3] = prevedge->Subdivide();
child = mesh->NewFace(3, vertices, face, i);
vertices[i] = vertex->Subdivide();
vertices[(i + 1) % 3] = edge->Subdivide();
vertices[(i + 2) % 3] = prevedge->Subdivide();
child = mesh->NewFace(3, vertices, face, i);
#ifdef HBR_DEBUG
std::cerr << "Creating face " << *child << " during refine\n";
#endif
std::cerr << "Creating face " << *child << " during refine\n";
#endif
// Hand down edge sharpness
float sharpness;
HbrHalfedge<T>* childedge;
// Hand down edge sharpness
float sharpness;
HbrHalfedge<T>* childedge;
childedge = child->GetEdge(i);
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight(
edge, edge->GetDestVertex(), childedge);
}
childedge->CopyFVarInfiniteSharpness(edge);
childedge = child->GetEdge((i+2)%3);
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight(
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight(
prevedge, prevedge->GetOrgVertex(), childedge);
}
}
childedge->CopyFVarInfiniteSharpness(prevedge);
if (mesh->GetTotalFVarWidth()) {
transferFVarToChild(mesh, face, child, i);
}
if (mesh->GetTotalFVarWidth()) {
transferFVarToChild(mesh, face, child, i);
}
transferEditsToChild(face, child, i);
transferEditsToChild(face, child, i);
}
prevedge = edge;
edge = edge->GetNext();
}
prevedge = edge;
edge = edge->GetNext();
}
refineFaceAtMiddle(mesh, face);
@ -545,55 +546,55 @@ HbrLoopSubdivision<T>::RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, Hb
#endif
HbrHalfedge<T>* edge = face->GetFirstEdge();
HbrHalfedge<T>* prevedge = edge->GetPrev();
for (int i = 0; i < 3; ++i) {
if (edge->GetOrgVertex() == vertex) {
if (!face->GetChild(i)) {
if (edge->GetOrgVertex() == vertex) {
if (!face->GetChild(i)) {
#ifdef HBR_DEBUG
std::cerr << "Kid " << i << "\n";
std::cerr << "Kid " << i << "\n";
#endif
HbrFace<T>* child;
HbrVertex<T>* vertices[3];
HbrFace<T>* child;
HbrVertex<T>* vertices[3];
vertices[i] = vertex->Subdivide();
vertices[(i + 1) % 3] = edge->Subdivide();
vertices[(i + 2) % 3] = prevedge->Subdivide();
child = mesh->NewFace(3, vertices, face, i);
vertices[i] = vertex->Subdivide();
vertices[(i + 1) % 3] = edge->Subdivide();
vertices[(i + 2) % 3] = prevedge->Subdivide();
child = mesh->NewFace(3, vertices, face, i);
#ifdef HBR_DEBUG
std::cerr << "Creating face " << *child << " during refine\n";
#endif
std::cerr << "Creating face " << *child << " during refine\n";
#endif
// Hand down edge sharpness
float sharpness;
HbrHalfedge<T>* childedge;
// Hand down edge sharpness
float sharpness;
HbrHalfedge<T>* childedge;
childedge = child->GetEdge(i);
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight(
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight(
edge, edge->GetDestVertex(), childedge);
}
}
childedge->CopyFVarInfiniteSharpness(edge);
childedge = child->GetEdge((i+2)%3);
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight(
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
HbrSubdivision<T>::SubdivideCreaseWeight(
prevedge, prevedge->GetOrgVertex(), childedge);
}
}
childedge->CopyFVarInfiniteSharpness(prevedge);
if (mesh->GetTotalFVarWidth()) {
transferFVarToChild(mesh, face, child, i);
}
if (mesh->GetTotalFVarWidth()) {
transferFVarToChild(mesh, face, child, i);
}
transferEditsToChild(face, child, i);
return child;
} else {
return face->GetChild(i);
}
}
prevedge = edge;
edge = edge->GetNext();
transferEditsToChild(face, child, i);
return child;
} else {
return face->GetChild(i);
}
}
prevedge = edge;
edge = edge->GetNext();
}
return 0;
}
@ -602,7 +603,7 @@ template <class T>
void
HbrLoopSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
if (edge->GetOpposite()) {
return;
return;
}
#ifdef HBR_DEBUG
@ -611,7 +612,7 @@ HbrLoopSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge)
/*
Imagine the following:
X
/ \
/ \
@ -622,7 +623,7 @@ HbrLoopSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge)
/ \ \
X------X--------X
1
If the parent of _both_ incident vertices are themselves edges,
(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
@ -633,41 +634,41 @@ HbrLoopSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge)
HbrHalfedge<T>* parentEdge2 = edge->GetDestVertex()->GetParentEdge();
if (parentEdge1 && parentEdge2) {
#ifdef HBR_DEBUG
std::cerr << "two parent edge situation\n";
std::cerr << "two parent edge situation\n";
#endif
HbrFace<T>* parentFace = parentEdge1->GetFace();
assert(parentFace == parentEdge2->GetFace());
if(parentEdge1->GetOrgVertex() == parentEdge2->GetDestVertex()) {
refineFaceAtMiddle(mesh, parentFace);
} else {
RefineFaceAtVertex(mesh, parentFace, parentEdge1->GetOrgVertex());
}
assert(edge->GetOpposite());
return;
HbrFace<T>* parentFace = parentEdge1->GetFace();
assert(parentFace == parentEdge2->GetFace());
if(parentEdge1->GetOrgVertex() == parentEdge2->GetDestVertex()) {
refineFaceAtMiddle(mesh, parentFace);
} else {
RefineFaceAtVertex(mesh, parentFace, parentEdge1->GetOrgVertex());
}
assert(edge->GetOpposite());
return;
}
// Otherwise we're in the situation of edge 1 or edge 2 in the
// diagram above.
if (parentEdge1) {
#ifdef HBR_DEBUG
std::cerr << "parent edge 1 " << *parentEdge1 << "\n";
std::cerr << "parent edge 1 " << *parentEdge1 << "\n";
#endif
HbrVertex<T>* parentVertex2 = edge->GetDestVertex()->GetParentVertex();
assert(parentVertex2);
RefineFaceAtVertex(mesh, parentEdge1->GetLeftFace(), parentVertex2);
if (parentEdge1->GetRightFace()) {
RefineFaceAtVertex(mesh, parentEdge1->GetRightFace(), parentVertex2);
}
HbrVertex<T>* parentVertex2 = edge->GetDestVertex()->GetParentVertex();
assert(parentVertex2);
RefineFaceAtVertex(mesh, parentEdge1->GetLeftFace(), parentVertex2);
if (parentEdge1->GetRightFace()) {
RefineFaceAtVertex(mesh, parentEdge1->GetRightFace(), parentVertex2);
}
} else if (parentEdge2) {
#ifdef HBR_DEBUG
std::cerr << "parent edge 2 " << *parentEdge2 << "\n";
std::cerr << "parent edge 2 " << *parentEdge2 << "\n";
#endif
HbrVertex<T>* parentVertex1 = edge->GetOrgVertex()->GetParentVertex();
assert(parentVertex1);
RefineFaceAtVertex(mesh, parentEdge2->GetLeftFace(), parentVertex1);
if (parentEdge2->GetRightFace()) {
RefineFaceAtVertex(mesh, parentEdge2->GetRightFace(), parentVertex1);
}
HbrVertex<T>* parentVertex1 = edge->GetOrgVertex()->GetParentVertex();
assert(parentVertex1);
RefineFaceAtVertex(mesh, parentEdge2->GetLeftFace(), parentVertex1);
if (parentEdge2->GetRightFace()) {
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)
// have refined their "middle" face (which doesn't live at either
// vertex).
HbrHalfedge<T>* parentEdge = vertex->GetParentEdge();
if (parentEdge) {
#ifdef HBR_DEBUG
std::cerr << "parent edge situation " << *parentEdge << "\n";
std::cerr << "parent edge situation " << *parentEdge << "\n";
#endif
HbrVertex<T>* dest = parentEdge->GetDestVertex();
HbrVertex<T>* org = parentEdge->GetOrgVertex();
GuaranteeNeighbor(mesh, parentEdge);
HbrFace<T>* parentFace = parentEdge->GetLeftFace();
RefineFaceAtVertex(mesh, parentFace, dest);
RefineFaceAtVertex(mesh, parentFace, org);
refineFaceAtMiddle(mesh, parentFace);
parentFace = parentEdge->GetRightFace();
// The right face may not necessarily exist even after
// GuaranteeNeighbor
if (parentFace) {
RefineFaceAtVertex(mesh, parentFace, dest);
RefineFaceAtVertex(mesh, parentFace, org);
refineFaceAtMiddle(mesh, parentFace);
}
return;
}
HbrVertex<T>* dest = parentEdge->GetDestVertex();
HbrVertex<T>* org = parentEdge->GetOrgVertex();
GuaranteeNeighbor(mesh, parentEdge);
HbrFace<T>* parentFace = parentEdge->GetLeftFace();
RefineFaceAtVertex(mesh, parentFace, dest);
RefineFaceAtVertex(mesh, parentFace, org);
refineFaceAtMiddle(mesh, parentFace);
parentFace = parentEdge->GetRightFace();
// The right face may not necessarily exist even after
// GuaranteeNeighbor
if (parentFace) {
RefineFaceAtVertex(mesh, parentFace, dest);
RefineFaceAtVertex(mesh, parentFace, org);
refineFaceAtMiddle(mesh, parentFace);
}
return;
}
// The second case: the vertex is a child of a vertex. In this case
// we have to recursively guarantee that the parent's adjacent
// faces also exist.
HbrVertex<T>* parentVertex = vertex->GetParentVertex();
if (parentVertex) {
#ifdef HBR_DEBUG
std::cerr << "parent vertex situation " << *parentVertex << "\n";
std::cerr << "parent vertex situation " << *parentVertex << "\n";
#endif
parentVertex->GuaranteeNeighbors();
parentVertex->GuaranteeNeighbors();
// And then we refine all the face neighbors of the parent
// vertex
HbrHalfedge<T>* start = parentVertex->GetIncidentEdge(), *edge;
edge = start;
while (edge) {
HbrFace<T>* f = edge->GetLeftFace();
RefineFaceAtVertex(mesh, f, parentVertex);
edge = parentVertex->GetNextEdge(edge);
if (edge == start) break;
}
// And then we refine all the face neighbors of the parent
// vertex
HbrHalfedge<T>* start = parentVertex->GetIncidentEdge(), *edge;
edge = start;
while (edge) {
HbrFace<T>* f = edge->GetLeftFace();
RefineFaceAtVertex(mesh, f, parentVertex);
edge = parentVertex->GetNextEdge(edge);
if (edge == start) break;
}
}
}
@ -740,9 +741,9 @@ HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face) {
if (face->IsHole()) return false;
// A limit face exists if all the bounding edges have limit curves
for (int i = 0; i < face->GetNumVertices(); ++i) {
if (!HasLimit(mesh, face->GetEdge(i))) {
return false;
}
if (!HasLimit(mesh, face->GetEdge(i))) {
return false;
}
}
return true;
}
@ -750,14 +751,14 @@ HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face) {
template <class T>
bool
HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
// A sharp edge has a limit curve if both endpoints have limits.
// A smooth edge has a limit if both endpoints have limits and
// the edge isn't on the boundary.
// A sharp edge has a limit curve if both endpoints have limits.
// A smooth edge has a limit if both endpoints have limits and
// the edge isn't on the boundary.
if (edge->GetSharpness() >= HbrHalfedge<T>::k_InfinitelySharp) return true;
if (!HasLimit(mesh, edge->GetOrgVertex()) || !HasLimit(mesh, edge->GetDestVertex())) return false;
return !edge->IsBoundary();
}
@ -766,21 +767,21 @@ bool
HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
vertex->GuaranteeNeighbors();
switch (vertex->GetMask(false)) {
case HbrVertex<T>::k_Smooth:
case HbrVertex<T>::k_Dart:
return !vertex->OnBoundary();
break;
case HbrVertex<T>::k_Crease:
case HbrVertex<T>::k_Corner:
default:
if (vertex->IsVolatile()) {
// Search for any incident semisharp boundary edge
case HbrVertex<T>::k_Smooth:
case HbrVertex<T>::k_Dart:
return !vertex->OnBoundary();
break;
case HbrVertex<T>::k_Crease:
case HbrVertex<T>::k_Corner:
default:
if (vertex->IsVolatile()) {
// Search for any incident semisharp boundary edge
HbrHalfedge<T>* start = vertex->GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
if (edge->IsBoundary() && edge->GetSharpness() < HbrHalfedge<T>::k_InfinitelySharp) {
return false;
}
if (edge->IsBoundary() && edge->GetSharpness() < HbrHalfedge<T>::k_InfinitelySharp) {
return false;
}
next = vertex->GetNextEdge(edge);
if (next == start) {
break;
@ -793,9 +794,9 @@ HbrLoopSubdivision<T>::HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
} else {
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
// have to make sure the edit has been applied
if (mesh->HasVertexEdits()) {
edge->GetOrgVertex()->GuaranteeNeighbors();
edge->GetDestVertex()->GuaranteeNeighbors();
edge->GetOrgVertex()->GuaranteeNeighbors();
edge->GetDestVertex()->GuaranteeNeighbors();
}
if (!edge->IsBoundary() && esharp <= 1.0f) {
// Of the two half-edges, pick one of them consistently such
// that the org and dest vertices are also consistent through
// multi-threading. It doesn't matter as far as the
// theoretical calculation is concerned, but it is desirable
// to be consistent about it in the face of the limitations of
// floating point commutativity. So we always pick the
// half-edge such that its incident face is the smallest of
// the two faces, as far as the face paths are concerned.
if (edge->GetOpposite() && edge->GetOpposite()->GetFace()->GetPath() < edge->GetFace()->GetPath()) {
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).
// Of the two half-edges, pick one of them consistently such
// that the org and dest vertices are also consistent through
// multi-threading. It doesn't matter as far as the
// theoretical calculation is concerned, but it is desirable
// to be consistent about it in the face of the limitations of
// floating point commutativity. So we always pick the
// half-edge such that its incident face is the smallest of
// the two faces, as far as the face paths are concerned.
if (edge->GetOpposite() && edge->GetOpposite()->GetFace()->GetPath() < edge->GetFace()->GetPath()) {
edge = edge->GetOpposite();
}
// Lerp end point weight between non sharp contribution of
// 3/8 and the sharp contribution of 0.5.
float endPtWeight = 0.375f + esharp * (0.5f - 0.375f);
data.AddWithWeight(edge->GetOrgVertex()->GetData(), endPtWeight);
data.AddWithWeight(edge->GetDestVertex()->GetData(), endPtWeight);
// 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 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);
// Lerp end point weight between non sharp contribution of
// 3/8 and the sharp contribution of 0.5.
float endPtWeight = 0.375f + esharp * (0.5f - 0.375f);
data.AddWithWeight(edge->GetOrgVertex()->GetData(), endPtWeight);
data.AddWithWeight(edge->GetDestVertex()->GetData(), endPtWeight);
// 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 {
// Fully sharp edge, just average the two end points
data.AddWithWeight(edge->GetOrgVertex()->GetData(), 0.5f);
data.AddWithWeight(edge->GetDestVertex()->GetData(), 0.5f);
// Fully sharp edge, just average the two end points
data.AddWithWeight(edge->GetOrgVertex()->GetData(), 0.5f);
data.AddWithWeight(edge->GetDestVertex()->GetData(), 0.5f);
}
// 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
if (edge->IsBoundary()) {
v->SetExtraordinary();
v->SetExtraordinary();
}
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
// we compute the valence
vertex->GuaranteeNeighbors();
float valence = static_cast<float>(vertex->GetValence());
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
// each weighing
if (masks[0] != masks[1]) {
weights[1] = vertex->GetFractionalMask();
weights[0] = 1.0f - weights[1];
passes = 2;
weights[1] = vertex->GetFractionalMask();
weights[0] = 1.0f - weights[1];
passes = 2;
} else {
weights[0] = 1.0f;
weights[1] = 0.0f;
passes = 1;
weights[0] = 1.0f;
weights[1] = 0.0f;
passes = 1;
}
for (int i = 0; i < passes; ++i) {
switch (masks[i]) {
case HbrVertex<T>::k_Smooth:
case HbrVertex<T>::k_Dart: {
float beta = 0.25f * cosf((float)M_PI * 2.0f * invvalence) + 0.375f;
beta = beta * beta;
beta = (0.625f - beta) * invvalence;
switch (masks[i]) {
case HbrVertex<T>::k_Smooth:
case HbrVertex<T>::k_Dart: {
float beta = 0.25f * cosf((float)M_PI * 2.0f * invvalence) + 0.375f;
beta = beta * beta;
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(
mesh, vertex, weights[i] * beta, &data);
break;
}
case HbrVertex<T>::k_Crease: {
// Compute 3/4 of old vertex value
data.AddWithWeight(vertex->GetData(), weights[i] * 0.75f);
}
case HbrVertex<T>::k_Crease: {
// Compute 3/4 of old vertex value
data.AddWithWeight(vertex->GetData(), weights[i] * 0.75f);
// Add 0.125f of the (hopefully only two!) neighbouring
// sharp edges
// Add 0.125f of the (hopefully only two!) neighbouring
// sharp edges
HbrSubdivision<T>::AddCreaseEdgesWithWeight(
mesh, vertex, i == 1, weights[i] * 0.125f, &data);
break;
}
case HbrVertex<T>::k_Corner:
default: {
// Just copy the old value
data.AddWithWeight(vertex->GetData(), weights[i]);
break;
}
}
break;
}
case HbrVertex<T>::k_Corner:
default: {
// Just copy the old value
data.AddWithWeight(vertex->GetData(), weights[i]);
break;
}
}
}
// Varying data is always just propogated down
// Varying data is always just propagated down
data.AddVaryingWithWeight(vertex->GetData(), 1.0f);
#ifdef HBR_DEBUG
std::cerr << "Subdividing at " << *vertex << "\n";
std::cerr << "Subdividing at " << *vertex << "\n";
std::cerr << " created " << *v << "\n";
#endif
// Inherit extraordinary flag and sharpness
if (vertex->IsExtraordinary()) v->SetExtraordinary();
float sharp = vertex->GetSharpness();
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) {
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 {
v->SetSharpness(HbrVertex<T>::k_Smooth);
v->SetSharpness(HbrVertex<T>::k_Smooth);
}
return v;
}
@ -974,28 +975,28 @@ HbrLoopSubdivision<T>::refineFaceAtMiddle(HbrMesh<T>* mesh, HbrFace<T>* face) {
#ifdef HBR_DEBUG
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
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 <cstring>
#include <deque>
#include <list>
#include <vector>
#include <set>
#include <iostream>
@ -94,14 +93,14 @@ public:
#endif
);
~HbrMesh();
// Create vertex with the indicated ID and data
HbrVertex<T>* NewVertex(int id, const T &data);
// Create vertex with the indicated data. The ID will be assigned
// by the mesh.
HbrVertex<T>* NewVertex(const T &data);
// Create vertex without an ID - one will be assigned by the mesh,
// and the data implicitly created will share the same id
HbrVertex<T>* NewVertex();
@ -120,36 +119,36 @@ public:
// Finishes initialization of the mesh
void Finish();
// Remove the indicated face from the mesh
void DeleteFace(HbrFace<T>* face);
// Remove the indicated vertex from the mesh
void DeleteVertex(HbrVertex<T>* vertex);
// Returns number of vertices in the mesh
int GetNumVertices() const;
// Returns number of disconnected vertices in the mesh
int GetNumDisconnectedVertices() const;
// Returns number of faces in the mesh
// Returns number of faces in the mesh
int GetNumFaces() const;
// Returns number of coarse faces in the mesh
// Returns number of coarse faces in the mesh
int GetNumCoarseFaces() const;
// Ask for face with the indicated ID
HbrFace<T>* GetFace(int id) const;
// 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
void ApplyOperatorAllVertices(HbrVertexOperator<T> &op) const;
// 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
HbrSubdivision<T>* GetSubdivision() const { return subdivision; }
@ -159,7 +158,7 @@ public:
// Return a table of the start index of each facevarying variable
const int *GetFVarIndices() const { return fvarindices; }
// Return a table of the size of each facevarying variable
const int *GetFVarWidths() const { return fvarwidths; }
@ -177,9 +176,9 @@ public:
// Interpolate boundary management
enum InterpolateBoundaryMethod {
k_InterpolateBoundaryNone,
k_InterpolateBoundaryEdgeOnly,
k_InterpolateBoundaryEdgeAndCorner,
k_InterpolateBoundaryNone,
k_InterpolateBoundaryEdgeOnly,
k_InterpolateBoundaryEdgeAndCorner,
k_InterpolateBoundaryAlwaysSharp
};
@ -190,15 +189,15 @@ public:
bool GetFVarPropagateCorners() const { return fvarpropagatecorners; }
void SetFVarPropagateCorners(bool p) { fvarpropagatecorners = p; }
// Register routines for keeping track of memory usage
void RegisterMemoryRoutines(void (*increment)(unsigned long bytes), void (*decrement)(unsigned long bytes)) {
m_faceAllocator.SetMemStatsIncrement(increment);
m_faceAllocator.SetMemStatsDecrement(decrement);
m_vertexAllocator.SetMemStatsIncrement(increment);
m_vertexAllocator.SetMemStatsDecrement(decrement);
s_memStatsIncrement = increment;
s_memStatsDecrement = decrement;
m_faceAllocator.SetMemStatsIncrement(increment);
m_faceAllocator.SetMemStatsDecrement(decrement);
m_vertexAllocator.SetMemStatsIncrement(increment);
m_vertexAllocator.SetMemStatsDecrement(decrement);
s_memStatsIncrement = increment;
s_memStatsDecrement = decrement;
}
// Add a vertex to consider for garbage collection. All
@ -219,37 +218,39 @@ public:
// Add a new hierarchical edit to the mesh
void AddHierarchicalEdit(HbrHierarchicalEdit<T>* edit);
// Return a pointer to the beginning of the list of hierarchical edits
HbrHierarchicalEdit<T>** GetHierarchicalEdits() const { return hierarchicalEditArray; }
// Return the hierarchical edits associated with the mesh
const std::vector<HbrHierarchicalEdit<T>*> &GetHierarchicalEdits() const {
return hierarchicalEdits;
}
// Whether the mesh has certain types of edits
bool HasVertexEdits() const { return hasVertexEdits; }
bool HasCreaseEdits() const { return hasCreaseEdits; }
void Unrefine(int numCoarseVerts, int numCoarseFaces) {
static int oldMaxFaceID = 0;
if(oldMaxFaceID == 0) {
oldMaxFaceID = numCoarseFaces;
}
for (int i = numCoarseFaces; i < maxFaceID; ++i) {
if (faces[i]) {
HbrFace<T>* f = faces[i];
if(f && not f->IsCoarse())
DeleteFace(f);
}
}
//oldMaxFaceID = maxFaceID;
maxFaceID = numCoarseFaces;
static int oldMaxFaceID = 0;
if(oldMaxFaceID == 0) {
oldMaxFaceID = numCoarseFaces;
}
for (int i = numCoarseFaces; i < maxFaceID; ++i) {
if (faces[i]) {
HbrFace<T>* f = faces[i];
if(f && not f->IsCoarse())
DeleteFace(f);
}
}
//oldMaxFaceID = maxFaceID;
maxFaceID = numCoarseFaces;
int vert = numCoarseVerts % vsetsize;
for( int set=(numCoarseVerts/vsetsize); set<nvsets; set++ ) {
for( ; vert<vsetsize; vert++ ) {
HbrVertex<T>* v = vertices[set][vert];
if(v && not v->IsReferenced())
DeleteVertex(v);
}
for( int set=(numCoarseVerts/vsetsize); set<nvsets; set++ ) {
for( ; vert<vsetsize; vert++ ) {
HbrVertex<T>* v = vertices[set][vert];
if(v && not v->IsReferenced())
DeleteVertex(v);
}
vert = 0;
}
}
}
// Whether the mesh is in "transient" mode, i.e. all
@ -257,9 +258,9 @@ public:
void SetTransientMode(bool mode) {
m_transientMode = mode;
}
void FreeTransientData();
private:
// The mutex type depends on where hbr is being used.
#if PRMAN
@ -277,8 +278,8 @@ private:
public:
ScopedLock(Mutex *mutex) : _mutex(mutex) {
mutex->Lock();
}
}
~ScopedLock() {
Release();
}
@ -292,12 +293,12 @@ private:
Mutex *_mutex;
};
#endif
// Mutex used to lock access to the "vertices" data member.
mutable Mutex m_verticesMutex;
private:
// Subdivision method used in this mesh
HbrSubdivision<T>* subdivision;
@ -316,7 +317,7 @@ private:
#ifdef HBRSTITCH
const int stitchCount;
#endif
// Vertices which comprise this mesh
HbrVertex<T>*** vertices;
int nvsets;
@ -344,28 +345,22 @@ private:
// Whether facevarying corners propagate their sharpness
bool fvarpropagatecorners;
// Memory statistics tracking routines
HbrMemStatFunction s_memStatsIncrement;
HbrMemStatFunction s_memStatsDecrement;
// Vertices which may be garbage collected
std::deque<HbrVertex<T>*> gcVertices;
std::vector<HbrVertex<T>*> gcVertices;
// List of vertex IDs which may be recycled
std::set<int> recycleIDs;
// Sorted hierarchical edits. This set is valid only until
// Finish() is called, at which point the mesh should switch over
// to using hierarchicalEditArray
std::multiset<HbrHierarchicalEdit<T>*, HbrHierarchicalEditComparator<T> > hierarchicalEditSet;
// 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;
// Hierarchical edits. This vector is left unsorted until Finish()
// is called, at which point it is sorted. After that point,
// HbrFaces have pointers directly into this array so manipulation
// of it should be avoided.
std::vector<HbrHierarchicalEdit<T>*> hierarchicalEdits;
// Size of faces (including 4 facevarying bits and stitch edges)
const size_t m_faceSize;
@ -373,14 +368,14 @@ private:
// Size of vertices (includes storage for one piece of facevarying data)
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
size_t m_memory;
// Number of coarse faces. Initialized at Finish()
int m_numCoarseFaces;
// Flags which indicate whether the mesh has certain types of
// edits
unsigned hasVertexEdits:1;
@ -392,11 +387,11 @@ private:
bool m_transientMode;
// Vertices which are transient
std::deque<HbrVertex<T>*> m_transientVertices;
std::vector<HbrVertex<T>*> m_transientVertices;
// Faces which are transient
std::deque<HbrFace<T>*> m_transientFaces;
std::vector<HbrFace<T>*> m_transientFaces;
};
} // end namespace OPENSUBDIV_VERSION
@ -429,8 +424,6 @@ HbrMesh<T>::HbrMesh(HbrSubdivision<T>* s, int _fvarcount, const int *_fvarindice
fvarinterpboundarymethod(k_InterpolateBoundaryNone),
fvarpropagatecorners(false),
s_memStatsIncrement(0), s_memStatsDecrement(0),
nHierarchicalEdits(0),
hierarchicalEditArray(0),
m_faceSize(sizeof(HbrFace<T>) + 4 *
((fvarcount + 15) / 16 * sizeof(unsigned int)
#ifdef HBRSTITCH
@ -438,11 +431,11 @@ HbrMesh<T>::HbrMesh(HbrSubdivision<T>* s, int _fvarcount, const int *_fvarindice
+ sizeof(void*) // for stitch data
#endif
)),
m_faceAllocator(&m_memory, 64, 0, 0, m_faceSize),
m_faceAllocator(&m_memory, 512, 0, 0, m_faceSize),
m_vertexSize(sizeof(HbrVertex<T>) +
sizeof(HbrHalfedge<T>*) + // for incidentEdges[1]
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_numCoarseFaces(-1),
hasVertexEdits(0),
@ -456,17 +449,17 @@ HbrMesh<T>::~HbrMesh() {
int i;
if (faces) {
for (i = 0; i < nfaces; ++i) {
if (faces[i]) {
faces[i]->Destroy();
m_faceAllocator.Deallocate(faces[i]);
}
}
if (s_memStatsDecrement) {
s_memStatsDecrement(nfaces * sizeof(HbrFace<T>*));
}
for (i = 0; i < nfaces; ++i) {
if (faces[i]) {
faces[i]->Destroy();
m_faceAllocator.Deallocate(faces[i]);
}
}
if (s_memStatsDecrement) {
s_memStatsDecrement(nfaces * sizeof(HbrFace<T>*));
}
m_memory -= nfaces * sizeof(HbrFace<T>*);
delete[] faces;
delete[] faces;
}
if (nvsets) {
@ -483,14 +476,12 @@ HbrMesh<T>::~HbrMesh() {
s_memStatsDecrement(vsetsize * sizeof(HbrVertex<T>*));
}
m_memory -= vsetsize * sizeof(HbrVertex<T>*);
}
}
delete[] vertices;
}
if (hierarchicalEditArray) {
for (i = 0; i < nHierarchicalEdits; ++i) {
delete hierarchicalEditArray[i];
}
delete[] hierarchicalEditArray;
for (typename std::vector<HbrHierarchicalEdit<T>* >::iterator hi =
hierarchicalEdits.begin(); hi != hierarchicalEdits.end(); ++hi) {
delete *hi;
}
}
@ -501,11 +492,11 @@ HbrMesh<T>::NewVertex(int id, const T &data) {
int arrayindex = id / vsetsize;
int vertindex = id % vsetsize;
#if PRMAN or MENV
#if PRMAN or MENV
ScopedLock lock(&m_verticesMutex);
#else
IlmThread::Lock lock(m_verticesMutex);
#endif
#endif
HbrVertex<T>** vset = 0;
if (arrayindex >= nvsets) {
HbrVertex<T>*** nvertices = new HbrVertex<T>**[arrayindex + 1];
@ -526,22 +517,22 @@ HbrMesh<T>::NewVertex(int id, const T &data) {
vertices = nvertices;
}
vset = vertices[arrayindex];
#if PRMAN or MENV
#if PRMAN or MENV
lock.Release();
#else
lock.release();
#endif
#endif
v = vset[vertindex];
if (v) {
v->Destroy();
v->Destroy();
} else {
v = m_vertexAllocator.Allocate();
v = m_vertexAllocator.Allocate();
}
v->Initialize(id, data, GetTotalFVarWidth());
vset[vertindex] = v;
if (id >= maxVertexID) {
maxVertexID = id + 1;
maxVertexID = id + 1;
}
// Newly created vertices are always candidates for garbage
@ -563,11 +554,11 @@ HbrMesh<T>::NewVertex(const T &data) {
// we can
int id = maxVertexID;
if (!recycleIDs.empty()) {
id = *recycleIDs.begin();
id = *recycleIDs.begin();
recycleIDs.erase(recycleIDs.begin());
}
if (id >= maxVertexID) {
maxVertexID = id + 1;
maxVertexID = id + 1;
}
return NewVertex(id, data);
}
@ -579,11 +570,11 @@ HbrMesh<T>::NewVertex() {
// we can
int id = maxVertexID;
if (!recycleIDs.empty()) {
id = *recycleIDs.begin();
recycleIDs.erase(recycleIDs.begin());
id = *recycleIDs.begin();
recycleIDs.erase(recycleIDs.begin());
}
if (id >= maxVertexID) {
maxVertexID = id + 1;
maxVertexID = id + 1;
}
T data(id);
data.Clear();
@ -596,11 +587,11 @@ HbrMesh<T>::GetVertex(int id) const {
int arrayindex = id / vsetsize;
int vertindex = id % vsetsize;
#if PRMAN or MENV
#if PRMAN or MENV
ScopedLock lock(&m_verticesMutex);
#else
IlmThread::Lock lock(m_verticesMutex);
#endif
#endif
if (arrayindex >= nvsets) {
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));
int i;
for (i = 0; i < nv; ++i) {
facevertices[i] = GetVertex(vtx[i]);
if (!facevertices[i]) {
return 0;
}
facevertices[i] = GetVertex(vtx[i]);
if (!facevertices[i]) {
return 0;
}
}
HbrFace<T> *f = 0;
// Resize if needed
if (nfaces <= maxFaceID) {
int nnfaces = nfaces;
while (nnfaces <= maxFaceID) {
int nnfaces = nfaces;
while (nnfaces <= maxFaceID) {
nnfaces *= 2;
if (nnfaces < 1) nnfaces = 1;
}
HbrFace<T>** newfaces = new HbrFace<T>*[nnfaces];
if (s_memStatsIncrement) {
s_memStatsIncrement(nnfaces * sizeof(HbrFace<T>*));
}
}
HbrFace<T>** newfaces = new HbrFace<T>*[nnfaces];
if (s_memStatsIncrement) {
s_memStatsIncrement(nnfaces * sizeof(HbrFace<T>*));
}
m_memory += nnfaces * sizeof(HbrFace<T>*);
if (faces) {
for (i = 0; i < nfaces; ++i) {
newfaces[i] = faces[i];
}
if (s_memStatsDecrement) {
s_memStatsDecrement(nfaces * sizeof(HbrFace<T>*));
}
if (faces) {
for (i = 0; i < nfaces; ++i) {
newfaces[i] = faces[i];
}
if (s_memStatsDecrement) {
s_memStatsDecrement(nfaces * sizeof(HbrFace<T>*));
}
m_memory -= nfaces * sizeof(HbrFace<T>*);
delete[] faces;
}
for (i = nfaces; i < nnfaces; ++i) {
newfaces[i] = 0;
}
faces = newfaces;
nfaces = nnfaces;
delete[] faces;
}
for (i = nfaces; i < nnfaces; ++i) {
newfaces[i] = 0;
}
faces = newfaces;
nfaces = nnfaces;
}
f = faces[maxFaceID];
if (f) {
f->Destroy();
f->Destroy();
} else {
f = m_faceAllocator.Allocate();
f = m_faceAllocator.Allocate();
}
f->Initialize(this, NULL, -1, maxFaceID, uindex, nv, facevertices, totalfvarwidth, 0);
faces[maxFaceID] = f;
@ -673,37 +664,37 @@ HbrMesh<T>::NewFace(int nv, HbrVertex<T> **vtx, HbrFace<T>* parent, int childind
HbrFace<T> *f = 0;
// Resize if needed
if (nfaces <= maxFaceID) {
int nnfaces = nfaces;
while (nnfaces <= maxFaceID) {
int nnfaces = nfaces;
while (nnfaces <= maxFaceID) {
nnfaces *= 2;
if (nnfaces < 1) nnfaces = 1;
}
HbrFace<T>** newfaces = new HbrFace<T>*[nnfaces];
if (s_memStatsIncrement) {
s_memStatsIncrement(nnfaces * sizeof(HbrFace<T>*));
}
}
HbrFace<T>** newfaces = new HbrFace<T>*[nnfaces];
if (s_memStatsIncrement) {
s_memStatsIncrement(nnfaces * sizeof(HbrFace<T>*));
}
m_memory += nnfaces * sizeof(HbrFace<T>*);
if (faces) {
for (int i = 0; i < nfaces; ++i) {
newfaces[i] = faces[i];
}
if (s_memStatsDecrement) {
s_memStatsDecrement(nfaces * sizeof(HbrFace<T>*));
}
if (faces) {
for (int i = 0; i < nfaces; ++i) {
newfaces[i] = faces[i];
}
if (s_memStatsDecrement) {
s_memStatsDecrement(nfaces * sizeof(HbrFace<T>*));
}
m_memory -= nfaces * sizeof(HbrFace<T>*);
delete[] faces;
}
for (int i = nfaces; i < nnfaces; ++i) {
newfaces[i] = 0;
}
faces = newfaces;
nfaces = nnfaces;
}
delete[] faces;
}
for (int i = nfaces; i < nnfaces; ++i) {
newfaces[i] = 0;
}
faces = newfaces;
nfaces = nnfaces;
}
f = faces[maxFaceID];
if (f) {
f->Destroy();
f->Destroy();
} 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);
if (parent) {
@ -725,36 +716,36 @@ HbrMesh<T>::Finish() {
int i, j;
m_numCoarseFaces = 0;
for (i = 0; i < nfaces; ++i) {
if (faces[i]) {
if (faces[i]) {
faces[i]->SetCoarse();
m_numCoarseFaces++;
}
}
std::list<HbrVertex<T>*> vertexlist;
std::vector<HbrVertex<T>*> 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) {
HbrVertex<T>* vertex = *vi;
if (vertex->IsConnected()) vertex->Finish();
}
// If interpolateboundary is on, process boundary edges
if (interpboundarymethod == k_InterpolateBoundaryEdgeOnly || interpboundarymethod == k_InterpolateBoundaryEdgeAndCorner) {
for (i = 0; i < nfaces; ++i) {
if (HbrFace<T>* face = faces[i]) {
int nv = face->GetNumVertices();
for (int k = 0; k < nv; ++k) {
HbrHalfedge<T>* edge = face->GetEdge(k);
if (edge->IsBoundary()) {
edge->SetSharpness(HbrHalfedge<T>::k_InfinitelySharp);
}
}
}
}
for (i = 0; i < nfaces; ++i) {
if (HbrFace<T>* face = faces[i]) {
int nv = face->GetNumVertices();
for (int k = 0; k < nv; ++k) {
HbrHalfedge<T>* edge = face->GetEdge(k);
if (edge->IsBoundary()) {
edge->SetSharpness(HbrHalfedge<T>::k_InfinitelySharp);
}
}
}
}
}
// Process corners
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) {
HbrVertex<T>* vertex = *vi;
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();
if (nHierarchicalEdits) {
// Size the array by one extra; the last will be a sentinel
// value (null)
hierarchicalEditArray = new HbrHierarchicalEdit<T>*[nHierarchicalEdits + 1];
i = 0;
for (typename std::multiset<HbrHierarchicalEdit<T>*, HbrHierarchicalEditComparator<T> >::iterator pi = hierarchicalEditSet.begin(); pi != hierarchicalEditSet.end(); ++pi) {
hierarchicalEditArray[i++] = *pi;
}
assert(i == nHierarchicalEdits);
hierarchicalEditArray[i] = 0;
// Sort the hierarchical edits
if (!hierarchicalEdits.empty()) {
HbrHierarchicalEditComparator<T> cmp;
int nHierarchicalEdits = (int)hierarchicalEdits.size();
std::sort(hierarchicalEdits.begin(), hierarchicalEdits.end(), cmp);
// Push a sentinel null value - we rely upon this sentinel to
// ensure face->GetHierarchicalEdits knows when to terminate
hierarchicalEdits.push_back(0);
j = 0;
// Link faces to hierarchical edits
for (i = 0; i < nfaces; ++i) {
if (faces[i]) {
while (j < nHierarchicalEdits && hierarchicalEditArray[j]->GetFaceID() < i) {
while (j < nHierarchicalEdits && hierarchicalEdits[j]->GetFaceID() < i) {
++j;
}
if (j < nHierarchicalEdits && hierarchicalEditArray[j]->GetFaceID() == i) {
faces[i]->SetHierarchicalEdits(&hierarchicalEditArray[j]);
if (j < nHierarchicalEdits && hierarchicalEdits[j]->GetFaceID() == i) {
faces[i]->SetHierarchicalEdits(&hierarchicalEdits[j]);
}
}
}
hierarchicalEditSet.clear();
}
}
@ -794,12 +781,12 @@ template <class T>
void
HbrMesh<T>::DeleteFace(HbrFace<T>* face) {
if (face->GetID() < nfaces) {
HbrFace<T>* f = faces[face->GetID()];
if (f == face) {
faces[face->GetID()] = 0;
face->Destroy();
m_faceAllocator.Deallocate(face);
}
HbrFace<T>* f = faces[face->GetID()];
if (f == face) {
faces[face->GetID()] = 0;
face->Destroy();
m_faceAllocator.Deallocate(face);
}
}
}
@ -811,18 +798,18 @@ HbrMesh<T>::DeleteVertex(HbrVertex<T>* vertex) {
recycleIDs.insert(vertex->GetID());
int id = vertex->GetID();
int arrayindex = id / vsetsize;
#if PRMAN or MENV
#if PRMAN or MENV
ScopedLock lock(&m_verticesMutex);
#else
IlmThread::Lock lock(m_verticesMutex);
#endif
#endif
int vertindex = id % vsetsize;
HbrVertex<T>** vset = vertices[arrayindex];
#if PRMAN or MENV
#if PRMAN or MENV
lock.Release();
#else
lock.release();
#endif
#endif
vset[vertindex] = 0;
vertex->Destroy();
m_vertexAllocator.Deallocate(vertex);
@ -833,11 +820,11 @@ template <class T>
int
HbrMesh<T>::GetNumVertices() const {
int count = 0;
#if PRMAN or MENV
#if PRMAN or MENV
ScopedLock lock(&m_verticesMutex);
#else
IlmThread::Lock lock(m_verticesMutex);
#endif
#endif
for (int vi = 0; vi < nvsets; ++vi) {
HbrVertex<T>** vset = vertices[vi];
for (int i = 0; i < vsetsize; ++i) {
@ -851,11 +838,11 @@ template <class T>
int
HbrMesh<T>::GetNumDisconnectedVertices() const {
int disconnected = 0;
#if PRMAN or MENV
#if PRMAN or MENV
ScopedLock lock(&m_verticesMutex);
#else
IlmThread::Lock lock(m_verticesMutex);
#endif
#endif
for (int vi = 0; vi < nvsets; ++vi) {
HbrVertex<T>** vset = vertices[vi];
for (int i = 0; i < vsetsize; ++i) {
@ -874,7 +861,7 @@ int
HbrMesh<T>::GetNumFaces() const {
int count = 0;
for (int i = 0; i < nfaces; ++i) {
if (faces[i]) count++;
if (faces[i]) count++;
}
return count;
}
@ -887,7 +874,7 @@ HbrMesh<T>::GetNumCoarseFaces() const {
// Otherwise we have to just count it up now
int count = 0;
for (int i = 0; i < nfaces; ++i) {
if (faces[i] && faces[i]->IsCoarse()) count++;
if (faces[i] && faces[i]->IsCoarse()) count++;
}
return count;
}
@ -896,19 +883,19 @@ template <class T>
HbrFace<T>*
HbrMesh<T>::GetFace(int id) const {
if (id < nfaces) {
return faces[id];
return faces[id];
}
return 0;
}
template <class T>
void
HbrMesh<T>::GetVertices(std::list<HbrVertex<T>*>& lvertices) const {
#if PRMAN or MENV
HbrMesh<T>::GetVertices(std::vector<HbrVertex<T>*>& lvertices) const {
#if PRMAN or MENV
ScopedLock lock(&m_verticesMutex);
#else
IlmThread::Lock lock(m_verticesMutex);
#endif
#endif
for (int vi = 0; vi < nvsets; ++vi) {
HbrVertex<T>** vset = vertices[vi];
for (int i = 0; i < vsetsize; ++i) {
@ -920,11 +907,11 @@ HbrMesh<T>::GetVertices(std::list<HbrVertex<T>*>& lvertices) const {
template <class T>
void
HbrMesh<T>::ApplyOperatorAllVertices(HbrVertexOperator<T> &op) const {
#if PRMAN or MENV
#if PRMAN or MENV
ScopedLock lock(&m_verticesMutex);
#else
IlmThread::Lock lock(m_verticesMutex);
#endif
#endif
for (int vi = 0; vi < nvsets; ++vi) {
HbrVertex<T>** vset = vertices[vi];
for (int i = 0; i < vsetsize; ++i) {
@ -935,9 +922,9 @@ HbrMesh<T>::ApplyOperatorAllVertices(HbrVertexOperator<T> &op) const {
template <class T>
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) {
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++;
}
else if (!v->IsConnected()) {
out << " disconnected: " << *v << "\n";
out << " disconnected: " << *v << "\n";
disconnected++;
} else {
if (v->IsExtraordinary()) {
@ -979,74 +966,80 @@ HbrMesh<T>::PrintStats(std::ostream &out) {
int sumsides = 0;
int numfaces = 0;
for (i = 0; i < nfaces; ++i) {
if (HbrFace<T>* f = faces[i]) {
numfaces++;
sumsides += f->GetNumVertices();
}
if (HbrFace<T>* f = faces[i]) {
numfaces++;
sumsides += f->GetNumVertices();
}
}
out << "Mesh has " << nfaces << " faces\n";
out << "Average sidedness " << (float) sumsides / nfaces << "\n";
}
#define HBR_MESH_BUFFERSIZE 4096
template <class T>
void
HbrMesh<T>::GarbageCollect() {
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
// up the neighboring faces of those vertices which can be garbage
// collected.
std::list<HbrFace<T>*> killlist;
std::list<HbrVertex<T>*> vlist;
std::vector<HbrFace<T>*> killlist;
std::vector<HbrVertex<T>*> vlist;
while (gcVertices.size() > HBR_MESH_BUFFERSIZE / 2) {
HbrVertex<T>* v = gcVertices.front(); gcVertices.pop_front();
v->ClearCollected();
if (v->IsUsed()) continue;
vlist.push_back(v);
HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge;
edge = start;
while (edge) {
HbrFace<T>* f = edge->GetLeftFace();
if (!f->IsCollected()) {
// Process the vertices in the same order as they were collected
// (gcVertices used to be declared as a std::deque, but that was
// causing unnecessary heap traffic).
int numprocessed = gcVertices.size() - gcthreshold / 2;
for (int i = 0; i < numprocessed; ++i) {
HbrVertex<T>* v = gcVertices[i];
v->ClearCollected();
if (v->IsUsed()) continue;
vlist.push_back(v);
HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge;
edge = start;
while (edge) {
HbrFace<T>* f = edge->GetLeftFace();
if (!f->IsCollected()) {
f->SetCollected();
killlist.push_back(f);
}
edge = v->GetNextEdge(edge);
if (edge == start) break;
}
killlist.push_back(f);
}
edge = v->GetNextEdge(edge);
if (edge == start) break;
}
}
gcVertices.erase(gcVertices.begin(), gcVertices.begin() + numprocessed);
// Delete those faces
for (typename std::list<HbrFace<T>*>::iterator fi = killlist.begin(); fi != killlist.end(); ++fi) {
if ((*fi)->GarbageCollectable()) {
DeleteFace(*fi);
} else {
(*fi)->ClearCollected();
for (typename std::vector<HbrFace<T>*>::iterator fi = killlist.begin(); fi != killlist.end(); ++fi) {
if ((*fi)->GarbageCollectable()) {
DeleteFace(*fi);
} else {
(*fi)->ClearCollected();
}
}
// Delete as many vertices as we can
for (typename std::list<HbrVertex<T>*>::iterator vi = vlist.begin(); vi != vlist.end(); ++vi) {
HbrVertex<T>* v = *vi;
if (!v->IsReferenced()) {
DeleteVertex(v);
}
for (typename std::vector<HbrVertex<T>*>::iterator vi = vlist.begin(); vi != vlist.end(); ++vi) {
HbrVertex<T>* v = *vi;
if (!v->IsReferenced()) {
DeleteVertex(v);
}
}
}
template <class T>
void
HbrMesh<T>::AddHierarchicalEdit(HbrHierarchicalEdit<T>* edit) {
hierarchicalEditSet.insert(edit);
hierarchicalEdits.push_back(edit);
if (dynamic_cast<HbrVertexEdit<T>*>(edit) ||
dynamic_cast<HbrMovingVertexEdit<T>*>(edit)) {
hasVertexEdits = 1;
dynamic_cast<HbrMovingVertexEdit<T>*>(edit)) {
hasVertexEdits = 1;
} else if (dynamic_cast<HbrCreaseEdit<T>*>(edit)) {
hasCreaseEdits = 1;
hasCreaseEdits = 1;
}
}
@ -1054,13 +1047,13 @@ template <class T>
void
HbrMesh<T>::FreeTransientData() {
// 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) {
DeleteFace(*fi);
}
// The vertices should now be trivial to purge after the transient
// 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) {
DeleteVertex(*vi);
}
@ -1075,11 +1068,11 @@ HbrMesh<T>::FreeTransientData() {
}
}
// Reset max vertex ID. Slightly more complicated
#if PRMAN or MENV
#if PRMAN or MENV
ScopedLock lock(&m_verticesMutex);
#else
IlmThread::Lock lock(m_verticesMutex);
#endif
#endif
for (i = (nvsets * vsetsize) - 1; i >= 0; --i) {
int arrayindex = i / vsetsize;
int vertindex = i % vsetsize;

View File

@ -69,12 +69,12 @@ template <class T> class HbrMesh;
template <class T> class HbrSubdivision {
public:
HbrSubdivision<T>()
: creaseSubdivision(k_CreaseNormal) {}
: creaseSubdivision(k_CreaseNormal) {}
virtual ~HbrSubdivision<T>() {}
virtual HbrSubdivision<T>* Clone() const = 0;
// How to subdivide a face
virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face) = 0;
@ -83,7 +83,7 @@ public:
// Refine all faces around a particular vertex
virtual void RefineAtVertex(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
// Given an edge, try to ensure the edge's opposite exists by
// forcing refinement up the hierarchy
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 */, HbrHalfedge<T>* /* edge */) { return true; }
virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrVertex<T>* /* vertex */) { return true; }
// 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, HbrHalfedge<T>* edge) = 0;
@ -106,6 +106,9 @@ public:
// Returns true if the vertex is extraordinary in the subdivision scheme
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
// strength, we get two child subedges, and we need to determine
// what weights to assign these subedges. The "normal" rule
@ -115,8 +118,8 @@ public:
// vertices, and weighs them; for more information consult
// the Geri's Game paper.
enum CreaseSubdivision {
k_CreaseNormal,
k_CreaseChaikin
k_CreaseNormal,
k_CreaseChaikin
};
CreaseSubdivision GetCreaseSubdivisionMethod() const { return creaseSubdivision; }
void SetCreaseSubdivisionMethod(CreaseSubdivision method) { creaseSubdivision = method; }
@ -132,7 +135,7 @@ public:
// Returns the expected number of children faces after subdivision
// for a face with the given number of vertices.
virtual int GetFaceChildrenCount(int nvertices) const = 0;
protected:
CreaseSubdivision creaseSubdivision;
@ -143,7 +146,7 @@ protected:
// Helper routine for subclasses: for a given vertex with a crease
// mask, adds contributions from the two crease edges
void AddCreaseEdgesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, bool next, float weight, T* data);
private:
// Helper class used by AddSurroundingVerticesWithWeight
class SmoothSubdivisionVertexOperator : public HbrVertexOperator<T> {
@ -155,7 +158,7 @@ private:
{
}
virtual void operator() (HbrVertex<T> &vertex) {
// Must ensure vertex edits have been applied
// Must ensure vertex edits have been applied
if (m_meshHasEdits) {
vertex.GuaranteeNeighbors();
}
@ -186,7 +189,7 @@ private:
// Must ensure vertex edits have been applied
if (m_meshHasEdits) {
a->GuaranteeNeighbors();
}
}
m_data->AddWithWeight(a->GetData(), m_weight);
m_count++;
}
@ -218,7 +221,7 @@ private:
HbrMesh<T>* const m_mesh;
HbrVertex<T>* const m_vertex;
};
};
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
// child edge is also infinitely sharp
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,
// plus 1/4 of crease sharpnesses incident to vertex
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
// the vertex (other than this crease edge)
std::list<HbrHalfedge<T>*> edges;
vertex->GuaranteeNeighbors();
vertex->GetSurroundingEdges(edges);
// Add 1/4 of the sharpness of all crease edges incident to
// the vertex (other than this crease edge)
std::vector<HbrHalfedge<T>*> edges;
vertex->GuaranteeNeighbors();
vertex->GetSurroundingEdges(edges);
int n = 0;
for (typename std::list<HbrHalfedge<T>*>::iterator ei = edges.begin(); ei != edges.end(); ++ei) {
if (*ei == edge) continue;
if ((*ei)->GetSharpness() > HbrHalfedge<T>::k_Smooth) {
childsharp += (*ei)->GetSharpness();
n++;
}
}
int n = 0;
for (typename std::vector<HbrHalfedge<T>*>::iterator ei = edges.begin(); ei != edges.end(); ++ei) {
if (*ei == edge) continue;
if ((*ei)->GetSharpness() > HbrHalfedge<T>::k_Smooth) {
childsharp += (*ei)->GetSharpness();
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 {
sharpness -= 1.0f;
if (sharpness < (float) HbrHalfedge<T>::k_Smooth) {
sharpness = (float) HbrHalfedge<T>::k_Smooth;
}
subedge->SetSharpness(sharpness);
sharpness -= 1.0f;
if (sharpness < (float) HbrHalfedge<T>::k_Smooth) {
sharpness = (float) HbrHalfedge<T>::k_Smooth;
}
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) {
out << "vertex path = (" << path.faceid << ' ';
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] << ')';
}
@ -82,24 +82,24 @@ class HbrVertexEdit : public HbrHierarchicalEdit<T> {
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)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
edit = new float[width];
memcpy(edit, _edit, width * sizeof(float));
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
edit = new float[width];
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)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
edit = new float[width];
memcpy(edit, _edit, width * sizeof(float));
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
edit = new float[width];
memcpy(edit, _edit, width * sizeof(float));
}
virtual ~HbrVertexEdit() {
delete[] edit;
delete[] edit;
}
// Return the vertex id (the last element in the path)
unsigned char GetVertexID() const { return vertexid; }
friend std::ostream& operator<< <T> (std::ostream& out, const HbrVertexEdit<T>& path);
// Return index of variable this edit applies to
@ -113,48 +113,48 @@ public:
// Get the type of operation
typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; }
virtual void ApplyEditToFace(HbrFace<T>* face) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
// Tags the vertex as being edited; it'll figure out what to
// when GuaranteeNeighbor is called
face->GetVertex(vertexid)->SetVertexEdit();
}
// In any event, mark the face as having a vertex edit (which
// may only be applied on subfaces)
face->MarkVertexEdits();
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
// Tags the vertex as being edited; it'll figure out what to
// when GuaranteeNeighbor is called
face->GetVertex(vertexid)->SetVertexEdit();
}
// In any event, mark the face as having a vertex edit (which
// may only be applied on subfaces)
face->MarkVertexEdits();
}
virtual void ApplyEditToVertex(HbrFace<T>* face, HbrVertex<T>* vertex) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth() &&
face->GetVertex(vertexid) == vertex) {
vertex->GetData().ApplyVertexEdit(*const_cast<const HbrVertexEdit<T>*>(this));
}
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth() &&
face->GetVertex(vertexid) == vertex) {
vertex->GetData().ApplyVertexEdit(*const_cast<const HbrVertexEdit<T>*>(this));
}
}
#ifdef PRMAN
virtual void ApplyToBound(struct bbox& bbox, RtMatrix *mx) {
if (isP) {
struct xyz p = *(struct xyz*)edit;
if (mx)
MxTransformByMatrix(&p, &p, *mx, 1);
if (op == HbrHierarchicalEdit<T>::Set) {
bbox.min.x = std::min(bbox.min.x, p.x);
bbox.min.y = std::min(bbox.min.y, p.y);
bbox.min.z = std::min(bbox.min.z, p.z);
bbox.max.x = std::max(bbox.max.x, p.x);
bbox.max.y = std::max(bbox.max.y, p.y);
bbox.max.z = std::max(bbox.max.z, p.z);
} else if (op == HbrHierarchicalEdit<T>::Add ||
op == HbrHierarchicalEdit<T>::Subtract) {
bbox.min.x -= fabsf(p.x);
bbox.min.y -= fabsf(p.y);
bbox.min.z -= fabsf(p.z);
bbox.max.x += fabsf(p.x);
bbox.max.y += fabsf(p.y);
bbox.max.z += fabsf(p.z);
}
}
virtual void ApplyToBound(struct bbox& bbox, RtMatrix *mx) const {
if (isP) {
struct xyz p = *(struct xyz*)edit;
if (mx)
MxTransformByMatrix(&p, &p, *mx, 1);
if (op == HbrHierarchicalEdit<T>::Set) {
bbox.min.x = std::min(bbox.min.x, p.x);
bbox.min.y = std::min(bbox.min.y, p.y);
bbox.min.z = std::min(bbox.min.z, p.z);
bbox.max.x = std::max(bbox.max.x, p.x);
bbox.max.y = std::max(bbox.max.y, p.y);
bbox.max.z = std::max(bbox.max.z, p.z);
} else if (op == HbrHierarchicalEdit<T>::Add ||
op == HbrHierarchicalEdit<T>::Subtract) {
bbox.min.x -= fabsf(p.x);
bbox.min.y -= fabsf(p.y);
bbox.min.z -= fabsf(p.z);
bbox.max.x += fabsf(p.x);
bbox.max.y += fabsf(p.y);
bbox.max.z += fabsf(p.z);
}
}
}
#endif
@ -173,24 +173,24 @@ class HbrMovingVertexEdit : public HbrHierarchicalEdit<T> {
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)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
edit = new float[width * 2];
memcpy(edit, _edit, 2 * width * sizeof(float));
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
edit = new float[width * 2];
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)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
edit = new float[width * 2];
memcpy(edit, _edit, 2 * width * sizeof(float));
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(_vertexid), index(_index), width(_width), isP(_isP), op(_op) {
edit = new float[width * 2];
memcpy(edit, _edit, 2 * width * sizeof(float));
}
virtual ~HbrMovingVertexEdit() {
delete[] edit;
delete[] edit;
}
// Return the vertex id (the last element in the path)
unsigned char GetVertexID() const { return vertexid; }
friend std::ostream& operator<< <T> (std::ostream& out, const HbrVertexEdit<T>& path);
// Return index of variable this edit applies to
@ -198,60 +198,60 @@ public:
// Return width of the variable
int GetWidth() const { return width; }
// Get the numerical value of the edit
const float* GetEdit() const { return edit; }
// Get the type of operation
typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; }
virtual void ApplyEditToFace(HbrFace<T>* face) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
// Tags the vertex as being edited; it'll figure out what to
// when GuaranteeNeighbor is called
face->GetVertex(vertexid)->SetVertexEdit();
}
// In any event, mark the face as having a vertex edit (which
// may only be applied on subfaces)
face->MarkVertexEdits();
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
// Tags the vertex as being edited; it'll figure out what to
// when GuaranteeNeighbor is called
face->GetVertex(vertexid)->SetVertexEdit();
}
// In any event, mark the face as having a vertex edit (which
// may only be applied on subfaces)
face->MarkVertexEdits();
}
virtual void ApplyEditToVertex(HbrFace<T>* face, HbrVertex<T>* vertex) {
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth() &&
face->GetVertex(vertexid) == vertex) {
vertex->GetData().ApplyMovingVertexEdit(*const_cast<const HbrMovingVertexEdit<T>*>(this));
}
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth() &&
face->GetVertex(vertexid) == vertex) {
vertex->GetData().ApplyMovingVertexEdit(*const_cast<const HbrMovingVertexEdit<T>*>(this));
}
}
#ifdef PRMAN
virtual void ApplyToBound(struct bbox& bbox, RtMatrix *mx) {
if (isP) {
struct xyz p1 = *(struct xyz*)edit;
struct xyz p2 = *(struct xyz*)&edit[3];
if (mx) {
MxTransformByMatrix(&p1, &p1, *mx, 1);
MxTransformByMatrix(&p2, &p2, *mx, 1);
}
if (op == HbrVertexEdit<T>::Set) {
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.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.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);
} else if (op == HbrVertexEdit<T>::Add ||
op == HbrVertexEdit<T>::Subtract) {
float maxx = std::max(fabsf(p1.x), fabsf(p2.x));
float maxy = std::max(fabsf(p1.y), fabsf(p2.y));
float maxz = std::max(fabsf(p1.z), fabsf(p2.z));
bbox.min.x -= maxx;
bbox.min.y -= maxy;
bbox.min.z -= maxz;
bbox.max.x += maxx;
bbox.max.y += maxy;
bbox.max.z += maxz;
}
}
virtual void ApplyToBound(struct bbox& bbox, RtMatrix *mx) const {
if (isP) {
struct xyz p1 = *(struct xyz*)edit;
struct xyz p2 = *(struct xyz*)&edit[3];
if (mx) {
MxTransformByMatrix(&p1, &p1, *mx, 1);
MxTransformByMatrix(&p2, &p2, *mx, 1);
}
if (op == HbrVertexEdit<T>::Set) {
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.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.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);
} else if (op == HbrVertexEdit<T>::Add ||
op == HbrVertexEdit<T>::Subtract) {
float maxx = std::max(fabsf(p1.x), fabsf(p2.x));
float maxy = std::max(fabsf(p1.y), fabsf(p2.y));
float maxz = std::max(fabsf(p1.z), fabsf(p2.z));
bbox.min.x -= maxx;
bbox.min.y -= maxy;
bbox.min.z -= maxz;
bbox.max.x += maxx;
bbox.max.y += maxy;
bbox.max.z += maxz;
}
}
}
#endif

View File

@ -71,7 +71,7 @@ set(SOURCE_FILES
cpuKernel.cpp
kernelDispatcher.cpp
mesh.cpp
vertexBuffer.cpp
vertexBuffer.cpp
)
set(KERNEL_FILES
@ -96,7 +96,9 @@ set(PUBLIC_HEADER_FILES
#-------------------------------------------------------------------------------
# platform dependent tweaks
if(APPLE)
set(PLATFORM_COMPILE_FLAGS
-fPIC
)
elseif(UNIX)
set(PLATFORM_COMPILE_FLAGS
-fPIC
@ -110,26 +112,31 @@ add_definitions(
)
#-------------------------------------------------------------------------------
if( OPENMP_FOUND )
add_definitions(
-DOPENSUBDIV_HAS_OPENMP
${OpenMP_CXX_FLAGS}
if( PTEX_FOUND )
list(APPEND SOURCE_FILES
pTexture.cpp
)
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)
list(APPEND PLATFORM_LIBRARIES
gomp
)
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()
#-------------------------------------------------------------------------------
# GL code & dependencies
# note : (GLSL compute kernels require GL 4.2, which excludes APPLE)
# GL code & dependencies
# note : (GLSL compute kernels require GL 4.2, which excludes APPLE)
if( OPENGL_FOUND AND GLEW_FOUND AND (NOT APPLE) )
list(APPEND SOURCE_FILES
glslDispatcher.cpp
@ -143,19 +150,16 @@ if( OPENGL_FOUND AND GLEW_FOUND AND (NOT APPLE) )
list(APPEND PLATFORM_LIBRARIES
${OPENGL_LIBRARY}
${GLEW_LIBRARY}
)
add_definitions(
-DOPENSUBDIV_HAS_GLSL
)
else()
message(STATUS
"* 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.")
else( OPENGL_FOUND AND APPLE )
list(APPEND PLATFORM_LIBRARIES
${OPENGL_LIBRARY}
${ILMBASE_LIBRARIES}
)
endif()
#-------------------------------------------------------------------------------
# OpenCL code & dependencies
# OpenCL code & dependencies
if ( OPENCL_FOUND )
list(APPEND SOURCE_FILES
clDispatcher.cpp
@ -168,19 +172,11 @@ if ( OPENCL_FOUND )
)
list(APPEND PLATFORM_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()
#-------------------------------------------------------------------------------
# CUDA code & dependencies
# CUDA code & dependencies
if( CUDA_FOUND )
list(APPEND SOURCE_FILES
cudaDispatcher.cpp
@ -191,17 +187,9 @@ if( CUDA_FOUND )
list(APPEND KERNEL_FILES
cudaKernel.cu
)
add_definitions(
-DOPENSUBDIV_HAS_CUDA
)
if (UNIX)
list( APPEND CUDA_NVCC_FLAGS -Xcompiler -fPIC )
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()
@ -220,15 +208,15 @@ foreach(kernel_file ${KERNEL_FILES})
string(REGEX REPLACE "(.*)[.].*" "\\1.inc" inc_file ${kernel_file})
list(APPEND INC_FILES ${inc_file})
add_custom_command(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${inc_file}
COMMAND stringify ${CMAKE_CURRENT_SOURCE_DIR}/${kernel_file}
${CMAKE_CURRENT_SOURCE_DIR}/${inc_file}
DEPENDS stringify ${CMAKE_CURRENT_SOURCE_DIR}/${kernel_file}
)
endif()
endif()
endforeach()
#-------------------------------------------------------------------------------
@ -236,7 +224,7 @@ source_group("Kernels" FILES ${KERNEL_FILES})
source_group("Inc" FILES ${INC_FILES})
_add_library(osd_static STATIC
_add_possibly_cuda_library(osd_static STATIC
${SOURCE_FILES}
${PRIVATE_HEADER_FILES}
${PUBLIC_HEADER_FILES}
@ -250,7 +238,7 @@ target_link_libraries(osd_static
)
if (NOT WIN32)
_add_library(osd_dynamic SHARED
_add_possibly_cuda_library(osd_dynamic SHARED
${SOURCE_FILES}
${PRIVATE_HEADER_FILES}
${PUBLIC_HEADER_FILES}

View File

@ -61,6 +61,7 @@
#if defined(_WIN32)
#include <windows.h>
#elif defined(__APPLE__)
#include <OpenGL/OpenGL.h>
#include <OpenCL/opencl.h>
#else
#include <GL/glx.h>
@ -85,9 +86,9 @@ static const char *clSource =
std::vector<OsdClKernelDispatcher::ClKernel> OsdClKernelDispatcher::kernelRegistry;
// XXX: context and queue should be moved to client code
cl_context OsdClKernelDispatcher::_clContext = NULL;
cl_command_queue OsdClKernelDispatcher::_clQueue = NULL;
cl_device_id OsdClKernelDispatcher::_clDevice=NULL;
OsdClVertexBuffer::OsdClVertexBuffer(int numElements, int numVertices,
cl_context clContext, cl_command_queue clQueue) :
@ -143,7 +144,7 @@ OsdClKernelDispatcher::DeviceTable::Copy(cl_context context, int size, const voi
clReleaseMemObject(devicePtr);
devicePtr = clCreateBuffer(context, CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR, size,
const_cast<void*>(table), &ciErrNum);
CL_CHECK_ERROR(ciErrNum, "Table copy %p\n", table);
}
}
@ -229,6 +230,52 @@ OsdClKernelDispatcher::Synchronize() {
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
OsdClKernelDispatcher::ApplyCatmarkFaceVerticesKernel(FarMesh<OsdVertex> * mesh, int offset,
int level, int start, int end, void * data) const {
@ -252,7 +299,7 @@ OsdClKernelDispatcher::ApplyCatmarkFaceVerticesKernel(FarMesh<OsdVertex> * mesh,
}
void
OsdClKernelDispatcher::ApplyCatmarkEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset,
OsdClKernelDispatcher::ApplyCatmarkEdgeVerticesKernel(FarMesh<OsdVertex> * mesh, int offset,
int level, int start, int end, void * data) const {
cl_int ciErrNum;
@ -268,7 +315,7 @@ OsdClKernelDispatcher::ApplyCatmarkEdgeVerticesKernel(FarMesh<OsdVertex> * mesh,
clSetKernelArg(kernel, 6, sizeof(int), &offset);
clSetKernelArg(kernel, 7, sizeof(int), &start);
clSetKernelArg(kernel, 8, sizeof(int), &end);
ciErrNum = clEnqueueNDRangeKernel(_clQueue, kernel, 1, NULL, globalWorkSize, NULL, 0, NULL, NULL);
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
void
void
OsdClKernelDispatcher::initCL() {
cl_int ciErrNum;
@ -415,9 +462,8 @@ OsdClKernelDispatcher::initCL() {
}
}
// -------------
cl_device_id cdDevice;
clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 1, &cdDevice, NULL);
clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 1, &_clDevice, NULL);
#if defined(_WIN32)
cl_context_properties props[] = {
CL_GL_CONTEXT_KHR, (cl_context_properties)wglGetCurrentContext(),
@ -442,10 +488,10 @@ OsdClKernelDispatcher::initCL() {
#endif
// 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");
_clQueue = clCreateCommandQueue(_clContext, cdDevice, 0, &ciErrNum);
_clQueue = clCreateCommandQueue(_clContext, _clDevice, 0, &ciErrNum);
CL_CHECK_ERROR(ciErrNum, "clCreateCommandQueue\n");
}
@ -460,6 +506,8 @@ OsdClKernelDispatcher::uninitCL() {
// ------------------------------------------------------------------
OsdClKernelDispatcher::ClKernel::ClKernel() :
_clBilinearEdge(NULL),
_clBilinearVertex(NULL),
_clCatmarkFace(NULL),
_clCatmarkEdge(NULL),
_clCatmarkVertexA(NULL),
@ -472,6 +520,11 @@ OsdClKernelDispatcher::ClKernel::ClKernel() :
OsdClKernelDispatcher::ClKernel::~ClKernel() {
if (_clBilinearEdge)
clReleaseKernel(_clBilinearEdge);
if (_clBilinearVertex)
clReleaseKernel(_clBilinearVertex);
if (_clCatmarkFace)
clReleaseKernel(_clCatmarkFace);
if (_clCatmarkEdge)
@ -491,6 +544,15 @@ OsdClKernelDispatcher::ClKernel::~ClKernel() {
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
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);
if (ciErrNum != CL_SUCCESS) {
OSD_ERROR("ERROR in clBuildProgram %d\n", ciErrNum);
//char cBuildLog[10240];
//clGetProgramBuildInfo(_clProgram, cdDevice, CL_PROGRAM_BUILD_LOG,
// sizeof(cBuildLog), cBuildLog, NULL);
//OSD_ERROR(cBuildLog);
char cBuildLog[10240];
clGetProgramBuildInfo(_clProgram, _clDevice, CL_PROGRAM_BUILD_LOG,
sizeof(cBuildLog), cBuildLog, NULL);
OSD_ERROR(cBuildLog);
return false;
}
// -------
_clCatmarkFace = clCreateKernel(_clProgram, "computeFace", &ciErrNum);
CL_CHECK_ERROR(ciErrNum, "clCreateKernel face\n");
_clCatmarkEdge = clCreateKernel(_clProgram, "computeEdge", &ciErrNum);
CL_CHECK_ERROR(ciErrNum, "clCreateKernel edge\n");
_clCatmarkVertexA = clCreateKernel(_clProgram, "computeVertexA", &ciErrNum);
CL_CHECK_ERROR(ciErrNum, "clCreateKernel vertex a\n");
_clCatmarkVertexB = clCreateKernel(_clProgram, "computeVertexB", &ciErrNum);
CL_CHECK_ERROR(ciErrNum, "clCreateKernel vertex b\n");
_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");
_clBilinearEdge = buildKernel(_clProgram, "computeBilinearEdge");
_clBilinearVertex = buildKernel(_clProgram, "computeBilinearVertex");
_clCatmarkFace = buildKernel(_clProgram, "computeFace");
_clCatmarkEdge = buildKernel(_clProgram, "computeEdge");
_clCatmarkVertexA = buildKernel(_clProgram, "computeVertexA");
_clCatmarkVertexB = buildKernel(_clProgram, "computeVertexB");
_clLoopEdge = buildKernel(_clProgram, "computeEdge");
_clLoopVertexA = buildKernel(_clProgram, "computeVertexA");
_clLoopVertexB = buildKernel(_clProgram, "computeLoopVertexB");
return true;
}

View File

@ -93,24 +93,38 @@ public:
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 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 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 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 ApplyVertexEdit(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const {}
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 OnKernelFinish() {}
@ -118,7 +132,7 @@ public:
virtual OsdVertexBuffer *InitializeVertexBuffer(int numElements, int count);
virtual void BindVertexBuffer(OsdVertexBuffer *vertex, OsdVertexBuffer *varying);
virtual void UnbindVertexBuffer();
virtual void Synchronize();
@ -139,13 +153,23 @@ protected:
bool Compile(cl_context clContext, int numVertexElements, int numVaryingElements);
cl_kernel GetCatmarkFaceKernel() const { return _clCatmarkFace; }
cl_kernel GetCatmarkEdgeKernel() const { return _clCatmarkEdge; }
cl_kernel GetBilinearEdgeKernel() const { return _clBilinearEdge; }
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 GetCatmarkVertexKernelB() const { return _clCatmarkVertexB; }
cl_kernel GetLoopEdgeKernel() const { return _clLoopEdge; }
cl_kernel GetLoopVertexKernelA() const { return _clLoopVertexA; }
cl_kernel GetLoopVertexKernelB() const { return _clLoopVertexB; }
cl_kernel GetLoopEdgeKernel() const { return _clLoopEdge; }
cl_kernel GetLoopVertexKernelA() const { return _clLoopVertexA; }
cl_kernel GetLoopVertexKernelB() const { return _clLoopVertexB; }
struct Match {
Match(int numVertexElements, int numVaryingElements) :
@ -161,12 +185,22 @@ protected:
protected:
cl_program _clProgram;
cl_kernel _clCatmarkFace, _clCatmarkEdge, _clCatmarkVertexA, _clCatmarkVertexB;
cl_kernel _clLoopEdge, _clLoopVertexA, _clLoopVertexB;
int _numVertexElements, _numVaryingElements;
cl_kernel _clBilinearEdge,
_clBilinearVertex,
_clCatmarkFace,
_clCatmarkEdge,
_clCatmarkVertexA,
_clCatmarkVertexB,
_clLoopEdge,
_clLoopVertexA,
_clLoopVertexB;
int _numVertexElements,
_numVaryingElements;
};
struct DeviceTable
struct DeviceTable
{
DeviceTable() : devicePtr(NULL) {}
~DeviceTable();
@ -200,8 +234,9 @@ protected:
ClKernel * _clKernel;
// 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_device_id _clDevice;
// static shader registry (XXX tentative..)
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,
@ -107,9 +161,9 @@ __kernel void computeFace(__global struct Vertex *vertex,
int i = start + get_global_id(0);
int h = F_ITa[2*i];
int n = F_ITa[2*i+1];
float weight = 1.0f/n;
struct Vertex dst;
struct Varying dstVarying;
clearVertex(&dst);
@ -136,11 +190,11 @@ __kernel void computeEdge(__global struct Vertex *vertex,
int i = start + get_global_id(0);
int eidx0 = E_IT[4*i+0];
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];
float vertWeight = E_W[i*2+0];
// Fully sharp edge : vertWeight = 0.5f;
struct Vertex dst;
struct Varying dstVarying;
@ -149,10 +203,10 @@ __kernel void computeEdge(__global struct Vertex *vertex,
addWithWeight(&dst, &vertex[eidx0], vertWeight);
addWithWeight(&dst, &vertex[eidx1], vertWeight);
if (eidx2 > -1) {
float faceWeight = E_W[i*2+1];
addWithWeight(&dst, &vertex[eidx2], 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 eidx0 = V_ITa[5*i+3];
int eidx1 = V_ITa[5*i+4];
float weight = (pass==1) ? V_W[i] : 1.0f - V_W[i];
// In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the
// In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the
// k_Smooth kernel runs much more often than this one)
if (weight>0.0f && weight<1.0f && n > 0)
weight=1.0f-weight;
struct Vertex dst;
if (not pass)
clearVertex(&dst);
@ -227,7 +281,7 @@ __kernel void computeVertexB(__global struct Vertex *vertex,
int h = V_ITa[5*i];
int n = V_ITa[5*i+1];
int p = V_ITa[5*i+2];
float weight = V_W[i];
float wp = 1.0f/(float)(n*n);
float wv = (n-2.0f) * n * wp;
@ -236,7 +290,7 @@ __kernel void computeVertexB(__global struct Vertex *vertex,
clearVertex(&dst);
addWithWeight(&dst, &vertex[p], weight * wv);
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+1]], weight * wp);
@ -267,7 +321,7 @@ __kernel void computeLoopVertexB(__global struct Vertex *vertex,
int h = V_ITa[5*i];
int n = V_ITa[5*i+1];
int p = V_ITa[5*i+2];
float weight = V_W[i];
float wp = 1.0f/(float)(n);
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;
clearVertex(&dst);
addWithWeight(&dst, &vertex[p], weight * (1.0f - (beta * n)));
for (int j = 0; j < n; ++j) {
addWithWeight(&dst, &vertex[V_IT[h+j]], weight * beta);
}

View File

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

View File

@ -69,35 +69,41 @@ class OsdCpuKernelDispatcher : public OsdKernelDispatcher
{
public:
OsdCpuKernelDispatcher(int levels, int numOmpThreads=1);
virtual ~OsdCpuKernelDispatcher();
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 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 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 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 ApplyVertexEdit(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const;
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 OnKernelFinish() {}
@ -113,15 +119,16 @@ public:
static void Register();
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 *ptr;
void *ptr;
};
float *GetVertexBuffer() const { return _currentVertexBuffer ? _currentVertexBuffer->GetCpuBuffer() : NULL; }
@ -134,7 +141,8 @@ protected:
VertexDescriptor *_vdesc;
int _numOmpThreads;
std::vector<SubdivisionTable> _tables;
std::vector<Table> _tables;
std::vector<Table> _editTables;
};
} // end namespace OPENSUBDIV_VERSION

View File

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

View File

@ -58,13 +58,14 @@
#define OSD_CPU_KERNEL_H
#include "../version.h"
#include <stdio.h>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
struct VertexDescriptor {
VertexDescriptor(int numVertexElem, int numVaryingElem)
VertexDescriptor(int numVertexElem, int numVaryingElem)
: numVertexElements(numVertexElem), numVaryingElements(numVaryingElem) { }
void Clear(float *vertex, float *varying, int index) const {
@ -90,7 +91,14 @@ struct VertexDescriptor {
for (int i = 0; i < numVaryingElements; ++i)
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 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 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

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 OsdCudaEditVertexAdd(float *vertex, int numUserVertexElements, int primVarOffset, int primVarWidth, int numVertices, int *editIndices, float *editValues);
}
namespace OpenSubdiv {
@ -145,7 +147,34 @@ OsdCudaKernelDispatcher::~OsdCudaKernelDispatcher() {
void
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 *
@ -174,7 +203,7 @@ OsdCudaKernelDispatcher::BindVertexBuffer(OsdVertexBuffer *vertex, OsdVertexBuff
} else {
_numVertexElements = 0;
}
if (_currentVaryingBuffer) {
_deviceVaryings = (float*)_currentVaryingBuffer->Map();
_numVaryingElements = _currentVaryingBuffer->GetNumElements();
@ -222,7 +251,7 @@ OsdCudaKernelDispatcher::ApplyBilinearEdgeVerticesKernel(FarMesh<OsdVertex> * me
void
OsdCudaKernelDispatcher::ApplyBilinearVertexVerticesKernel(FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
OsdCudaComputeBilinearVertex(_deviceVertices, _deviceVaryings,
_numVertexElements-3, _numVaryingElements,
(int*)_tables[V_ITa].devicePtr + _tableOffsets[V_ITa][level-1],
@ -299,5 +328,21 @@ OsdCudaKernelDispatcher::ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mes
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

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 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 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 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 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 ApplyVertexEdit(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const;
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 OnKernelFinish() {}
@ -125,7 +133,7 @@ public:
virtual OsdVertexBuffer *InitializeVertexBuffer(int numElements, int numVertices);
virtual void BindVertexBuffer(OsdVertexBuffer *vertex, OsdVertexBuffer *varying);
virtual void UnbindVertexBuffer();
virtual void Synchronize();
@ -138,7 +146,7 @@ public:
}
protected:
struct DeviceTable
struct DeviceTable
{
DeviceTable() : devicePtr(NULL) {}
~DeviceTable();
@ -149,6 +157,7 @@ protected:
};
std::vector<DeviceTable> _tables;
std::vector<DeviceTable> _editTables;
OsdCudaVertexBuffer *_currentVertexBuffer,
*_currentVaryingBuffer;
@ -156,7 +165,7 @@ protected:
float *_deviceVertices,
*_deviceVaryings;
int _numVertexElements,
int _numVertexElements,
_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 n = F0_ITa[2*i+1];
float weight = 1.0f/n;
DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst;
dst.clear();
if(NUM_VARYING_ELEMENTS > 0){
DeviceVarying<NUM_VARYING_ELEMENTS> dstVarying;
dstVarying.clear();
for(int j=0; j<n; ++j){
int index = F0_IT[h+j];
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){
int eidx0 = E0_IT[4*i+0];
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];
float vertWeight = E0_S[i*2+0];
// Fully sharp edge : vertWeight = 0.5f;
DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst;
dst.clear();
dst.addWithWeight(&vertex[eidx0], vertWeight);
dst.addWithWeight(&vertex[eidx1], vertWeight);
if(eidx2 > -1){
float faceWeight = E0_S[i*2+1];
dst.addWithWeight(&vertex[eidx2], 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
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)
{
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 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];
float vertWeight = E0_S[i*2+0];
// Fully sharp edge : vertWeight = 0.5f;
float *dstVertex = fVertex + (i+offset)*numVertexElements;
clear(dstVertex, numVertexElements);
addWithWeight(dstVertex, fVertex + eidx0*numVertexElements, vertWeight, numVertexElements);
addWithWeight(dstVertex, fVertex + eidx1*numVertexElements, vertWeight, numVertexElements);
if(eidx2 > -1){
float faceWeight = E0_S[i*2+1];
addWithWeight(dstVertex, fVertex + eidx2*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 eidx0 = V0_ITa[5*i+3];
int eidx1 = V0_ITa[5*i+4];
float weight = (pass==1) ? V0_S[i] : 1.0f - V0_S[i];
// In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the
// In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the
// k_Smooth kernel runs much more often than this one)
if (weight>0.0f && weight<1.0f && n > 0)
weight=1.0f-weight;
DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst;
if (not pass) {
dst.clear();
} else {
dst = vertex[i+offset];
}
if (eidx0==-1 || (pass==0 && (n==-1)) ) {
dst.addWithWeight(&vertex[p], weight);
} else {
@ -318,11 +318,11 @@ computeVertexA(float *fVertex, int numVertexElements, float *fVaryings, int numV
int p = V0_ITa[5*i+2];
int eidx0 = V0_ITa[5*i+3];
int eidx1 = V0_ITa[5*i+4];
float weight = (pass==1) ? V0_S[i] : 1.0f - V0_S[i];
// In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the
// In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the
// k_Smooth kernel runs much more often than this one)
if (weight>0.0f && weight<1.0f && n > 0)
weight=1.0f-weight;
@ -331,7 +331,7 @@ computeVertexA(float *fVertex, int numVertexElements, float *fVaryings, int numV
if (not pass) {
clear(dstVertex, numVertexElements);
}
if (eidx0==-1 || (pass==0 && (n==-1)) ) {
addWithWeight(dstVertex, fVertex + p*numVertexElements, weight, numVertexElements);
} 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 n = V0_ITa[5*i+1];
int p = V0_ITa[5*i+2];
float weight = V0_S[i];
float wp = 1.0f/float(n*n);
float wv = (n-2.0f) * n * wp;
DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst;
dst.clear();
dst.addWithWeight(&vertex[p], weight * wv);
@ -381,7 +381,7 @@ computeVertexB(float *fVertex, float *fVaryings,
// dst.addWithWeight(&vertex[idx0], weight * wp);
// dst.addWithWeight(&vertex[idx1], weight * wp);
}
vertex[i+offset] = dst;
vertex[i+offset] = dst;
if(NUM_VARYING_ELEMENTS > 0){
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 n = V0_ITa[5*i+1];
int p = V0_ITa[5*i+2];
float weight = V0_S[i];
float wp = 1.0f/float(n*n);
float wv = (n-2.0f) * n * wp;
float *dstVertex = fVertex + (i+offset)*numVertexElements;
clear(dstVertex, 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 n = V0_ITa[5*i+1];
int p = V0_ITa[5*i+2];
float weight = V0_S[i];
float wp = 1.0f/float(n);
float beta = 0.25f * __cosf(float(M_PI) * 2.0f * wp) + 0.375f;
beta = beta * beta;
beta = (0.625f - beta) * wp;
DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst;
dst.clear();
dst.addWithWeight(&vertex[p], weight * (1.0f - (beta * n)));
for(int j = 0; j < n; ++j){
dst.addWithWeight(&vertex[V0_IT[h+j]], weight * beta);
}
vertex[i+offset] = dst;
vertex[i+offset] = dst;
if(NUM_VARYING_ELEMENTS > 0){
DeviceVarying<NUM_VARYING_ELEMENTS> dstVarying;
@ -468,13 +468,13 @@ computeLoopVertexB(float *fVertex, int numVertexElements, float *fVaryings, int
int h = V0_ITa[5*i];
int n = V0_ITa[5*i+1];
int p = V0_ITa[5*i+2];
float weight = V0_S[i];
float wp = 1.0f/float(n);
float beta = 0.25f * __cosf(float(M_PI) * 2.0f * wp) + 0.375f;
beta = beta * beta;
beta = (0.625f - beta) * wp;
float *dstVertex = fVertex + (i+offset)*numVertexElements;
clear(dstVertex, 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
@ -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){
int eidx0 = E0_IT[2*i+0];
int eidx1 = E0_IT[2*i+1];
DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst;
dst.clear();
dst.addWithWeight(&vertex[eidx0], 0.5f);
dst.addWithWeight(&vertex[eidx1], 0.5f);
vertex[offset+i] = dst;
if(NUM_VARYING_ELEMENTS > 0){
@ -521,19 +521,19 @@ computeBilinearEdge(float *fVertex, float *fVaryings, int *E0_IT, int offset, in
}
__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)
{
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 eidx1 = E0_IT[2*i+1];
float *dstVertex = fVertex + (i+offset)*numVertexElements;
clear(dstVertex, numVertexElements);
addWithWeight(dstVertex, fVertex + eidx0*numVertexElements, 0.5f, numVertexElements);
addWithWeight(dstVertex, fVertex + eidx1*numVertexElements, 0.5f, numVertexElements);
if(numVaryingElements > 0){
float *dstVarying = fVarying + i*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;
for(int i = start + threadIdx.x + blockIdx.x*blockDim.x; i < end; i += blockDim.x * gridDim.x){
int p = V0_ITa[i];
DeviceVertex<NUM_USER_VERTEX_ELEMENTS> dst;
dst.clear();
dst.addWithWeight(&vertex[p], 1.0f);
vertex[i+offset] = dst;
vertex[i+offset] = dst;
if(NUM_VARYING_ELEMENTS > 0){
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){
int p = V0_ITa[i];
float *dstVertex = fVertex + (i+offset)*numVertexElements;
clear(dstVertex, 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"
// 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..
#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);
}
void OsdCudaComputeVertexA(float *vertex, float *varying,
void OsdCudaComputeVertexA(float *vertex, float *varying,
int numUserVertexElements, int numVaryingElements,
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);
}
void OsdCudaComputeBilinearVertex(float *vertex, float *varying,
void OsdCudaComputeBilinearVertex(float *vertex, float *varying,
int numUserVertexElements, int numVaryingElements,
int *V_ITa, int offset, int start, int end)
{
@ -702,4 +715,11 @@ void OsdCudaComputeBilinearVertex(float *vertex, float *varying,
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__)
#include <GL/glew.h>
#else
#include <OpenGL/gl.h>
#include <OpenGL/gl3.h>
#endif
#include "../osd/glslDispatcher.h"
@ -97,7 +97,7 @@ static const char *shaderDefines = ""
;
std::vector<OsdGlslKernelDispatcher::ComputeShader> OsdGlslKernelDispatcher::shaderRegistry;
OsdGlslKernelDispatcher::OsdGlslKernelDispatcher(int levels)
: OsdKernelDispatcher(levels)
{
@ -200,7 +200,7 @@ OsdGlslKernelDispatcher::BindVertexBuffer(OsdVertexBuffer *vertex, OsdVertexBuff
if (vertex)
_currentVertexBuffer = dynamic_cast<OsdGpuVertexBuffer *>(vertex);
else
else
_currentVertexBuffer = NULL;
if (varying)
@ -310,7 +310,7 @@ OsdGlslKernelDispatcher::ApplyBilinearFaceVerticesKernel(
void
OsdGlslKernelDispatcher::ApplyBilinearEdgeVerticesKernel(
FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
_shader->ApplyBilinearEdgeVerticesKernel(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[E_IT][level-1],
offset, start, end);
@ -319,7 +319,7 @@ OsdGlslKernelDispatcher::ApplyBilinearEdgeVerticesKernel(
void
OsdGlslKernelDispatcher::ApplyBilinearVertexVerticesKernel(
FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
_shader->ApplyBilinearVertexVerticesKernel(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[V_ITa][level-1],
offset, start, end);
@ -341,7 +341,7 @@ OsdGlslKernelDispatcher::ApplyCatmarkFaceVerticesKernel(
void
OsdGlslKernelDispatcher::ApplyCatmarkEdgeVerticesKernel(
FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
_shader->ApplyCatmarkEdgeVerticesKernel(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[E_IT][level-1],
_tableOffsets[E_W][level-1],
@ -351,7 +351,7 @@ OsdGlslKernelDispatcher::ApplyCatmarkEdgeVerticesKernel(
void
OsdGlslKernelDispatcher::ApplyCatmarkVertexVerticesKernelB(
FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
_shader->ApplyCatmarkVertexVerticesKernelB(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[V_IT][level-1],
_tableOffsets[V_ITa][level-1],
@ -362,7 +362,7 @@ OsdGlslKernelDispatcher::ApplyCatmarkVertexVerticesKernelB(
void
OsdGlslKernelDispatcher::ApplyCatmarkVertexVerticesKernelA(
FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const {
_shader->ApplyCatmarkVertexVerticesKernelA(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[V_ITa][level-1],
_tableOffsets[V_W][level-1],
@ -374,7 +374,7 @@ OsdGlslKernelDispatcher::ApplyCatmarkVertexVerticesKernelA(
void
OsdGlslKernelDispatcher::ApplyLoopEdgeVerticesKernel(
FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
_shader->ApplyLoopEdgeVerticesKernel(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[E_IT][level-1],
_tableOffsets[E_W][level-1],
@ -384,7 +384,7 @@ OsdGlslKernelDispatcher::ApplyLoopEdgeVerticesKernel(
void
OsdGlslKernelDispatcher::ApplyLoopVertexVerticesKernelB(
FarMesh<OsdVertex> * mesh, int offset, int level, int start, int end, void * data) const {
_shader->ApplyLoopVertexVerticesKernelB(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[V_IT][level-1],
_tableOffsets[V_ITa][level-1],
@ -395,7 +395,7 @@ OsdGlslKernelDispatcher::ApplyLoopVertexVerticesKernelB(
void
OsdGlslKernelDispatcher::ApplyLoopVertexVerticesKernelA(
FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const {
_shader->ApplyLoopVertexVerticesKernelA(_currentVertexBuffer, _currentVaryingBuffer,
_tableOffsets[V_ITa][level-1],
_tableOffsets[V_W][level-1],
@ -411,7 +411,7 @@ OsdGlslKernelDispatcher::ComputeShader::ComputeShader() :
OsdGlslKernelDispatcher::ComputeShader::~ComputeShader()
{
if (_program)
if (_program)
glDeleteProgram(_program);
}
@ -439,10 +439,10 @@ OsdGlslKernelDispatcher::ComputeShader::Compile(int numVertexElements, int numVa
glCompileShader(shader);
glAttachShader(_program, shader);
const char *outputs[] = { "outPosition",
"outNormal",
"gl_NextBuffer",
"outVaryingData" };
const char *outputs[] = { "outPosition",
"outNormal",
"gl_NextBuffer",
"outVaryingData" };
int nOutputs = numVaryingElements > 0 ? 4 : 2;
@ -463,7 +463,7 @@ OsdGlslKernelDispatcher::ComputeShader::Compile(int numVertexElements, int numVa
glGetProgramInfoLog(_program, 1024, NULL, buffer);
OSD_ERROR(buffer);
glDeleteProgram(_program);
_program = 0;
// XXX ERROR HANDLE
@ -539,7 +539,7 @@ OsdGlslKernelDispatcher::ComputeShader::transformGpuBufferData(OsdGpuVertexBuffe
glBeginTransformFeedback(GL_POINTS);
CHECK_GL_ERROR("transformGpuBufferData glBeginTransformFeedback\n");
// draw array -----------------------------------------
glDrawArrays(GL_POINTS, 0, count);
CHECK_GL_ERROR("transformGpuBufferData DrawArray (%d)\n", count);
@ -578,7 +578,7 @@ void
OsdGlslKernelDispatcher::ComputeShader::ApplyBilinearVertexVerticesKernel(
OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
int V_ITa_ofs, int offset, int start, int end) {
glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeVertex);
glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs);
transformGpuBufferData(vertex, varying, offset, start, end);
@ -611,7 +611,7 @@ void
OsdGlslKernelDispatcher::ComputeShader::ApplyCatmarkVertexVerticesKernelB(
OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
int V_IT_ofs, int V_ITa_ofs, int V_W_ofs, int offset, int start, int end) {
glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeCatmarkVertexB);
glUniform1i(_tableOffsetUniforms[V_IT], V_IT_ofs);
glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs);
@ -623,7 +623,7 @@ void
OsdGlslKernelDispatcher::ComputeShader::ApplyCatmarkVertexVerticesKernelA(
OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
int V_ITa_ofs, int V_W_ofs, int offset, bool pass, int start, int end) {
glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeVertexA);
glUniform1i(_uniformVertexPass, pass ? 1 : 0);
glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs);
@ -635,7 +635,7 @@ void
OsdGlslKernelDispatcher::ComputeShader::ApplyLoopEdgeVerticesKernel(
OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
int E_IT_ofs, int E_W_ofs, int offset, int start, int end) {
glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeEdge);
glUniform1i(_tableOffsetUniforms[E_IT], E_IT_ofs);
glUniform1i(_tableOffsetUniforms[E_W], E_W_ofs);
@ -646,7 +646,7 @@ void
OsdGlslKernelDispatcher::ComputeShader::ApplyLoopVertexVerticesKernelB(
OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
int V_IT_ofs, int V_ITa_ofs, int V_W_ofs, int offset, int start, int end) {
glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeLoopVertexB);
glUniform1i(_tableOffsetUniforms[V_IT], V_IT_ofs);
glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs);
@ -658,7 +658,7 @@ void
OsdGlslKernelDispatcher::ComputeShader::ApplyLoopVertexVerticesKernelA(
OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
int V_ITa_ofs, int V_W_ofs, int offset, bool pass, int start, int end) {
glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subComputeVertexA);
glUniform1i(_uniformVertexPass, pass ? 1 : 0);
glUniform1i(_tableOffsetUniforms[V_ITa], V_ITa_ofs);

View File

@ -60,7 +60,7 @@
#if not defined(__APPLE__)
#include <GL/gl.h>
#else
#include <OpenGL/gl.h>
#include <OpenGL/gl3.h>
#endif
#include "../version.h"
@ -73,34 +73,41 @@ class OsdGlslKernelDispatcher : public OsdKernelDispatcher {
public:
OsdGlslKernelDispatcher(int levels);
virtual ~OsdGlslKernelDispatcher();
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 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 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 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 ApplyVertexEdit(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const {}
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 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 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 ApplyLoopVertexVerticesKernelA(OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying, int V_ITa_ofs, int V_W_ofs, int offset, bool pass, int start, int end);
void UseProgram () const;
struct Match {
Match(int numVertexElements, int numVaryingElements) :
_numVertexElements(numVertexElements), _numVaryingElements(numVaryingElements) { }
bool operator() (ComputeShader const & shader) {
return (shader._numVertexElements == _numVertexElements
&& shader._numVaryingElements == _numVaryingElements);
}
int _numVertexElements,
int _numVertexElements,
_numVaryingElements;
};
friend struct Match;
private:
void transformGpuBufferData(OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
void transformGpuBufferData(OsdGpuVertexBuffer *vertex, OsdGpuVertexBuffer *varying,
GLint offset, int start, int end) const;
int _numVertexElements;
@ -191,10 +198,10 @@ protected:
GLuint _uniformVertexPass;
GLuint _uniformIndexStart;
GLuint _uniformIndexOffset;
GLuint _vertexUniform,
_varyingUniform;
// shader locations
GLuint _subComputeFace, // general face-vertex kernel (all schemes)
_subComputeEdge, // edge-vertex kernel (catmark + loop schemes)
@ -216,9 +223,9 @@ protected:
ComputeShader * _shader;
// texture for vertex
GLuint _vertexTexture,
GLuint _vertexTexture,
_varyingTexture;
OsdGpuVertexBuffer *_currentVertexBuffer,
*_currentVaryingBuffer;

View File

@ -68,8 +68,8 @@ uniform samplerBuffer _E0_S;
uniform samplerBuffer _V0_S;
uniform bool vertexPass;
uniform int indexOffset = 0; // index offset for the level
uniform int indexStart = 0; // start index for given batch
uniform int indexOffset = 0; // index offset for the level
uniform int indexStart = 0; // start index for given batch
uniform int F_IT_ofs;
uniform int F_ITa_ofs;
@ -83,8 +83,8 @@ uniform int V_W_ofs;
+-----+---------------------------------+-----
n-1 | Level n |<batch range>| | n+1
+-----+---------------------------------+-----
^ ^
indexOffset |
^ ^
indexOffset |
indexStart
*/
@ -107,9 +107,9 @@ uniform samplerBuffer varyingData; // float[NUM_VARYING]
out vec3 outPosition;
out vec3 outNormal;
#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
//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)
{
@ -221,7 +221,7 @@ void catmarkComputeEdge()
#ifdef OPT_E0_S_VEC2
float faceWeight = weight.y;
#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
addWithWeight(dst, readVertex(eidx.z), faceWeight);
@ -292,8 +292,8 @@ void catmarkComputeVertexA()
? 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
// the value is shared with the k_Smooth kernel (statistically the
// In the case of fractional weight, the weight must be inverted since
// the value is shared with the k_Smooth kernel (statistically the
// k_Smooth kernel runs much more often than this one)
if (weight>0.0 && weight<1.0 && n > 0)
weight=1.0-weight;
@ -336,7 +336,7 @@ void catmarkComputeVertexB()
Vertex dst;
clear(dst);
addWithWeight(dst, readVertex(p), weight * wv);
for(int j = 0; j < n; ++j){
@ -372,7 +372,7 @@ void loopComputeVertexB()
Vertex dst;
clear(dst);
addWithWeight(dst, readVertex(p), weight * (1.0-(beta*n)));
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 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 OnKernelFinish() = 0;
virtual OsdVertexBuffer *InitializeVertexBuffer(int numElements, int count) = 0;
@ -101,12 +106,12 @@ public:
virtual void Synchronize() = 0;
template<class T> void UpdateTable(int tableIndex, const T & table) {
CopyTable(tableIndex, table.GetMemoryUsed(), table[0]);
_tableOffsets[tableIndex].resize(_maxLevel);
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 ) {
@ -123,7 +128,7 @@ public:
enum { E_IT,
E_W,
V_ITa,
V_ITa,
V_IT,
V_W,
F_IT,
@ -165,7 +170,7 @@ protected:
static Factory &GetInstance() {
return _instance;
}
static Factory _instance;
protected:
@ -187,6 +192,16 @@ protected:
protected:
int _maxLevel;
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

View File

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

View File

@ -54,6 +54,13 @@
// exclude the implied warranties of merchantability, fitness for
// a particular purpose and non-infringement.
//
#if not defined(__APPLE__)
#include <GL/glew.h>
#else
#include <OpenGL/gl3.h>
#endif
#include <string.h>
#include "../version.h"
@ -67,15 +74,21 @@
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
OsdMesh::OsdMesh() : _fMesh(NULL), _dispatcher(NULL) { }
OsdMesh::OsdMesh() : _farMesh(NULL), _dispatcher(NULL) { }
OsdMesh::~OsdMesh() {
if(_dispatcher)
if(_dispatcher)
delete _dispatcher;
if(_fMesh)
delete _fMesh;
if(_farMesh)
delete _farMesh;
// delete ptex coordinates
for (int i=0; i<(int)_ptexCoordinates.size(); ++i) {
if (glIsTexture(_ptexCoordinates[i]))
glDeleteTextures(1,&_ptexCoordinates[i]);
}
}
void
@ -87,12 +100,12 @@ OsdMesh::createTables( FarSubdivisionTables<OsdVertex> const * tables ) {
_dispatcher->UpdateTable(OsdKernelDispatcher::E_W, tables->Get_E_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) ) {
// catmark
_dispatcher->UpdateTable(OsdKernelDispatcher::F_IT, cctable->Get_F_IT());
_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) ) {
// bilinear
_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_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
@ -119,31 +144,60 @@ OsdMesh::Create(OsdHbrMesh *hbrMesh, int level, int kernel, std::vector<int> * r
}
_level = level;
// create Far mesh
OSD_DEBUG("Create MeshFactory\n");
FarMeshFactory<OsdVertex> meshFactory(hbrMesh, _level);
_fMesh = meshFactory.Create(_dispatcher);
OSD_DEBUG("PREP: NumCoarseVertex = %d\n", _fMesh->GetNumCoarseVertices());
OSD_DEBUG("PREP: NumVertex = %d\n", _fMesh->GetNumVertices());
_farMesh = meshFactory.Create(_dispatcher);
OSD_DEBUG("PREP: NumCoarseVertex = %d\n", _farMesh->GetNumCoarseVertices());
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
// Osd to Hbr for comparison / regression purposes.
if (remap)
(*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;
}
OsdVertexBuffer *
OsdMesh::InitializeVertexBuffer(int numElements)
{
if (!_dispatcher) return NULL;
OsdMesh::InitializeVertexBuffer(int numElements) {
if (!_dispatcher)
return NULL;
return _dispatcher->InitializeVertexBuffer(numElements, GetTotalVertices());
}
@ -154,7 +208,7 @@ OsdMesh::Subdivide(OsdVertexBuffer *vertex, OsdVertexBuffer *varying) {
_dispatcher->OnKernelLaunch();
_fMesh->Subdivide(_level+1);
_farMesh->Subdivide(_level+1);
_dispatcher->OnKernelFinish();

View File

@ -83,6 +83,8 @@ typedef HbrVertex<OsdVertex> OsdHbrVertex;
typedef HbrHalfedge<OsdVertex> OsdHbrHalfedge;
typedef HbrFace<OsdVertex> OsdHbrFace;
class OsdPtexIndicesBuffer;
class OsdMesh {
public:
@ -90,16 +92,18 @@ public:
virtual ~OsdMesh();
// Given a valid HbrMesh, create an OsdMesh
// - cappable of densely refining up to 'level'
// Given a valid HbrMesh, create an OsdMesh
// - capable of densely refining up to 'level'
// - 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)
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
void Subdivide(OsdVertexBuffer *vertex, OsdVertexBuffer *varying = NULL);
@ -111,19 +115,28 @@ public:
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:
void createTables( FarSubdivisionTables<OsdVertex> const * tables );
FarMesh<OsdVertex> *_fMesh;
void createEditTables( FarVertexEditTables<OsdVertex> const * editTables );
FarMesh<OsdVertex> *_farMesh;
int _level;
OsdKernelDispatcher * _dispatcher;
std::vector<GLuint> _ptexCoordinates; // index of the coarse parent face + sub-face coordinates (cf. far)
};
} // 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
#define GSD_VERTEX_H
#ifndef OSD_VERTEX_H
#define OSD_VERTEX_H
#include "../version.h"
#include "../hbr/face.h"
#include "../hbr/vertexEdit.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
@ -13,8 +15,10 @@ public:
OsdVertex(const OsdVertex &src) {}
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 ApplyVertexEdit(const OpenSubdiv::HbrVertexEdit<OsdVertex> &) { }
void ApplyMovingVertexEdit(const OpenSubdiv::HbrMovingVertexEdit<OsdVertex> &) { }
};
} // end namespace OPENSUBDIV_VERSION
@ -22,4 +26,4 @@ using namespace OPENSUBDIV_VERSION;
} // 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"
#if not defined(__APPLE__)
#include <GL/glew.h>
#else
#include <OpenGL/gl.h>
#include <OpenGL/gl3.h>
#endif
#include "vertexBuffer.h"
#include "../osd/vertexBuffer.h"
#include <iostream>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
OsdVertexBuffer::~OsdVertexBuffer()
{
OsdVertexBuffer::~OsdVertexBuffer() {
}
OsdGpuVertexBuffer::OsdGpuVertexBuffer(int numElements, int numVertices) :
@ -28,21 +83,30 @@ OsdGpuVertexBuffer::OsdGpuVertexBuffer(int numElements, int numVertices) :
}
void
OsdGpuVertexBuffer::UpdateData(const float *src, int numVertices)
{
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
OsdGpuVertexBuffer::UpdateData(const float *src, int numVertices) {
glBindBuffer(GL_ARRAY_BUFFER, GetGpuBuffer());
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);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
OsdGpuVertexBuffer::~OsdGpuVertexBuffer()
{
glDeleteBuffers(1, &_vbo);
void
OsdGpuVertexBuffer::GetBufferData(float * data, int firstVert, int numVerts) {
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) :
OsdVertexBuffer(numElements), _cpuVbo(NULL), _vboSize(0), _vbo(0)
@ -51,27 +115,29 @@ OsdCpuVertexBuffer::OsdCpuVertexBuffer(int numElements, int numVertices) :
_cpuVbo = new float[numElements * numVertices];
}
OsdCpuVertexBuffer::~OsdCpuVertexBuffer()
{
OsdCpuVertexBuffer::~OsdCpuVertexBuffer() {
delete [] _cpuVbo;
if (_vbo)
glDeleteBuffers(1, &_vbo);
}
void
OsdCpuVertexBuffer::UpdateData(const float *src, int numVertices)
{
OsdCpuVertexBuffer::UpdateData(const float *src, int numVertices) {
memcpy(_cpuVbo, src, _numElements * numVertices * sizeof(float));
}
GLuint
OsdCpuVertexBuffer::GetGpuBuffer()
{
OsdCpuVertexBuffer::GetGpuBuffer() {
if (!_vbo)
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, _vboSize * sizeof(float), _cpuVbo, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
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
#define OSD_VERTEX_BUFFER_H
@ -7,7 +63,7 @@
#endif
#include <GL/gl.h>
#else
#include <OpenGL/gl.h>
#include <OpenGL/gl3.h>
#endif
#include <string.h> // memcpy (tobe moved to cpp)
@ -44,6 +100,10 @@ public:
return _vbo;
}
// Copies the vertex data from the compute device into
// the pointer.
void GetBufferData(float * data, int firstVert, int numVerts);
protected:
GLuint _vbo;
};
@ -51,7 +111,7 @@ protected:
class OsdCpuVertexBuffer : public OsdVertexBuffer {
public:
OsdCpuVertexBuffer(int numElements, int numVertices);
virtual ~OsdCpuVertexBuffer();
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) {
// escape double quotes
if (line[i]=='"') {
if (line[i]=='"') {
s << '\\' ;
inconstant = inconstant ? false : true;
}
// escape backslash
if (inconstant and line[i]=='\\')
s << '\\' ;

View File

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

View File

@ -57,4 +57,28 @@
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
#define SHAPE_UTILS_H
#include <hbr/vertexEdit.h>
#include <hbr/cornerEdit.h>
#include <stdio.h>
#include <string.h>
@ -64,14 +67,14 @@
#include <string>
#include <vector>
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
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') {
memcpy(s, *stream, i);
s[i]='\0';
if ((*stream)[i]=='\0')
return 0;
else {
@ -83,57 +86,57 @@ static char const * sgets( char * s, int size, char ** stream ) {
return 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
struct shape {
struct tag {
static tag * parseTag( char const * stream );
std::string name;
std::string name;
std::vector<int> intargs;
std::vector<float> floatargs;
std::vector<std::string> stringargs;
};
static shape * parseShape(char const * shapestr, int axis=1);
~shape();
int getNverts() const { return (int)verts.size()/3; }
int getNfaces() const { return (int)nvertsPerFace.size(); }
std::vector<float> verts;
std::vector<float> uvs;
std::vector<int> nvertsPerFace;
std::vector<int> faceverts;
std::vector<int> nvertsPerFace;
std::vector<int> faceverts;
std::vector<int> faceuvs;
std::vector<tag *> tags;
};
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
shape::~shape() {
for (int i=0; i<(int)tags.size(); ++i)
delete tags[i];
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
shape::tag * shape::tag::parseTag(char const * line) {
tag * t = 0;
const char* cp = &line[2];
const char* cp = &line[2];
char name[50];
while (*cp == ' ') cp++;
if (sscanf(cp, "%s", &name )!=1) return t;
while (*cp && *cp != ' ') cp++;
if (sscanf(cp, "%s", name )!=1) return t;
while (*cp && *cp != ' ') cp++;
int nints=0, nfloats=0, nstrings=0;
while (*cp == ' ') cp++;
if (sscanf(cp, "%d/%d/%d", &nints, &nfloats, &nstrings)!=3) return t;
while (*cp && *cp != ' ') cp++;
while (*cp && *cp != ' ') cp++;
std::vector<int> intargs;
for (int i=0; i<nints; ++i) {
@ -141,7 +144,7 @@ shape::tag * shape::tag::parseTag(char const * line) {
while (*cp == ' ') cp++;
if (sscanf(cp, "%d", &val)!=1) return t;
intargs.push_back(val);
while (*cp && *cp != ' ') cp++;
while (*cp && *cp != ' ') cp++;
}
std::vector<float> floatargs;
@ -150,16 +153,16 @@ shape::tag * shape::tag::parseTag(char const * line) {
while (*cp == ' ') cp++;
if (sscanf(cp, "%f", &val)!=1) return t;
floatargs.push_back(val);
while (*cp && *cp != ' ') cp++;
while (*cp && *cp != ' ') cp++;
}
std::vector<std::string> stringargs;
for (int i=0; i<nstrings; ++i) {
char * val;
char val[512];
while (*cp == ' ') cp++;
if (sscanf(cp, "%s", &val)!=1) return t;
if (sscanf(cp, "%s", val)!=1) return t;
stringargs.push_back(val);
while (*cp && *cp != ' ') cp++;
while (*cp && *cp != ' ') cp++;
}
t = new shape::tag;
@ -167,53 +170,53 @@ shape::tag * shape::tag::parseTag(char const * line) {
t->intargs = intargs;
t->floatargs = floatargs;
t->stringargs = stringargs;
return t;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
shape * shape::parseShape(char const * shapestr, int axis ) {
shape * s = new shape;
char * str=const_cast<char *>(shapestr), line[256];
bool done = false;
while( not done )
while( not done )
{ done = sgets(line, sizeof(line), &str)==0;
char* end = &line[strlen(line)-1];
if (*end == '\n') *end = '\0'; // strip trailing nl
float x, y, z, u, v;
switch (line[0]) {
case 'v': switch (line[1])
{ case ' ': if(sscanf(line, "v %f %f %f", &x, &y, &z) == 3)
s->verts.push_back(x);
switch( axis ) {
case 0 : s->verts.push_back(-z);
char* end = &line[strlen(line)-1];
if (*end == '\n') *end = '\0'; // strip trailing nl
float x, y, z, u, v;
switch (line[0]) {
case 'v': switch (line[1])
{ case ' ': if(sscanf(line, "v %f %f %f", &x, &y, &z) == 3)
s->verts.push_back(x);
switch( axis ) {
case 0 : s->verts.push_back(-z);
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;
} break;
case 't': if(sscanf(line, "vt %f %f", &u, &v) == 2) {
s->uvs.push_back(u);
s->uvs.push_back(v);
} break;
case 't': if(sscanf(line, "vt %f %f", &u, &v) == 2) {
s->uvs.push_back(u);
s->uvs.push_back(v);
} break;
case 'n' : break; // skip normals for now
}
break;
case 'f': if(line[1] == ' ') {
int vi, ti, ni;
const char* cp = &line[2];
while (*cp == ' ') cp++;
int nverts = 0, nitems=0;
while( (nitems=sscanf(cp, "%d/%d/%d", &vi, &ti, &ni))>0) {
nverts++;
s->faceverts.push_back(vi-1);
if(nitems >= 1) s->faceuvs.push_back(ti-1);
while (*cp && *cp != ' ') cp++;
while (*cp == ' ') cp++;
}
s->nvertsPerFace.push_back(nverts);
int vi, ti, ni;
const char* cp = &line[2];
while (*cp == ' ') cp++;
int nverts = 0, nitems=0;
while( (nitems=sscanf(cp, "%d/%d/%d", &vi, &ti, &ni))>0) {
nverts++;
s->faceverts.push_back(vi-1);
if(nitems >= 1) s->faceuvs.push_back(ti-1);
while (*cp && *cp != ' ') cp++;
while (*cp == ' ') cp++;
}
s->nvertsPerFace.push_back(nverts);
}
break;
case 't' : if(line[1] == ' ') {
@ -226,19 +229,19 @@ shape * shape::parseShape(char const * shapestr, int axis ) {
return s;
}
//------------------------------------------------------------------------------
template <class T>
//------------------------------------------------------------------------------
template <class T>
void applyTags( OpenSubdiv::HbrMesh<T> * mesh, shape const * sh ) {
for (int i=0; i<(int)sh->tags.size(); ++i) {
shape::tag * t = sh->tags[i];
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] ),
* w = mesh->GetVertex( t->intargs[j+1] );
OpenSubdiv::HbrHalfedge<T> * e = 0;
if( v && w ) {
if( v && w ) {
if( !(e = v->GetEdge(w) ) )
e = w->GetEdge(v);
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);
continue;
}
switch( t->intargs[0] ) {
switch( t->intargs[0] ) {
case 0 : mesh->SetInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryNone); break;
case 1 : mesh->SetInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryEdgeAndCorner); 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
printf( "expecting single int argument for \"facevaryingpropagatecorners\"\n" );
} else if (t->name=="creasemethod") {
OpenSubdiv::HbrCatmarkSubdivision<T> * scheme =
OpenSubdiv::HbrCatmarkSubdivision<T> * scheme =
dynamic_cast<OpenSubdiv::HbrCatmarkSubdivision<T> *>( mesh->GetSubdivision() );
if (not scheme) {
printf("the \"creasemethod\" tag can only be applied to Catmark meshes\n");
continue;
}
if ((int)t->stringargs.size()==0) {
printf("the \"creasemethod\" tag expects a string argument\n");
continue;
}
if( t->stringargs[0]=="normal" )
scheme->SetTriangleSubdivisionMethod(
OpenSubdiv::HbrCatmarkSubdivision<T>::k_Old);
@ -304,12 +307,140 @@ void applyTags( OpenSubdiv::HbrMesh<T> * mesh, shape const * sh ) {
OpenSubdiv::HbrCatmarkSubdivision<T>::k_New);
else
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") {
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 {
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) {
OpenSubdiv::HbrMesh<T> * mesh = 0;
static OpenSubdiv::HbrBilinearSubdivision<T> _bilinear;
static OpenSubdiv::HbrLoopSubdivision<T> _loop;
static OpenSubdiv::HbrCatmarkSubdivision<T> _catmark;
switch (scheme) {
case kBilinear : mesh = new OpenSubdiv::HbrMesh<T>( &_bilinear ); break;
case kLoop : mesh = new OpenSubdiv::HbrMesh<T>( &_loop ); break;
case kCatmark : mesh = new OpenSubdiv::HbrMesh<T>( &_catmark ); break;
}
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] );
mesh->NewVertex( i, v );
}
if (verts)
*verts = sh->verts;
}
@ -370,37 +501,37 @@ createTopology( shape const * sh, OpenSubdiv::HbrMesh<T> * mesh, Scheme scheme)
const int * fv=&(sh->faceverts[0]);
for(int f=0, ptxidx=0;f<sh->getNfaces(); f++ ) {
int nv = sh->nvertsPerFace[f];
if ((scheme==kLoop) and (nv!=3)) {
printf("Trying to create a Loop surbd with non-triangle face\n");
exit(1);
printf("Trying to create a Loop surbd with non-triangle face\n");
exit(1);
}
for(int j=0;j<nv;j++) {
OpenSubdiv::HbrVertex<T> * origin = mesh->GetVertex( fv[j] );
for(int j=0;j<nv;j++) {
OpenSubdiv::HbrVertex<T> * origin = mesh->GetVertex( fv[j] );
OpenSubdiv::HbrVertex<T> * destination = mesh->GetVertex( fv[ (j+1)%nv] );
OpenSubdiv::HbrHalfedge<T> * opposite = destination->GetEdge(origin);
if(origin==NULL || destination==NULL) {
printf(" An edge was specified that connected a nonexistent vertex\n");
exit(1);
if(origin==NULL || destination==NULL) {
printf(" An edge was specified that connected a nonexistent vertex\n");
exit(1);
}
if(origin == destination) {
printf(" An edge was specified that connected a vertex to itself\n");
exit(1);
if(origin == destination) {
printf(" An edge was specified that connected a vertex to itself\n");
exit(1);
}
if(opposite && opposite->GetOpposite() ) {
printf(" A non-manifold edge incident to more than 2 faces was found\n");
exit(1);
if(opposite && opposite->GetOpposite() ) {
printf(" A non-manifold edge incident to more than 2 faces was found\n");
exit(1);
}
if(origin->GetEdge(destination)) {
if(origin->GetEdge(destination)) {
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);
}
}
@ -431,13 +562,13 @@ simpleHbr(char const * shapestr, Scheme scheme, std::vector<float> * verts=0) {
shape * sh = shape::parseShape( shapestr );
OpenSubdiv::HbrMesh<T> * mesh = createMesh<T>(scheme);
createVertices<T>(sh, mesh, verts);
createTopology<T>(sh, mesh, scheme);
delete sh;
return mesh;
}
@ -448,13 +579,13 @@ simpleHbr(char const * shapestr, Scheme scheme, std::vector<float> & verts) {
shape * sh = shape::parseShape( shapestr );
OpenSubdiv::HbrMesh<T> * mesh = createMesh<T>(scheme);
createVertices<T>(sh, mesh, verts);
createTopology<T>(sh, mesh, scheme);
delete sh;
return mesh;
}

View File

@ -55,18 +55,6 @@
# 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(
${ILMBASE_INCLUDE_DIR}
${PROJECT_SOURCE_DIR}/opensubdiv
@ -82,6 +70,6 @@ add_executable(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
//
// - 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.
//
@ -96,17 +96,38 @@ struct xyzVV {
void AddVaryingWithWeight(const xyzVV& , float, void * =0 ) { }
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 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; }
private:
private:
Imath::Vec3<float> _pos;
};
//------------------------------------------------------------------------------
class xyzFV;
typedef OpenSubdiv::HbrMesh<xyzVV> xyzmesh;
typedef OpenSubdiv::HbrFace<xyzVV> xyzface;
typedef OpenSubdiv::HbrVertex<xyzVV> xyzvertex;
typedef OpenSubdiv::HbrFace<xyzVV> xyzface;
typedef OpenSubdiv::HbrVertex<xyzVV> xyzvertex;
typedef OpenSubdiv::HbrHalfedge<xyzVV> xyzhalfedge;
typedef OpenSubdiv::HbrFaceOperator<xyzVV> xyzFaceOperator;
typedef OpenSubdiv::HbrVertexOperator<xyzVV> xyzVertexOperator;
@ -119,9 +140,9 @@ static bool g_debugmode = 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
// 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]] }, ... ]
//------------------------------------------------------------------------------
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");
}
printf("],\n");
printf("],\n");
}
//------------------------------------------------------------------------------
@ -157,21 +178,21 @@ static void dumpFaces( xyzmesh * mesh, int level ) {
continue;
if (f->GetDepth()==level) {
if (f->GetNumVertices()==4)
printf("[%6d, %6d, %6d, %6d], ", f->GetVertex(0)->GetID()-vertofs,
f->GetVertex(1)->GetID()-vertofs,
printf("[%6d, %6d, %6d, %6d], ", f->GetVertex(0)->GetID()-vertofs,
f->GetVertex(1)->GetID()-vertofs,
f->GetVertex(2)->GetID()-vertofs,
f->GetVertex(3)->GetID()-vertofs );
else if (f->GetNumVertices()==3)
printf("[%6d, %6d, %6d], ", f->GetVertex(0)->GetID()-vertofs,
f->GetVertex(1)->GetID()-vertofs,
printf("[%6d, %6d, %6d], ", f->GetVertex(0)->GetID()-vertofs,
f->GetVertex(1)->GetID()-vertofs,
f->GetVertex(2)->GetID()-vertofs );
++counter;
if (counter!=0 and (counter+4)%32==0)
if (counter!=0 and (counter+4)%32==0)
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],
verts[i].GetPos()[1],
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");
printf("],\n");
}
//------------------------------------------------------------------------------
@ -209,14 +230,14 @@ static void dumpQuadFaces( fMesh * mesh, int level ) {
printf("\t'faces':[\t");
for (size_t i=0; i<(fverts.size()); i+=4) {
printf("[%6d, %6d, %6d, %6d], ", fverts[i ]-ofs,
fverts[i+1]-ofs,
fverts[i+2]-ofs,
printf("[%6d, %6d, %6d, %6d], ", fverts[i ]-ofs,
fverts[i+1]-ofs,
fverts[i+2]-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");
printf("]\n");
}
//------------------------------------------------------------------------------
@ -228,10 +249,10 @@ static void dumpTriFaces( fMesh * mesh, int level ) {
printf("\t'faces':[\t");
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 );
if (i!=0 and (i+4)%32==0)
if (i!=0 and (i+4)%32==0)
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
bool VertexOnBoundary( xyzvertex const * v ) {
if (not v)
if (not v)
return false;
if (v->OnBoundary())
return true;
xyzvertex const * pv = v->GetParentVertex();
if (pv)
return VertexOnBoundary(pv);
else {
xyzhalfedge const * pe = v->GetParentEdge();
if (pe) {
return VertexOnBoundary(pe->GetOrgVertex()) or
return VertexOnBoundary(pe->GetOrgVertex()) or
VertexOnBoundary(pe->GetDestVertex());
} else {
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);
int count=0;
Imath::Vec3<float> deltaAvg(0.0, 0.0, 0.0);
int count=0;
Imath::Vec3<float> deltaAvg(0.0, 0.0, 0.0);
Imath::Vec3<float> deltaCnt(0, 0, 0);
// 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)
if (g_dumphbr)
dumpXYZMesh( hmesh, i, scheme );
else
else
dumpMesh( m, i, scheme );
} else
printf("- %s (scheme=%d)\n", msg, scheme);
std::vector<int> const & remap = fact.GetRemappingTable();
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
VertexOnBoundary(hv) )
continue;
if ( hv->GetData().GetPos()[0] != nv.GetPos()[0] )
if ( hv->GetData().GetPos()[0] != nv.GetPos()[0] )
deltaCnt[0]++;
if ( hv->GetData().GetPos()[1] != nv.GetPos()[1] )
if ( hv->GetData().GetPos()[1] != nv.GetPos()[1] )
deltaCnt[1]++;
if ( hv->GetData().GetPos()[2] != nv.GetPos()[2] )
if ( hv->GetData().GetPos()[2] != nv.GetPos()[2] )
deltaCnt[2]++;
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()[1],
nv.GetPos()[2] );
count++;
count++;
}
}
if (deltaCnt[0])
deltaAvg[0]/=deltaCnt[0];
if (deltaCnt[1])
@ -353,20 +374,20 @@ int checkMesh( char const * msg, xyzmesh * hmesh, int levels, Scheme scheme=kCat
deltaAvg[2]/=deltaCnt[2];
if (not g_debugmode) {
printf(" delta ratio : (%d/%d %d/%d %d/%d)\n", (int)deltaCnt.x, nverts,
(int)deltaCnt.y, nverts,
printf(" delta ratio : (%d/%d %d/%d %d/%d)\n", (int)deltaCnt.x, nverts,
(int)deltaCnt.y, 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.z );
if (count==0)
printf(" success !\n");
}
delete hmesh;
delete m;
return count;
return count;
}
//------------------------------------------------------------------------------
@ -411,6 +432,10 @@ int main(int argc, char ** argv) {
#define test_catmark_tent
#define test_catmark_tent_creases0
#define test_catmark_tent_creases1
#define test_catmark_square_hedit0
#define test_catmark_square_hedit1
#define test_catmark_square_hedit2
#define test_catmark_square_hedit3
#define test_loop_triangle_edgeonly
#define test_loop_triangle_edgecorner
@ -428,141 +453,161 @@ int main(int argc, char ** argv) {
#ifdef test_catmark_edgeonly
#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
#ifdef test_catmark_edgecorner
#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
#ifdef test_catmark_pyramid
#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
#ifdef test_catmark_pyramid_creases0
#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
#ifdef test_catmark_pyramid_creases1
#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
#ifdef test_catmark_cube
#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
#ifdef test_catmark_cube_creases0
#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
#ifdef test_catmark_cube_creases1
#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
#ifdef test_catmark_cube_corner0
#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
#ifdef test_catmark_cube_corner1
#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
#ifdef test_catmark_cube_corner2
#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
#ifdef test_catmark_cube_corner3
#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
#ifdef test_catmark_cube_corner4
#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
#ifdef test_catmark_dart_edgecorner
#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
#ifdef test_catmark_dart_edgeonly
#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
#ifdef test_catmark_tent
#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
#ifdef test_catmark_tent_creases0
#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
#ifdef test_catmark_tent_creases1
#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
#ifdef test_loop_triangle_edgeonly
#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
#ifdef test_loop_triangle_edgecorner
#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
#ifdef test_loop_saddle_edgeonly
#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
#ifdef test_loop_saddle_edgecorner
#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
#ifdef test_loop_icosahedron
#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
#ifdef test_loop_cube
#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
#ifdef test_loop_cube_creases0
#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
#ifdef test_loop_cube_creases1
#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
#ifdef test_bilinear_cube
#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

View File

@ -55,21 +55,11 @@
# 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(
${ILMBASE_INCLUDE_DIR}
${PROJECT_SOURCE_DIR}/opensubdiv
${GLEW_INCLUDE_DIR}
${GLUT_INCLUDE_DIR}
)
set(SOURCE_FILES
@ -83,6 +73,8 @@ add_executable(osd_regression
target_link_libraries(osd_regression
${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
// 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 <cassert>
@ -88,7 +97,7 @@
// - precision is currently held at 1e-6
//
// - 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.
//
@ -108,17 +117,19 @@ struct xyzVV {
void AddVaryingWithWeight(const xyzVV& , float, void * =0 ) { }
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 ApplyVertexEdit(const OpenSubdiv::HbrVertexEdit<xyzVV> &) { }
void ApplyMovingVertexEdit(const OpenSubdiv::HbrMovingVertexEdit<xyzVV> &) { }
const Imath::Vec3<float>& GetPos() const { return _pos; }
private:
private:
Imath::Vec3<float> _pos;
};
//------------------------------------------------------------------------------
class xyzFV;
typedef OpenSubdiv::HbrMesh<xyzVV> xyzmesh;
typedef OpenSubdiv::HbrFace<xyzVV> xyzface;
typedef OpenSubdiv::HbrVertex<xyzVV> xyzvertex;
typedef OpenSubdiv::HbrFace<xyzVV> xyzface;
typedef OpenSubdiv::HbrVertex<xyzVV> xyzvertex;
typedef OpenSubdiv::HbrHalfedge<xyzVV> xyzhalfedge;
typedef OpenSubdiv::HbrFaceOperator<xyzVV> xyzFaceOperator;
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
bool VertexOnBoundary( xyzvertex const * v ) {
if (not v)
if (not v)
return false;
if (v->OnBoundary())
return true;
xyzvertex const * pv = v->GetParentVertex();
if (pv)
return VertexOnBoundary(pv);
else {
xyzhalfedge const * pe = v->GetParentEdge();
if (pe) {
return VertexOnBoundary(pe->GetOrgVertex()) or
return VertexOnBoundary(pe->GetOrgVertex()) or
VertexOnBoundary(pe->GetDestVertex());
} else {
xyzface const * pf = v->GetParentFace(), * rootf = pf;
@ -159,18 +170,18 @@ bool VertexOnBoundary( xyzvertex const * v ) {
//------------------------------------------------------------------------------
int checkVertexBuffer( xyzmesh * hmesh,
OpenSubdiv::OsdCpuVertexBuffer * vb,
int checkVertexBuffer( xyzmesh * hmesh,
OpenSubdiv::OsdCpuVertexBuffer * vb,
std::vector<int> const & remap) {
int count=0;
Imath::Vec3<float> deltaAvg(0.0, 0.0, 0.0);
int count=0;
Imath::Vec3<float> deltaAvg(0.0, 0.0, 0.0);
Imath::Vec3<float> deltaCnt(0,0,0);
int nverts = hmesh->GetNumVertices();
for (int i=0; i<nverts; ++i) {
xyzvertex * hv = hmesh->GetVertex(i);
float * ov = & vb->GetCpuBuffer()[ remap[ hv->GetID() ] * vb->GetNumElements() ];
// boundary interpolation rules set to "none" produce "undefined" vertices on
@ -180,11 +191,11 @@ int checkVertexBuffer( xyzmesh * hmesh,
continue;
if ( hv->GetData().GetPos()[0] != ov[0] )
if ( hv->GetData().GetPos()[0] != ov[0] )
deltaCnt[0]++;
if ( hv->GetData().GetPos()[1] != ov[1] )
if ( hv->GetData().GetPos()[1] != ov[1] )
deltaCnt[1]++;
if ( hv->GetData().GetPos()[2] != ov[2] )
if ( hv->GetData().GetPos()[2] != ov[2] )
deltaCnt[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[1],
ov[2] );
count++;
count++;
}
}
@ -211,15 +222,15 @@ int checkVertexBuffer( xyzmesh * hmesh,
if (deltaCnt[2])
deltaAvg[2]/=deltaCnt[2];
printf(" delta ratio : (%d/%d %d/%d %d/%d)\n", (int)deltaCnt.x, nverts,
(int)deltaCnt.y, nverts,
printf(" delta ratio : (%d/%d %d/%d %d/%d)\n", (int)deltaCnt.x, nverts,
(int)deltaCnt.y, 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.z );
if (count==0)
printf(" success !\n");
return count;
}
@ -243,14 +254,14 @@ int checkMesh( char const * msg, char const * shape, int levels, Scheme scheme=k
int result =0;
printf("- %s (scheme=%d)\n", msg, scheme);
xyzmesh * refmesh = simpleHbr<xyzVV>(shape, scheme, 0);
refine( refmesh, levels );
std::vector<float> coarseverts;
OpenSubdiv::OsdHbrMesh * hmesh = simpleHbr<OpenSubdiv::OsdVertex>(shape, scheme, coarseverts);
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;
{
{
omesh->Create(hmesh, levels, (int)OpenSubdiv::OsdKernelDispatcher::kCPU, &remap);
OpenSubdiv::OsdCpuVertexBuffer * vb =
OpenSubdiv::OsdCpuVertexBuffer * vb =
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->Synchronize();
checkVertexBuffer(refmesh, vb, remap);
checkVertexBuffer(refmesh, vb, remap);
}
delete hmesh;
return result;
}
//------------------------------------------------------------------------------
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;
// Register Osd compute kernels
@ -318,141 +334,141 @@ int main(int argc, char ** argv) {
#ifdef test_catmark_edgeonly
#include "../shapes/catmark_edgeonly.h"
total += checkMesh( "test_catmark_edgeonly", catmark_edgeonly, levels, kCatmark );
total += checkMesh( "test_catmark_edgeonly", catmark_edgeonly, levels, kCatmark );
#endif
#ifdef test_catmark_edgecorner
#include "../shapes/catmark_edgecorner.h"
total += checkMesh( "test_catmark_edgeonly", catmark_edgecorner, levels, kCatmark );
total += checkMesh( "test_catmark_edgeonly", catmark_edgecorner, levels, kCatmark );
#endif
#ifdef test_catmark_pyramid
#include "../shapes/catmark_pyramid.h"
total += checkMesh( "test_catmark_pyramid", catmark_pyramid, levels, kCatmark );
total += checkMesh( "test_catmark_pyramid", catmark_pyramid, levels, kCatmark );
#endif
#ifdef test_catmark_pyramid_creases0
#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
#ifdef test_catmark_pyramid_creases1
#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
#ifdef test_catmark_cube
#include "../shapes/catmark_cube.h"
total += checkMesh( "test_catmark_cube", catmark_cube, levels, kCatmark );
total += checkMesh( "test_catmark_cube", catmark_cube, levels, kCatmark );
#endif
#ifdef test_catmark_cube_creases0
#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
#ifdef test_catmark_cube_creases1
#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
#ifdef test_catmark_cube_corner0
#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
#ifdef test_catmark_cube_corner1
#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
#ifdef test_catmark_cube_corner2
#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
#ifdef test_catmark_cube_corner3
#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
#ifdef test_catmark_cube_corner4
#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
#ifdef test_catmark_dart_edgecorner
#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
#ifdef test_catmark_dart_edgeonly
#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
#ifdef test_catmark_tent
#include "../shapes/catmark_tent.h"
total += checkMesh( "test_catmark_tent", catmark_tent, levels, kCatmark );
total += checkMesh( "test_catmark_tent", catmark_tent, levels, kCatmark );
#endif
#ifdef test_catmark_tent_creases0
#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
#ifdef test_catmark_tent_creases1
#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
#ifdef test_loop_triangle_edgeonly
#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
#ifdef test_loop_triangle_edgecorner
#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
#ifdef test_loop_saddle_edgeonly
#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
#ifdef test_loop_saddle_edgecorner
#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
#ifdef test_loop_icosahedron
#include "../shapes/loop_icosahedron.h"
total += checkMesh( "test_loop_icosahedron", loop_icosahedron, levels, kLoop );
total += checkMesh( "test_loop_icosahedron", loop_icosahedron, levels, kLoop );
#endif
#ifdef test_loop_cube
#include "../shapes/loop_cube.h"
total += checkMesh( "test_loop_cube", loop_cube, levels, kLoop );
total += checkMesh( "test_loop_cube", loop_cube, levels, kLoop );
#endif
#ifdef test_loop_cube_creases0
#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
#ifdef test_loop_cube_creases1
#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
#ifdef test_bilinear_cube
#include "../shapes/bilinear_cube.h"
total += checkMesh( "test_bilinear_cube", bilinear_cube, levels, kBilinear );
total += checkMesh( "test_bilinear_cube", bilinear_cube, levels, kBilinear );
#endif
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"
;