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

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

View File

@ -72,6 +72,7 @@ if (WIN32)
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" )
@ -81,6 +82,7 @@ if (WIN32)
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
@ -93,6 +95,7 @@ if (${CMAKE_HOST_UNIX})
GL/glew.h
PATHS
${GLEW_LOCATION}/include
$ENV{GLEW_LOCATION}/include
/usr/include
/usr/local/include
/sw/include
@ -105,6 +108,7 @@ if (${CMAKE_HOST_UNIX})
GLEW glew
PATHS
${GLEW_LOCATION}/lib
$ENV{GLEW_LOCATION}/lib
/usr/lib64
/usr/lib
/usr/local/lib64

View File

@ -68,10 +68,13 @@ 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
@ -108,6 +114,7 @@ else ()
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

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,13 +68,13 @@ 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()
@ -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

@ -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})
@ -195,11 +210,12 @@ 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"
)
@ -208,11 +224,12 @@ 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"
)

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

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

@ -74,14 +74,14 @@ public:
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;
}

View File

@ -57,27 +57,18 @@
# *** glutViewer ***
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})
string(REGEX REPLACE ".*[.](.*)" "\\1" extension ${shader_file})
if(WIN32)
# Windows needs some of its dependency dll's copied into the same
# directory as the executable
set( LIBRARIES ${ILMBASE_LIBS_DIRECTORY} ${GLUT_LIBRARIES})
foreach (LIB ${LIBRARIES} )
string(REPLACE ".lib" ".dll" LIB ${LIB})
string(REPLACE ".LIB" ".DLL" LIB ${LIB})
add_custom_command(
TARGET ${target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${LIB}
$<TARGET_FILE_DIR:${target}>
)
endforeach()
endif()
endmacro()
string(REGEX REPLACE "(.*)[.].*" "\\1.inc" inc_file ${shader_file})
list(APPEND INC_FILES ${inc_file})
add_custom_command(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${inc_file}
COMMAND stringify ${CMAKE_CURRENT_SOURCE_DIR}/${shader_file}
${CMAKE_CURRENT_SOURCE_DIR}/${inc_file}
DEPENDS stringify ${CMAKE_CURRENT_SOURCE_DIR}/${shader_file}
)
endforeach()
if(APPLE)
_add_glut_executable(glutViewer
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,10 +82,17 @@
#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 {
@ -92,6 +100,7 @@ struct SimpleShape {
Scheme scheme;
char const * data;
SimpleShape() { }
SimpleShape( char const * idata, char const * iname, Scheme ischeme )
: name(iname), scheme(ischeme), data(idata) { }
};
@ -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,15 +214,20 @@ 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,
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,
g_height;
@ -209,7 +237,8 @@ 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;
@ -217,8 +246,18 @@ 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;
@ -249,6 +288,22 @@ normalize(float * p) {
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
@ -284,22 +339,35 @@ calcNormals(OpenSubdiv::OsdHbrMesh * mesh, std::vector<float> const & pos, std::
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;
}
@ -324,37 +392,12 @@ updateGeom() {
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
//------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
void
createOsdMesh( const char * shape, int level, int kernel, Scheme scheme=kCatmark ) {
fitFrame() {
// 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();
g_pan[0] = g_pan[1] = 0;
g_dolly = g_size;
}
//------------------------------------------------------------------------------
@ -369,11 +412,11 @@ 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++); } }
//------------------------------------------------------------------------------
@ -392,6 +435,32 @@ const char *getKernelName(int kernel) {
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,7 +473,6 @@ 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);
@ -429,6 +497,186 @@ drawNormals() {
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);
}
}
//------------------------------------------------------------------------------
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() {
@ -436,70 +684,100 @@ 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);
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);
bindProgram(g_quadFillProgram);
}
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,7 +809,7 @@ 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;
}
//------------------------------------------------------------------------------
@ -558,7 +842,7 @@ modelMenu(int m) {
m = 0;
if (m >= (int)g_defaultShapes.size())
m = g_defaultShapes.size() - 1;
m = (int)g_defaultShapes.size() - 1;
g_currentShape = m;
@ -588,8 +872,12 @@ 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,6 +887,7 @@ 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;
}
}
@ -606,11 +895,13 @@ keyboard(unsigned char key, int x, int y) {
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();
}
@ -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,6 +928,11 @@ 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");
}
//------------------------------------------------------------------------------
@ -648,6 +944,21 @@ int main(int argc, char ** argv) {
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);

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();
@ -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

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

@ -63,6 +63,8 @@ set(H_FILES
meshFactory.h
mesh.h
subdivisionTables.h
table.h
vertexEditTables.h
)
install( FILES ${H_FILES}

View File

@ -85,12 +85,12 @@ public:
virtual int GetMemoryUsed() const;
// Compute the positions of refined vertices using the specified kernels
virtual void Refine( int level, void * data=0 ) const;
virtual void Apply( int level, void * data=0 ) const;
// Table accessors
typename FarSubdivisionTables<T,U>::template Table<unsigned int> const & Get_F_IT( ) const { return _F_IT; }
FarTable<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; }
FarTable<int> const & Get_F_ITa( ) const { return _F_ITa; }
// Returns the number of indexing tables needed to represent this particular
// subdivision scheme.
@ -116,8 +116,8 @@ private:
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
@ -161,7 +161,7 @@ FarBilinearSubdivisionTables<T,U>::FarBilinearSubdivisionTables( FarMeshFactory<
// pointer to the first vertex corresponding to this level
this->_vertsOffsets[level] = factory._vertVertIdx[level-1] +
factory._vertVertsList[level-1].size();
(int)factory._vertVertsList[level-1].size();
typename FarSubdivisionTables<T,U>::VertexKernelBatch * batch = & (this->_batches[level-1]);
@ -193,7 +193,7 @@ FarBilinearSubdivisionTables<T,U>::FarBilinearSubdivisionTables( FarMeshFactory<
// 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) {
@ -230,7 +230,7 @@ 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);
@ -294,7 +294,7 @@ FarBilinearSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, in
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 ) {

View File

@ -85,12 +85,12 @@ public:
virtual int GetMemoryUsed() const;
// Compute the positions of refined vertices using the specified kernels
virtual void Refine( int level, void * data=0 ) const;
virtual void Apply( int level, void * data=0 ) const;
// Table accessors
typename FarSubdivisionTables<T,U>::template Table<unsigned int> const & Get_F_IT( ) const { return _F_IT; }
FarTable<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; }
FarTable<int> const & Get_F_ITa( ) const { return _F_ITa; }
// Returns the number of indexing tables needed to represent this particular
// subdivision scheme.
@ -120,8 +120,8 @@ private:
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
@ -172,7 +172,7 @@ FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,
// pointer to the first vertex corresponding to this level
this->_vertsOffsets[level] = factory._vertVertIdx[level-1] +
factory._vertVertsList[level-1].size();
(int)factory._vertVertsList[level-1].size();
typename FarSubdivisionTables<T,U>::VertexKernelBatch * batch = & (this->_batches[level-1]);
@ -211,7 +211,7 @@ FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,
// "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) {
@ -260,7 +260,7 @@ FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,
// Vertex vertices
batch->InitVertexKernels( factory._vertVertsList[level].size(), 0 );
batch->InitVertexKernels( (int)factory._vertVertsList[level].size(), 0 );
offset = 0;
int * V_ITa = this->_V_ITa[level-1];
@ -281,8 +281,8 @@ FarCatmarkSubdivisionTables<T,U>::FarCatmarkSubdivisionTables( FarMeshFactory<T,
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 (
@ -382,7 +382,7 @@ 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);
@ -450,7 +450,7 @@ FarCatmarkSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int
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 ) {

View File

@ -64,6 +64,7 @@
#include "../far/bilinearSubdivisionTables.h"
#include "../far/catmarkSubdivisionTables.h"
#include "../far/loopSubdivisionTables.h"
#include "../far/vertexEditTables.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
@ -87,6 +88,7 @@ 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;
@ -114,6 +116,8 @@ 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>;
@ -130,13 +134,18 @@ 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
@ -219,6 +228,14 @@ FarDispatcher<T,U>::ApplyLoopVertexVerticesKernelA(FarMesh<T,U> * mesh, int offs
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,7 +82,7 @@ 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;
virtual void Apply( int level, void * data=0 ) const;
private:
@ -142,12 +142,12 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
// pointer to the first vertex corresponding to this level
this->_vertsOffsets[level] = factory._vertVertIdx[level-1] +
factory._vertVertsList[level-1].size();
(int)factory._vertVertsList[level-1].size();
typename FarSubdivisionTables<T,U>::VertexKernelBatch * batch = & (this->_batches[level-1]);
// Edge vertices
unsigned int * E_IT = this->_E_IT[level-1];
int * E_IT = this->_E_IT[level-1];
float * E_W = this->_E_W[level-1];
batch->kernelE = (int)factory._edgeVertsList[level].size();
for (int i=0; i < batch->kernelE; ++i) {
@ -184,7 +184,7 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
// 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];
@ -205,8 +205,8 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
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 (
@ -303,7 +303,7 @@ FarLoopSubdivisionTables<T,U>::FarLoopSubdivisionTables( FarMeshFactory<T,U> con
}
template <class T, class U> void
FarLoopSubdivisionTables<T,U>::Refine( int level, void * clientdata ) const
FarLoopSubdivisionTables<T,U>::Apply( int level, void * clientdata ) const
{
assert(this->_mesh and level>0);
@ -337,7 +337,7 @@ FarLoopSubdivisionTables<T,U>::computeEdgePoints( int offset, int level, int sta
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 ) {

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.
//
@ -105,6 +106,13 @@ public:
// 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;
@ -119,7 +127,7 @@ public:
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 &);
@ -137,6 +145,12 @@ private:
// 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;
@ -148,6 +162,7 @@ template <class T, class U>
FarMesh<T,U>::~FarMesh()
{
delete _subdivision;
delete _vertexEdit;
}
template <class T, class U> int
@ -162,6 +177,14 @@ FarMesh<T,U>::GetFaceVertices(int level) const {
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

@ -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 & );
@ -145,10 +146,16 @@ private:
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,
@ -330,7 +337,7 @@ FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel ) :
// 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.
@ -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,6 +412,185 @@ copyVertex( T & dest, T const & src ) {
dest = src;
}
// 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 ) {
@ -446,12 +631,20 @@ FarMeshFactory<T,U>::Create( FarDispatcher<T,U> * dispatch ) {
// 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)
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;
@ -104,7 +105,7 @@ public:
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; }
@ -127,63 +128,20 @@ public:
// 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.
@ -246,12 +204,12 @@ protected:
// mesh that owns this subdivisionTable
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
@ -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 :

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

@ -114,7 +114,7 @@ private:
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);
@ -149,36 +149,36 @@ 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;
// 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;
// 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,7 +69,7 @@ template <class T>
class HbrBilinearSubdivision : public HbrSubdivision<T> {
public:
HbrBilinearSubdivision<T>()
: HbrSubdivision<T>() {}
: HbrSubdivision<T>() {}
virtual HbrSubdivision<T>* Clone() const {
return new HbrBilinearSubdivision<T>();
@ -89,6 +89,7 @@ public:
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; }
@ -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();
}
}
@ -531,59 +532,66 @@ HbrBilinearSubdivision<T>::RefineFaceAtVertex(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 (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) {
if (parentVertex) {
assert(parentEdge);
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
// 1. Go up to the parent of my face
parentFace = edge->GetFace()->GetParent();
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();
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;
}
// 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;
}
}
@ -810,15 +818,15 @@ HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) {
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";
@ -856,8 +864,8 @@ HbrBilinearSubdivision<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();
}
// Average the two end points
@ -893,7 +901,7 @@ HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
// 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 {
@ -909,15 +917,15 @@ HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
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;
}

View File

@ -69,10 +69,10 @@ 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);
@ -92,6 +92,7 @@ public:
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,9 +104,9 @@ 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; }
@ -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();
}
}
@ -554,61 +556,68 @@ HbrCatmarkSubdivision<T>::RefineFaceAtVertex(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 (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) {
if (parentVertex) {
assert(parentEdge);
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
// 1. Go up to the parent of my face
parentFace = edge->GetFace()->GetParent();
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();
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;
}
// 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,9 +813,9 @@ 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;
@ -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;
}
}
@ -865,15 +874,15 @@ HbrCatmarkSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) {
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";
@ -909,10 +918,10 @@ HbrCatmarkSubdivision<T>::OldTriangleSubdivide(HbrMesh<T>* mesh, HbrFace<T>* fac
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>*
@ -979,59 +988,59 @@ HbrCatmarkSubdivision<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 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();
}
// 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).
// Handle both the smooth and fractional sharpness cases. We
// lerp between the sharp case (average of the two end points)
// and the unsharp case (average of two end points plus two
// face averages).
float leftWeight, rightWeight, faceWeight, vertWeight;
HbrFace<T>* rf = edge->GetRightFace();
HbrFace<T>* lf = edge->GetLeftFace();
float leftWeight, rightWeight, faceWeight, vertWeight;
HbrFace<T>* rf = edge->GetRightFace();
HbrFace<T>* lf = edge->GetLeftFace();
// 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);
// 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);
// Lerp the face weight between non sharp contribution and
// sharp contribution (which is zero)
faceWeight *= (1.0f - esharp);
// 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;
// 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(edge->GetOrgVertex()->GetData(), vertWeight);
data.AddWithWeight(edge->GetDestVertex()->GetData(), vertWeight);
data.AddWithWeight(lf->Subdivide()->GetData(), faceWeight);
data.AddWithWeight(rf->Subdivide()->GetData(), faceWeight);
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
@ -1071,55 +1080,55 @@ 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
@ -1130,15 +1139,15 @@ HbrCatmarkSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
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;
}

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,11 +79,11 @@ 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() {}
@ -91,25 +91,25 @@ public:
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:

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,11 +79,11 @@ 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() {}
@ -91,27 +91,27 @@ public:
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:

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;
}
}
@ -160,8 +161,8 @@ public:
// 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
@ -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
@ -433,7 +435,7 @@ 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
@ -461,7 +463,7 @@ HbrFace<T>::Initialize(HbrMesh<T>* m, HbrFace<T>* _parent, int childindex, int f
// 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
@ -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
// 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,9 +602,9 @@ 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);
}
}
@ -611,25 +613,25 @@ HbrVertex<T>*
HbrFace<T>::GetVertex(int index) const {
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;
}
}
@ -683,21 +685,21 @@ HbrFace<T>::MarkUsage() {
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();
}
}
@ -710,25 +712,25 @@ HbrFace<T>::ClearUsage() {
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);
@ -127,15 +127,15 @@ public:
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() {
@ -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
@ -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,19 +82,19 @@ 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)
@ -118,7 +118,7 @@ public:
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

@ -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;
}
}
@ -225,32 +225,32 @@ public:
// 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
@ -268,68 +268,68 @@ 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
@ -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;
@ -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;
}
}
@ -533,9 +533,9 @@ HbrHalfedge<T>::GetFVarInfiniteSharp(int datum) {
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,16 +555,16 @@ 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
@ -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,11 +602,11 @@ 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;
}
@ -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)
@ -133,7 +133,7 @@ public:
#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:
@ -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,11 +79,11 @@ class HbrHoleEdit : public HbrHierarchicalEdit<T> {
public:
HbrHoleEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces) {
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces) {
}
HbrHoleEdit(int _faceid, int _nsubfaces, int *_subfaces)
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces) {
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces) {
}
virtual ~HbrHoleEdit() {}
@ -91,9 +91,9 @@ public:
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,7 +74,7 @@ template <class T>
class HbrLoopSubdivision : public HbrSubdivision<T>{
public:
HbrLoopSubdivision<T>()
: HbrSubdivision<T>() {}
: HbrSubdivision<T>() {}
virtual HbrSubdivision<T>* Clone() const {
return new HbrLoopSubdivision<T>();
@ -94,6 +94,7 @@ public:
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; }
@ -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,7 +130,7 @@ 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];
@ -157,8 +158,8 @@ HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, H
fvarindex += fvarwidth;
}
fv.SetInitialized();
}
return;
}
return;
}
HbrHalfedge<T>* edge;
@ -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++;
}
}
}
@ -488,49 +489,49 @@ HbrLoopSubdivision<T>::Refine(HbrMesh<T>* mesh, HbrFace<T>* face) {
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";
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);
@ -547,53 +548,53 @@ HbrLoopSubdivision<T>::RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, Hb
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";
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);
transferEditsToChild(face, child, i);
return child;
} else {
return face->GetChild(i);
}
}
prevedge = edge;
edge = edge->GetNext();
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
@ -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);
}
}
}
@ -690,24 +691,24 @@ HbrLoopSubdivision<T>::GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* 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
@ -716,20 +717,20 @@ HbrLoopSubdivision<T>::GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex
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,9 +751,9 @@ 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;
@ -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();
}
// 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).
// Handle both the smooth and fractional sharpness cases. We
// lerp between the sharp case (average of the two end points)
// and the unsharp case (3/8 of each of the two end points
// plus 1/8 of the two opposite face averages).
// Lerp end point weight between non sharp contribution of
// 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 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);
// 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;
}
@ -907,48 +908,48 @@ 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
@ -959,11 +960,11 @@ HbrLoopSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
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;
}
@ -977,25 +978,25 @@ HbrLoopSubdivision<T>::refineFaceAtMiddle(HbrMesh<T>* mesh, HbrFace<T>* face) {
#endif
if (!face->GetChild(3)) {
HbrFace<T>* child;
HbrVertex<T>* vertices[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);
// 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";
std::cerr << "Creating face " << *child << "\n";
#endif
if (mesh->GetTotalFVarWidth()) {
transferFVarToChild(mesh, face, child, 3);
}
if (mesh->GetTotalFVarWidth()) {
transferFVarToChild(mesh, face, child, 3);
}
transferEditsToChild(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>
@ -143,13 +142,13 @@ public:
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; }
@ -177,9 +176,9 @@ public:
// Interpolate boundary management
enum InterpolateBoundaryMethod {
k_InterpolateBoundaryNone,
k_InterpolateBoundaryEdgeOnly,
k_InterpolateBoundaryEdgeAndCorner,
k_InterpolateBoundaryNone,
k_InterpolateBoundaryEdgeOnly,
k_InterpolateBoundaryEdgeAndCorner,
k_InterpolateBoundaryAlwaysSharp
};
@ -193,12 +192,12 @@ public:
// 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( ; 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
@ -277,7 +278,7 @@ private:
public:
ScopedLock(Mutex *mutex) : _mutex(mutex) {
mutex->Lock();
}
}
~ScopedLock() {
Release();
@ -350,22 +351,16 @@ private:
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;
@ -392,10 +387,10 @@ 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;
};
@ -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;
}
}
@ -533,15 +524,15 @@ HbrMesh<T>::NewVertex(int id, const T &data) {
#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();
id = *recycleIDs.begin();
recycleIDs.erase(recycleIDs.begin());
}
if (id >= maxVertexID) {
maxVertexID = id + 1;
maxVertexID = id + 1;
}
T data(id);
data.Clear();
@ -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);
}
}
}
@ -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,14 +883,14 @@ 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 {
HbrMesh<T>::GetVertices(std::vector<HbrVertex<T>*>& lvertices) const {
#if PRMAN or MENV
ScopedLock lock(&m_verticesMutex);
#else
@ -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]);
}
}
@ -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);
}

View File

@ -69,7 +69,7 @@ template <class T> class HbrMesh;
template <class T> class HbrSubdivision {
public:
HbrSubdivision<T>()
: creaseSubdivision(k_CreaseNormal) {}
: creaseSubdivision(k_CreaseNormal) {}
virtual ~HbrSubdivision<T>() {}
@ -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; }
@ -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;
}
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);
// 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,19 +82,19 @@ 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)
@ -115,46 +115,46 @@ public:
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,19 +173,19 @@ 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)
@ -206,52 +206,52 @@ public:
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

@ -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,21 +112,26 @@ 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()
#-------------------------------------------------------------------------------
@ -144,14 +151,11 @@ if( OPENGL_FOUND AND GLEW_FOUND AND (NOT APPLE) )
${OPENGL_LIBRARY}
${GLEW_LIBRARY}
)
add_definitions(
-DOPENSUBDIV_HAS_GLSL
else( OPENGL_FOUND AND APPLE )
list(APPEND PLATFORM_LIBRARIES
${OPENGL_LIBRARY}
${ILMBASE_LIBRARIES}
)
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.")
endif()
#-------------------------------------------------------------------------------
@ -169,14 +173,6 @@ 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()
#-------------------------------------------------------------------------------
@ -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()
@ -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) :
@ -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 {
@ -415,8 +462,7 @@ 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[] = {
@ -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,6 +93,13 @@ 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;
@ -108,9 +115,16 @@ public:
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const;
virtual void ApplyVertexEdit(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const {}
virtual void 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() {}
@ -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,9 +185,19 @@ 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
@ -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,

View File

@ -70,18 +70,18 @@
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
OsdCpuKernelDispatcher::SubdivisionTable::~SubdivisionTable() {
OsdCpuKernelDispatcher::Table::~Table() {
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);
free(ptr);
ptr = malloc(size);
memcpy(ptr, table, size);
}
@ -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 *
@ -263,6 +290,24 @@ OsdCpuKernelDispatcher::ApplyLoopVertexVerticesKernelA( FarMesh<OsdVertex> * mes
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

@ -95,9 +95,15 @@ public:
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const;
virtual void ApplyVertexEdit(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const;
virtual void 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() {}
@ -114,14 +120,15 @@ public:
protected:
struct SubdivisionTable {
SubdivisionTable() : ptr(NULL) { }
// XXX: until far refactoring finishes, use this.
struct Table {
Table() : ptr(NULL) { }
~SubdivisionTable();
~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

@ -247,5 +247,15 @@ void computeBilinearVertex(const VertexDescriptor *vdesc, float *vertex, float *
}
}
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,6 +58,7 @@
#define OSD_CPU_KERNEL_H
#include "../version.h"
#include <stdio.h>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
@ -91,6 +92,13 @@ struct VertexDescriptor {
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 *
@ -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

@ -115,9 +115,17 @@ public:
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const;
virtual void ApplyVertexEdit(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const;
virtual void 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() {}
@ -149,6 +157,7 @@ protected:
};
std::vector<DeviceTable> _tables;
std::vector<DeviceTable> _editTables;
OsdCudaVertexBuffer *_currentVertexBuffer,
*_currentVaryingBuffer;

View File

@ -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;
@ -449,7 +449,7 @@ computeLoopVertexB(float *fVertex, float *fVaryings, int *V0_ITa, int *V0_IT, fl
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;
@ -556,7 +556,7 @@ computeBilinearVertex(float *fVertex, float *fVaryings, int *V0_ITa, int offset,
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;
@ -586,7 +586,20 @@ 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];
}
}
}
// --------------------------------------------------------------------------------------------
@ -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"
@ -441,8 +441,8 @@ OsdGlslKernelDispatcher::ComputeShader::Compile(int numVertexElements, int numVa
const char *outputs[] = { "outPosition",
"outNormal",
"gl_NextBuffer",
"outVaryingData" };
"gl_NextBuffer",
"outVaryingData" };
int nOutputs = numVaryingElements > 0 ? 4 : 2;

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"
@ -98,9 +98,16 @@ public:
virtual void ApplyLoopVertexVerticesKernelA(FarMesh<OsdVertex> * mesh, int offset, bool pass, int level, int start, int end, void * data) const;
virtual void ApplyVertexEdit(FarMesh<OsdVertex> *mesh, int offset, int level, void * clientdata) const {}
virtual void 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();

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

View File

@ -87,6 +87,11 @@ 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;
@ -106,7 +111,7 @@ public:
_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 ) {
@ -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

@ -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)
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
@ -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
@ -125,25 +150,54 @@ OsdMesh::Create(OsdHbrMesh *hbrMesh, int level, int kernel, std::vector<int> * r
FarMeshFactory<OsdVertex> meshFactory(hbrMesh, _level);
_fMesh = meshFactory.Create(_dispatcher);
_farMesh = meshFactory.Create(_dispatcher);
OSD_DEBUG("PREP: NumCoarseVertex = %d\n", _fMesh->GetNumCoarseVertices());
OSD_DEBUG("PREP: NumVertex = %d\n", _fMesh->GetNumVertices());
OSD_DEBUG("PREP: NumCoarseVertex = %d\n", _farMesh->GetNumCoarseVertices());
OSD_DEBUG("PREP: NumVertex = %d\n", _farMesh->GetNumVertices());
createTables( _fMesh->GetSubdivision() );
createTables( _farMesh->GetSubdivision() );
FarVertexEditTables<OsdVertex> const *editTables = _farMesh->GetVertexEdit();
if (editTables)
createEditTables( editTables );
// 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:
@ -91,15 +93,17 @@ public:
virtual ~OsdMesh();
// Given a valid HbrMesh, create an OsdMesh
// - cappable of densely refining up to 'level'
// - capable of densely refining up to 'level'
// - subdivision kernel one of (kCPU, kOPENMP, kCUDA, kGLSL, kCL)
// - 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 {
@ -15,6 +17,8 @@ public:
void AddWithWeight(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;
};

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>
@ -127,7 +130,7 @@ shape::tag * shape::tag::parseTag(char const * line) {
char name[50];
while (*cp == ' ') cp++;
if (sscanf(cp, "%s", &name )!=1) return t;
if (sscanf(cp, "%s", name )!=1) return t;
while (*cp && *cp != ' ') cp++;
int nints=0, nfloats=0, nstrings=0;
@ -155,9 +158,9 @@ shape::tag * shape::tag::parseTag(char const * line) {
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++;
}
@ -234,7 +237,7 @@ void applyTags( OpenSubdiv::HbrMesh<T> * mesh, shape const * sh ) {
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;
@ -306,10 +309,138 @@ void applyTags( OpenSubdiv::HbrMesh<T> * mesh, shape const * sh ) {
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: ;
}
}

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

@ -96,6 +96,27 @@ 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:
@ -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
@ -516,6 +541,26 @@ int main(int argc, char ** argv) {
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

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>
@ -108,6 +117,8 @@ 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:
@ -264,7 +275,7 @@ int checkMesh( char const * msg, char const * shape, int levels, Scheme scheme=k
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 );
@ -281,6 +292,11 @@ int checkMesh( char const * msg, char const * shape, int levels, Scheme scheme=k
//------------------------------------------------------------------------------
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

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"
;