mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
Embed OpenSubdiv code to TinyUSDZ.
This commit is contained in:
@@ -10,6 +10,9 @@ option(TINYUSDZ_USE_CCACHE "Use ccache for faster recompile." ON)
|
||||
option(TINYUSDZ_BUILD_TESTS "Build tests" ON)
|
||||
option(TINYUSDZ_BUILD_EXAMPLES "Build examples(but not all examples area built in `examples` folder)" ON)
|
||||
option(TINYUSDZ_WITH_OPENSUBDIV "Build with OpenSubdiv(osdCPU. Set `osd_DIR` to specify the path to OpenSubdiv)" OFF)
|
||||
# Use embedded version of OpenSubdiv code by default
|
||||
set(osd_DIR ${PROJECT_SOURCE_DIR}/src/osd)
|
||||
|
||||
option(TINYUSDZ_WITH_AUDIO "Build with Audio support(WAV and MP3)" ON)
|
||||
option(TINYUSDZ_WITH_EXR "Build with EXR HDR texture support" ON)
|
||||
|
||||
|
||||
14
README.md
14
README.md
@@ -34,7 +34,10 @@ TinyUSDZ is currently in alpha stage. Not usable.
|
||||
|
||||
## Requirements
|
||||
|
||||
* C++11
|
||||
* C++11 compiler
|
||||
* [x] gcc 4.8.5(CentOS 7 default) or later
|
||||
* [x] Visual Studio 2017 or later(2015 may OK)
|
||||
* [x] clang 3.8 or later
|
||||
|
||||
## USDZ file format
|
||||
|
||||
@@ -67,14 +70,10 @@ $ make
|
||||
* `TINYUSDZ_BUILD_TESTS` : Build tests
|
||||
* `TINYUSDZ_BUILD_EXAMPLES` : Build examples(note that not all examples in `examples` folder are built)
|
||||
* `TINYUSDZ_WITH_OPENSUBDIV` : Use OpenSubviv to tessellate subdivision surface.
|
||||
* `osd_DIR` to specify the path to OpenSubdiv repo(I recommend to use https://github.com/syoyo/OpenSubdiv-aarch64 )
|
||||
* OpenSubdiv code is included in TinyUSDZ repo. If you want to use external OpenSubdiv repo, specity the path to OpenSubdiv using `osd_DIR` cmake environment variable.
|
||||
* `TINYUSDZ_WITH_AUDIO` : Support loading audio(mp3 and wav).
|
||||
* `TINYUSDZ_WITH_EXR` : Support loading EXR format HDR texture through TinyEXR.
|
||||
|
||||
#### Build with OpenSubdiv(optional)
|
||||
|
||||
Recommended way is to run `scripts/clone_osd.sh` to clone OpenSubdiv-aarch64 repo to `deps/OpenSudiv`, then run `scripts/bootstrap-cmake-linux-with-osd.sh`.
|
||||
|
||||
### Meson
|
||||
|
||||
Meson build is provided for compile tests.
|
||||
@@ -98,6 +97,8 @@ See [prim_format.md](doc/prim_format.md) and [preview_surface.md](doc/preview_su
|
||||
|
||||
## TODO
|
||||
|
||||
* [ ] Subdivision surface using OpenSubdiv.
|
||||
* [ ] Replace OpenSubdiv with our own subdiv library or embree3's one.
|
||||
* [ ] USDA(USD Ascii) support
|
||||
* [ ] Write our own USDA parser with PEG.
|
||||
* [ ] Animation
|
||||
@@ -113,7 +114,6 @@ See [prim_format.md](doc/prim_format.md) and [preview_surface.md](doc/preview_su
|
||||
* [ ] iOS example?
|
||||
* [ ] CPU raytracer viewer
|
||||
* [ ] Viewer with Vulkan API.
|
||||
* [ ] Replace OpenSubdiv with our own subdiv library or embree3's one.
|
||||
* [ ] Read USD data with bounded memory size. This feature is especially useful for mobile platform(e.g. in terms of security, memory consumption, etc)
|
||||
* [ ] USDZ saver
|
||||
* [ ] Support Nested USDZ
|
||||
|
||||
@@ -12,6 +12,5 @@ mkdir ${builddir}
|
||||
cd ${builddir} && cmake \
|
||||
-DCMAKE_VERBOSE_MAKEFILE=1 \
|
||||
-DTINYUSDZ_WITH_OPENSUBDIV=On \
|
||||
-Dosd_DIR=${osd_path} \
|
||||
..
|
||||
|
||||
|
||||
848
src/osd/CMakeLists.txt
Normal file
848
src/osd/CMakeLists.txt
Normal file
@@ -0,0 +1,848 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
# with the following modification; you may not use this file except in
|
||||
# compliance with the Apache License and the following modification to it:
|
||||
# Section 6. Trademarks. is deleted and replaced with:
|
||||
#
|
||||
# 6. Trademarks. This License does not grant permission to use the trade
|
||||
# names, trademarks, service marks, or product names of the Licensor
|
||||
# and its affiliates, except as required to comply with Section 4(c) of
|
||||
# the License and to reproduce the content of the NOTICE file.
|
||||
#
|
||||
# You may obtain a copy of the Apache License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the Apache License with the above modification is
|
||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the Apache License for the specific
|
||||
# language governing permissions and limitations under the Apache License.
|
||||
#
|
||||
|
||||
project(OpenSubdiv)
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.6)
|
||||
|
||||
# Turn on folder support
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Obtain OpenSubdiv API version from version.h file
|
||||
if(EXISTS "${OpenSubdiv_SOURCE_DIR}/opensubdiv/version.h")
|
||||
file(STRINGS "${OpenSubdiv_SOURCE_DIR}/opensubdiv/version.h"
|
||||
OpenSubdiv_VERSION REGEX "^#define OPENSUBDIV_VERSION .*$")
|
||||
string(REPLACE "#define OPENSUBDIV_VERSION " "" OpenSubdiv_VERSION ${OpenSubdiv_VERSION})
|
||||
else()
|
||||
message(FATAL_ERROR, "Cannot locate opensubdiv/version.h in ${OpenSubdiv_SOURCE_DIR}")
|
||||
endif()
|
||||
|
||||
# Evaluate 'soname' from OSD version
|
||||
|
||||
# replace '_' with '.'
|
||||
string(REGEX REPLACE "(_)" "." OSD_SONAME ${OpenSubdiv_VERSION})
|
||||
|
||||
# remove starting 'v' character
|
||||
string(REGEX REPLACE "^v" "" OSD_SONAME ${OSD_SONAME})
|
||||
|
||||
add_definitions(
|
||||
-DOPENSUBDIV_VERSION_STRING="${OSD_SONAME}"
|
||||
)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
message(STATUS "Compiling ${CMAKE_PROJECT_NAME} version ${OpenSubdiv_VERSION}")
|
||||
message(STATUS "Using cmake version ${CMAKE_VERSION}")
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Specify the default install path
|
||||
if (NOT DEFINED CMAKE_INSTALL_PREFIX)
|
||||
SET( CMAKE_INSTALL_PREFIX "${PROJECT_BINARY_DIR}/" )
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED CMAKE_INCDIR_BASE)
|
||||
set( CMAKE_INCDIR_BASE include/opensubdiv )
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED CMAKE_BINDIR_BASE)
|
||||
set( CMAKE_BINDIR_BASE bin )
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED CMAKE_LIBDIR_BASE)
|
||||
set( CMAKE_LIBDIR_BASE lib )
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED CMAKE_FRAMEWORKDIR_BASE)
|
||||
set( CMAKE_FRAMEWORKDIR_BASE Frameworks )
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED CMAKE_PLUGINDIR_BASE)
|
||||
set( CMAKE_PLUGINDIR_BASE plugin )
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED CMAKE_DOCDIR_BASE)
|
||||
set( CMAKE_DOCDIR_BASE share/doc/opensubdiv )
|
||||
else()
|
||||
if (IS_ABSOLUTE ${CMAKE_DOCDIR_BASE})
|
||||
set( CMAKE_DOCDIR_BASE "${CMAKE_DOCDIR_BASE}" )
|
||||
else()
|
||||
set( CMAKE_DOCDIR_BASE "${CMAKE_INSTALL_PREFIX}/${CMAKE_DOCDIR_BASE}" )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Allow install path to be overridden for cross-compile builds
|
||||
if(LIBRARY_OUTPUT_PATH_ROOT)
|
||||
SET( CMAKE_INSTALL_PREFIX "${LIBRARY_OUTPUT_PATH_ROOT}/" )
|
||||
endif()
|
||||
|
||||
# Set the directory where the executables will be stored.
|
||||
set(EXECUTABLE_OUTPUT_PATH
|
||||
"${PROJECT_BINARY_DIR}/bin"
|
||||
CACHE PATH
|
||||
"Directory where executables will be stored"
|
||||
)
|
||||
|
||||
# Set the directory where the libraries will be stored.
|
||||
set(LIBRARY_OUTPUT_PATH
|
||||
"${PROJECT_BINARY_DIR}/lib"
|
||||
CACHE PATH
|
||||
"Directory where all libraries will be stored"
|
||||
)
|
||||
|
||||
# Specify the list of directories to search for cmake modules.
|
||||
set(CMAKE_MODULE_PATH
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
|
||||
)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# OpenSubdiv trips bugs in some older gcc versions
|
||||
if (CMAKE_COMPILER_IS_GNUCC)
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
|
||||
message(WARNING "g++ 4.8 or newer recommended")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Detect Clang (until a cmake version provides built-in variables)
|
||||
if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
|
||||
set(CMAKE_COMPILER_IS_CLANGCC 1)
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Intel")
|
||||
set(CMAKE_COMPILER_IS_ICC 1)
|
||||
endif()
|
||||
|
||||
|
||||
if (NOT CMAKE_COMPILER_IS_ICC)
|
||||
# Currently icc has a bug that asserts when linking rpaths containing long
|
||||
# sequences of ':' that this command causes. The consequence is that examples
|
||||
# built and installed using icc will not have an rpath pointing to the built
|
||||
# OSD library which they depend on and will have to set LD_LIBRARY_PATH instead.
|
||||
list(APPEND CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
endif()
|
||||
|
||||
# add the automatically determined parts of the RPATH
|
||||
# which point to directories outside the build tree to the install RPATH
|
||||
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
|
||||
# ensure that ARC is shown as enabled in the Xcode UI
|
||||
if(CMAKE_GENERATOR STREQUAL "Xcode")
|
||||
set (CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES")
|
||||
endif()
|
||||
|
||||
|
||||
set(OSD_COMPILER_FLAGS)
|
||||
|
||||
# Disable spurious warnings in gcc builds and clang
|
||||
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANGCC OR CMAKE_COMPILER_IS_ICC )
|
||||
|
||||
# Turn on all warnings
|
||||
if(CMAKE_COMPILER_IS_ICC)
|
||||
list(APPEND OSD_COMPILER_FLAGS -w2 -wd1572 -wd1418 -wd981 -wd383 -wd193 -wd444)
|
||||
else()
|
||||
list(APPEND OSD_COMPILER_FLAGS -Wall -Wextra)
|
||||
endif()
|
||||
|
||||
# HBR uses the offsetof macro on a templated struct, which appears
|
||||
# to spuriously set off this warning in both gcc and Clang
|
||||
list(APPEND OSD_COMPILER_FLAGS -Wno-invalid-offsetof)
|
||||
|
||||
# HBR uses unions as an optimization for its memory allocation.
|
||||
# Type casting between union members breaks strict aliasing rules from
|
||||
# gcc 4.4.1 versions onwards. We disable the warning but keep aliasing
|
||||
# optimization.
|
||||
list(APPEND OSD_COMPILER_FLAGS -Wno-strict-aliasing)
|
||||
|
||||
# FAR and OSD have templated virtual function implementations that trigger
|
||||
# a lot of hidden virtual function overloads (some of them spurious).
|
||||
# Disable those for now in Clang.
|
||||
if(CMAKE_COMPILER_IS_CLANGCC)
|
||||
list(APPEND OSD_COMPILER_FLAGS -Wno-overloaded-virtual)
|
||||
endif()
|
||||
|
||||
# Intel's icc compiler requires some libraries linked
|
||||
if(CMAKE_COMPILER_IS_ICC)
|
||||
|
||||
foreach (ICC_LIB iomp5 irng intlc)
|
||||
|
||||
if(CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
list(APPEND ICC_LIB_ARCH "intel64")
|
||||
elseif(CMAKE_SIZEOF_VOID_P MATCHES "4")
|
||||
list(APPEND ICC_LIB_ARCH "ia32")
|
||||
endif()
|
||||
|
||||
find_library( ICC_${ICC_LIB}
|
||||
NAMES
|
||||
${ICC_LIB}
|
||||
HINTS
|
||||
${ICC_LOCATION}
|
||||
PATHS
|
||||
/opt/intel/lib/
|
||||
PATH_SUFFIXES
|
||||
${ICC_LIB_ARCH}
|
||||
lib/${ICC_LIB_ARCH}
|
||||
)
|
||||
|
||||
if (ICC_${ICC_LIB})
|
||||
list(APPEND ICC_LIBRARIES ${ICC_${ICC_LIB}})
|
||||
else()
|
||||
message( FATAL_ERROR "${ICC_${ICC_LIB}} library not found - required by icc" )
|
||||
endif()
|
||||
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
elseif(MSVC)
|
||||
|
||||
# Turn on all warnings
|
||||
list(APPEND OSD_COMPILER_FLAGS /Wall)
|
||||
|
||||
list(APPEND OSD_COMPILER_FLAGS
|
||||
/W3 # Use warning level recommended for production purposes.
|
||||
# Disable since OSD fails to compile on VS2019.
|
||||
#/WX # Treat all compiler warnings as errors.
|
||||
|
||||
# warning C4005: macro redefinition
|
||||
/wd4005
|
||||
|
||||
# these warnings are being triggered from inside VC's header files
|
||||
# warning C4350: behavior change: 'member1' called instead of 'member2'
|
||||
/wd4350
|
||||
# warning C4548: expression before comma has no effect; expected expression with side-effect
|
||||
/wd4548
|
||||
|
||||
# Make sure WinDef.h does not define min and max macros which
|
||||
# will conflict with std::min() and std::max().
|
||||
/DNOMINMAX
|
||||
|
||||
# Make sure the constants in <math.h> get defined.
|
||||
/D_USE_MATH_DEFINES
|
||||
|
||||
# Do not enforce MSVC's safe CRT replacements.
|
||||
/D_CRT_SECURE_NO_WARNINGS
|
||||
|
||||
# Disable checked iterators and iterator debugging. Visual Studio
|
||||
# 2008 does not implement std::vector::data(), so we need to take the
|
||||
# address of std::vector::operator[](0) to get the memory location of
|
||||
# a vector's underlying data storage. This does not work for an empty
|
||||
# vector if checked iterators or iterator debugging is enabled.
|
||||
|
||||
# XXXX manuelk : we can't force SECURE_SCL to 0 or client code has
|
||||
# problems linking against OSD if their build is not also
|
||||
# overriding SSCL to the same value.
|
||||
# See : http://msdn.microsoft.com/en-us/library/vstudio/hh697468.aspx
|
||||
#/D_SECURE_SCL=0
|
||||
#/D_HAS_ITERATOR_DEBUGGING=0
|
||||
)
|
||||
|
||||
option(MSVC_STATIC_CRT "Statically link MSVC CRT" OFF)
|
||||
|
||||
if(MSVC_STATIC_CRT)
|
||||
message(STATUS "Using static MSVC CRT")
|
||||
# http://stackoverflow.com/a/32128977/486990
|
||||
add_compile_options(
|
||||
"$<$<CONFIG:Debug>:/MTd>"
|
||||
"$<$<CONFIG:RelWithDebInfo>:/MT>"
|
||||
"$<$<CONFIG:Release>:/MT>"
|
||||
"$<$<CONFIG:MinSizeRel>:/MT>"
|
||||
)
|
||||
else()
|
||||
# Turn off a duplicate LIBCMT linker warning
|
||||
set(CMAKE_EXE_LINKER_FLAGS
|
||||
"${CMAKE_EXE_LINKER_FLAGS} /NODEFAULTLIB:libcmt.lib")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS
|
||||
"${CMAKE_SHARED_LINKER_FLAGS} /NODEFAULTLIB:libcmt.lib")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
if(${SIMD} MATCHES "AVX")
|
||||
list(APPEND OSD_COMPILER_FLAGS -xAVX)
|
||||
endif()
|
||||
|
||||
add_definitions(${OSD_COMPILER_FLAGS})
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# Ignore rules that will re-run cmake (this will avoid constant
|
||||
# reloading of the generated Visual Studio project).
|
||||
set(CMAKE_SUPPRESS_REGENERATION TRUE)
|
||||
|
||||
option(PTEX_LOCATION "Path to Ptex" "")
|
||||
option(GLEW_LOCATION "Path to GLEW" "")
|
||||
option(GLFW_LOCATION "Path to GLFW" "")
|
||||
|
||||
option(NO_LIB "Disable the opensubdiv libs build (caveat emptor)" OFF)
|
||||
option(NO_EXAMPLES "Disable examples build" OFF)
|
||||
option(NO_TUTORIALS "Disable tutorials build" OFF)
|
||||
option(NO_REGRESSION "Disable regression tests build" OFF)
|
||||
option(NO_PTEX "Disable PTex support" OFF)
|
||||
option(NO_DOC "Disable documentation build" OFF)
|
||||
option(NO_OMP "Disable OpenMP backend" OFF)
|
||||
option(NO_TBB "Disable TBB backend" OFF)
|
||||
option(NO_CUDA "Disable CUDA backend" OFF)
|
||||
option(NO_OPENCL "Disable OpenCL backend" OFF)
|
||||
option(NO_CLEW "Disable CLEW wrapper library" OFF)
|
||||
option(NO_OPENGL "Disable OpenGL support")
|
||||
option(NO_GLES "Disable GLES support" ON)
|
||||
option(NO_METAL "Disable Metal support" OFF)
|
||||
option(NO_DX "Disable DirectX support")
|
||||
option(NO_TESTS "Disable all tests")
|
||||
option(NO_GLTESTS "Disable GL tests")
|
||||
option(NO_GLEW "Disable use of GLEW" ON)
|
||||
option(NO_GLFW "Disable components depending on GLFW" OFF)
|
||||
option(NO_GLFW_X11 "Disable GLFW components depending on X11" OFF)
|
||||
|
||||
option(OPENSUBDIV_GREGORY_EVAL_TRUE_DERIVATIVES "Enable true derivative evaluation for Gregory basis patches" OFF)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||
|
||||
# Save the current value of BUILD_SHARED_LIBS and restore it after
|
||||
# processing Find* modules, since some of the Find* modules invoked
|
||||
# below may wind up stomping over this value.
|
||||
set(build_shared_libs "${BUILD_SHARED_LIBS}")
|
||||
|
||||
set(OSD_GPU FALSE)
|
||||
|
||||
# Check for dependencies
|
||||
if(NOT NO_OMP)
|
||||
find_package(OpenMP)
|
||||
endif()
|
||||
if(NOT NO_TBB)
|
||||
find_package(TBB 4.0)
|
||||
endif()
|
||||
if (NOT NO_OPENGL)
|
||||
find_package(OpenGL)
|
||||
endif()
|
||||
#find_package(OpenGLES)
|
||||
if(NOT NO_OPENCL)
|
||||
if(NOT NO_CLEW)
|
||||
find_package(CLEW)
|
||||
endif()
|
||||
if (NOT CLEW_FOUND)
|
||||
find_package(OpenCL 1.1)
|
||||
else()
|
||||
set(OPENCL_FOUND TRUE)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT NO_CUDA)
|
||||
find_package(CUDA 4.0)
|
||||
endif()
|
||||
if(NOT NO_GLFW AND NOT NO_OPENGL AND NOT ANDROID AND NOT IOS)
|
||||
find_package(GLFW 3.0.0)
|
||||
endif()
|
||||
if(NOT NO_PTEX)
|
||||
find_package(PTex 2.0)
|
||||
find_package(ZLIB 1.2)
|
||||
endif()
|
||||
if(APPLE AND NOT NO_METAL)
|
||||
find_package(Metal)
|
||||
endif()
|
||||
|
||||
# Win32 may report OPENGL_FOUND even if `NO_OPENGL` is set
|
||||
if (OPENGL_FOUND AND NOT NO_OPENGL AND NOT IOS)
|
||||
add_definitions(
|
||||
-DOPENSUBDIV_HAS_OPENGL
|
||||
)
|
||||
if (NOT NO_GLEW)
|
||||
if (APPLE)
|
||||
find_package(GLEW)
|
||||
else()
|
||||
find_package(GLEW REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
if(GLEW_FOUND)
|
||||
add_definitions( -DOSD_USES_GLEW )
|
||||
else()
|
||||
add_definitions( -DOSD_USES_INTERNAL_GLAPILOADER )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WIN32 AND NOT NO_DX)
|
||||
find_package(DXSDK)
|
||||
endif()
|
||||
|
||||
if (NOT NO_DOC)
|
||||
find_package(Doxygen 1.8.4)
|
||||
find_package(Docutils 0.9)
|
||||
else()
|
||||
set(DOXYGEN_EXECUTABLE )
|
||||
endif()
|
||||
|
||||
set(BUILD_SHARED_LIBS "${build_shared_libs}")
|
||||
|
||||
# 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}
|
||||
)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_CXX_FLAGS}")
|
||||
else()
|
||||
if (NOT NO_OMP)
|
||||
message(WARNING
|
||||
"OpenMP was not found : support for OMP parallel compute kernels "
|
||||
"will be disabled in Osd. If your compiler supports OpenMP "
|
||||
"directives, please refer to the FindOpenMP.cmake shared module "
|
||||
"in your cmake installation.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(TBB_FOUND)
|
||||
add_definitions(
|
||||
-DOPENSUBDIV_HAS_TBB
|
||||
${TBB_CXX_FLAGS}
|
||||
)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TBB_CXX_FLAGS}")
|
||||
else()
|
||||
if (NOT NO_TBB)
|
||||
message(WARNING
|
||||
"TBB was not found : support for TBB parallel compute kernels "
|
||||
"will be disabled in Osd. If your compiler supports TBB "
|
||||
"directives, please refer to the FindTBB.cmake shared module "
|
||||
"in your cmake installation.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if( METAL_FOUND AND NOT NO_METAL)
|
||||
set(OSD_GPU TRUE)
|
||||
if (CMAKE_COMPILER_IS_CLANGCC)
|
||||
# When building with Metal support enabled, we need to explicitly
|
||||
# request that the C++ code be compiled with C++11 since some example
|
||||
# code for Metal relies on functionality only available in C++11.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if( OPENGL_FOUND AND NOT NO_OPENGL)
|
||||
set(OSD_GPU TRUE)
|
||||
endif()
|
||||
|
||||
if(GLFW_FOUND AND (GLFW_VERSION VERSION_EQUAL 3.0 OR GLFW_VERSION VERSION_GREATER 3.0))
|
||||
add_definitions( -DGLFW_VERSION_3 )
|
||||
endif()
|
||||
|
||||
macro(osd_detect_gl_version header)
|
||||
|
||||
if (EXISTS "${header}")
|
||||
file(STRINGS "${header}" VERSION_4_2 REGEX "^#define GL_VERSION_4_2.*$")
|
||||
if (VERSION_4_2)
|
||||
set(OPENGL_4_2_FOUND TRUE)
|
||||
else ()
|
||||
message(WARNING "OpenGL 4.2 dependent features not enabled")
|
||||
endif ()
|
||||
|
||||
file(STRINGS "${header}" VERSION_4_3 REGEX "^#define GL_VERSION_4_3.*$")
|
||||
if (VERSION_4_3)
|
||||
SET(OPENGL_4_3_FOUND TRUE)
|
||||
else ()
|
||||
message(WARNING "OpenGL 4.3 dependent features not enabled")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
endmacro()
|
||||
|
||||
if(GLEW_FOUND AND GLEW_INCLUDE_DIR)
|
||||
|
||||
osd_detect_gl_version(${GLEW_INCLUDE_DIR}/GL/glew.h)
|
||||
set(OPENGL_LOADER_INCLUDE_DIRS
|
||||
${GLEW_INCLUDE_DIR}
|
||||
${PROJECT_SOURCE_DIR}/glLoader)
|
||||
set(OPENGL_LOADER_LIBRARIES
|
||||
${GLEW_LIBRARY}
|
||||
${OPENGL_gl_LIBRARY})
|
||||
|
||||
elseif(OPENGL_FOUND)
|
||||
|
||||
osd_detect_gl_version(${PROJECT_SOURCE_DIR}/glLoader/glApi.h)
|
||||
set(OPENGL_LOADER_INCLUDE_DIRS
|
||||
${OPENGL_INCLUDE_DIR}
|
||||
${PROJECT_SOURCE_DIR}/glLoader)
|
||||
set(OPENGL_LOADER_LIBRARIES
|
||||
${OPENGL_gl_LIBRARY})
|
||||
|
||||
endif()
|
||||
|
||||
# note : (GLSL transform feedback kernels require GL 4.2)
|
||||
if(OPENGL_4_2_FOUND)
|
||||
add_definitions(
|
||||
-DOPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
|
||||
)
|
||||
else()
|
||||
if (NOT NO_OPENGL)
|
||||
message(WARNING
|
||||
"OpenGL 4.2 was not found : support for GLSL transform feedback 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()
|
||||
endif()
|
||||
|
||||
# note : (GLSL compute shader kernels require GL 4.3)
|
||||
if(OPENGL_4_3_FOUND)
|
||||
add_definitions(
|
||||
-DOPENSUBDIV_HAS_GLSL_COMPUTE
|
||||
)
|
||||
else()
|
||||
if (NOT NO_OPENGL)
|
||||
message(WARNING
|
||||
"OpenGL 4.3 was not found : support for GLSL compute shader kernels "
|
||||
"will be disabled in Osd. If you have an OpenGL SDK installed "
|
||||
"(version 4.3 or above), please refer to the FindOpenGL.cmake "
|
||||
"shared module in your cmake installation.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(OPENGLES_FOUND AND NOT NO_GLES)
|
||||
add_definitions(
|
||||
-DOPENSUBDIV_HAS_OPENGLES
|
||||
)
|
||||
set(OSD_GPU TRUE)
|
||||
endif()
|
||||
|
||||
if(OPENCL_FOUND)
|
||||
add_definitions(
|
||||
-DOPENSUBDIV_HAS_OPENCL
|
||||
)
|
||||
if(CLEW_FOUND)
|
||||
add_definitions(
|
||||
-DOPENSUBDIV_HAS_CLEW
|
||||
)
|
||||
set(OPENCL_INCLUDE_DIRS ${CLEW_INCLUDE_DIR})
|
||||
set(OPENCL_LIBRARIES ${CLEW_LIBRARY} ${CMAKE_DL_LIBS})
|
||||
else()
|
||||
if (NOT NO_CLEW)
|
||||
message(WARNING
|
||||
"OpenCL was found, but CLEW was not. "
|
||||
"Building with OpenCL support enabled, but the built binary "
|
||||
"will not be portable to systems without OpenCL installed.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (DXSDK_FOUND AND NOT NO_DX)
|
||||
if (OPENCL_CL_D3D11_H_FOUND)
|
||||
set(OPENCL_D3D11_INTEROP_FOUND "YES")
|
||||
add_definitions(
|
||||
-DOPENSUBDIV_HAS_OPENCL_DX_INTEROP
|
||||
-DOPENSUBDIV_HAS_CL_D3D11_H
|
||||
)
|
||||
endif()
|
||||
if (OPENCL_CL_D3D11_EXT_H_FOUND)
|
||||
set(OPENCL_D3D11_INTEROP_FOUND "YES")
|
||||
add_definitions(
|
||||
-DOPENSUBDIV_HAS_OPENCL_DX_INTEROP
|
||||
-DOPENSUBDIV_HAS_CL_D3D11_EXT_H
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
set(OSD_GPU TRUE)
|
||||
else()
|
||||
if (NOT NO_OPENCL)
|
||||
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()
|
||||
endif()
|
||||
|
||||
if(CUDA_FOUND)
|
||||
add_definitions(
|
||||
-DOPENSUBDIV_HAS_CUDA
|
||||
-DCUDA_ENABLE_DEPRECATED=0
|
||||
)
|
||||
set(OSD_GPU TRUE)
|
||||
|
||||
if (UNIX)
|
||||
list( APPEND CUDA_NVCC_FLAGS -Xcompiler -fPIC )
|
||||
if (NOT DEFINED OSD_CUDA_NVCC_FLAGS)
|
||||
if (CUDA_VERSION_MAJOR LESS 6)
|
||||
set( OSD_CUDA_NVCC_FLAGS --gpu-architecture compute_11 )
|
||||
else()
|
||||
set( OSD_CUDA_NVCC_FLAGS --gpu-architecture compute_20 )
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (DEFINED OSD_CUDA_NVCC_FLAGS)
|
||||
list( APPEND CUDA_NVCC_FLAGS ${OSD_CUDA_NVCC_FLAGS})
|
||||
endif()
|
||||
|
||||
else()
|
||||
if (NOT NO_CUDA)
|
||||
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()
|
||||
endif()
|
||||
|
||||
if(PTEX_FOUND)
|
||||
add_definitions(
|
||||
-DOPENSUBDIV_HAS_PTEX
|
||||
-DPTEX_STATIC
|
||||
)
|
||||
else()
|
||||
if(NOT NO_PTEX)
|
||||
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()
|
||||
endif()
|
||||
|
||||
if( OPENSUBDIV_GREGORY_EVAL_TRUE_DERIVATIVES )
|
||||
add_definitions(-DOPENSUBDIV_GREGORY_EVAL_TRUE_DERIVATIVES)
|
||||
endif()
|
||||
|
||||
# Link examples & regressions against Osd
|
||||
if( BUILD_SHARED_LIBS )
|
||||
if( OSD_GPU )
|
||||
set( OSD_LINK_TARGET osd_dynamic_gpu osd_dynamic_cpu )
|
||||
else()
|
||||
set( OSD_LINK_TARGET osd_dynamic_cpu )
|
||||
endif()
|
||||
else()
|
||||
if( OSD_GPU )
|
||||
set( OSD_LINK_TARGET osd_static_gpu osd_static_cpu )
|
||||
else()
|
||||
set( OSD_LINK_TARGET osd_static_cpu )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
if ("${GLEW_LIBRARY}" MATCHES "glew32s(d|)")
|
||||
# Link against the static version of GLEW
|
||||
add_definitions(
|
||||
-DGLEW_STATIC
|
||||
)
|
||||
endif()
|
||||
|
||||
if (DXSDK_FOUND AND NOT NO_DX)
|
||||
add_definitions(
|
||||
-DOPENSUBDIV_HAS_DX11SDK
|
||||
)
|
||||
set(OSD_GPU TRUE)
|
||||
elseif(NOT NO_DX)
|
||||
message(WARNING
|
||||
"DirectX11 SDK was not found. "
|
||||
"If you do have DXSDK installed and see this message, "
|
||||
"please add your sdk path to FindDirectX.cmake in "
|
||||
"${PROJECT_SOURCE_DIR}/cmake or set it through the "
|
||||
"DXSDK_LOCATION cmake command line argument or "
|
||||
"environment variable."
|
||||
)
|
||||
endif()
|
||||
|
||||
# Link examples & regressions statically against Osd for
|
||||
# Windows until all the kinks can be worked out.
|
||||
if( OSD_GPU )
|
||||
set( OSD_LINK_TARGET osd_static_cpu osd_static_gpu )
|
||||
else()
|
||||
set( OSD_LINK_TARGET osd_static_cpu )
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# General-use macros
|
||||
|
||||
# Macro for processing public headers into the build area for doxygen processing
|
||||
|
||||
add_custom_target( public_headers )
|
||||
|
||||
macro(osd_add_doxy_headers headers)
|
||||
if (NOT NO_DOC AND DOXYGEN_FOUND)
|
||||
file(RELATIVE_PATH path "${OpenSubdiv_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" )
|
||||
|
||||
string(REPLACE "/" "_" targetpath ${path})
|
||||
|
||||
foreach (header ${headers})
|
||||
|
||||
set(infile "${CMAKE_CURRENT_SOURCE_DIR}/${header}")
|
||||
set(outfile "${OpenSubdiv_BINARY_DIR}/public_headers/${path}/${header}")
|
||||
set(targetname "${targetpath}_${header}")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${outfile}"
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
ARGS
|
||||
-E copy ${infile} ${outfile}
|
||||
DEPENDS
|
||||
${infile}
|
||||
)
|
||||
|
||||
add_custom_target(${targetname} DEPENDS "${outfile}")
|
||||
|
||||
|
||||
list(APPEND headerfiles ${targetname} )
|
||||
endforeach()
|
||||
|
||||
add_dependencies( public_headers DEPENDS ${headerfiles} )
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Kernel Stringification
|
||||
# We want to use preprocessor include directives to include GLSL and OpenCL
|
||||
# kernel 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.
|
||||
function(osd_stringify src_files varname)
|
||||
|
||||
set(inc_files "")
|
||||
|
||||
foreach(src_file ${src_files})
|
||||
|
||||
string(REGEX REPLACE ".*[.](.*)" "\\1" extension "${src_file}")
|
||||
|
||||
string(REGEX REPLACE "(.*)[.].*" "\\1.gen.h" inc_file "${src_file}")
|
||||
list(APPEND inc_files "${CMAKE_CURRENT_BINARY_DIR}/${inc_file}")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${inc_file}"
|
||||
COMMAND
|
||||
stringify "${CMAKE_CURRENT_SOURCE_DIR}/${src_file}" "${CMAKE_CURRENT_BINARY_DIR}/${inc_file}"
|
||||
DEPENDS
|
||||
stringify "${CMAKE_CURRENT_SOURCE_DIR}/${src_file}"
|
||||
)
|
||||
|
||||
endforeach()
|
||||
set(${varname} ${inc_files} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Macro wrapper for adding a non-cuda dependent executable
|
||||
macro(osd_add_executable target folder)
|
||||
|
||||
add_executable(${target} ${ARGN})
|
||||
|
||||
set_target_properties(${target} PROPERTIES FOLDER ${folder})
|
||||
|
||||
if(CMAKE_COMPILER_IS_ICC)
|
||||
target_link_libraries(${target} ${ICC_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set_property (TARGET ${target} APPEND_STRING PROPERTY
|
||||
COMPILE_FLAGS " -fobjc-arc ")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
# Macro for adding a cuda executable if cuda is found and a regular
|
||||
# executable otherwise.
|
||||
macro(osd_add_possibly_cuda_executable target folder)
|
||||
if(CUDA_FOUND)
|
||||
cuda_add_executable(${target} ${ARGN})
|
||||
else()
|
||||
add_executable(${target} ${ARGN})
|
||||
endif()
|
||||
|
||||
set_target_properties(${target} PROPERTIES FOLDER ${folder})
|
||||
|
||||
if(CMAKE_COMPILER_IS_ICC)
|
||||
target_link_libraries(${target} ${ICC_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set_property (TARGET ${target} APPEND_STRING PROPERTY
|
||||
COMPILE_FLAGS " -fobjc-arc ")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
# Macro for adding a cuda library if cuda is found and a regular
|
||||
# library otherwise.
|
||||
macro(osd_add_possibly_cuda_library target folder)
|
||||
if(CUDA_FOUND)
|
||||
cuda_add_library(${target} ${ARGN})
|
||||
else()
|
||||
add_library(${target} ${ARGN})
|
||||
endif()
|
||||
set_target_properties(${target} PROPERTIES FOLDER ${folder})
|
||||
|
||||
if(APPLE)
|
||||
set_property (TARGET ${target} APPEND_STRING PROPERTY
|
||||
COMPILE_FLAGS " -fobjc-arc ")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
# Macro for adding a (potentially cuda) GLFW executable.
|
||||
macro(osd_add_glfw_executable target folder)
|
||||
|
||||
osd_add_possibly_cuda_executable(${target} ${folder} ${ARGN})
|
||||
|
||||
if(APPLE)
|
||||
set_property (TARGET ${target} APPEND_STRING PROPERTY
|
||||
COMPILE_FLAGS " -fobjc-arc ")
|
||||
endif()
|
||||
|
||||
endmacro()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Build targets
|
||||
|
||||
|
||||
# if you want to build examples against installed OpenSubdiv header files,
|
||||
# use OPENSUBDIV_INCLUDE_DIR.
|
||||
|
||||
# example: if you have already installed opensubdiv libs in this cmake setup,
|
||||
# set (OPENSUBDIV_INCLUDE_DIR ${CMAKE_INSTALL_PREFIX}/${CMAKE_INCDIR_BASE})
|
||||
|
||||
if (NOT OPENSUBDIV_INCLUDE_DIR)
|
||||
set(OPENSUBDIV_INCLUDE_DIR "${PROJECT_SOURCE_DIR}")
|
||||
endif()
|
||||
|
||||
#if (NOT NO_TESTS)
|
||||
# enable_testing()
|
||||
#endif()
|
||||
#
|
||||
#if (NOT NO_OPENGL)
|
||||
# add_subdirectory(glLoader)
|
||||
#endif()
|
||||
|
||||
add_subdirectory(opensubdiv)
|
||||
|
||||
#if (NOT ANDROID) # XXXdyu
|
||||
# add_subdirectory(regression)
|
||||
#endif()
|
||||
|
||||
#if (NOT NO_EXAMPLES)
|
||||
# add_subdirectory(examples)
|
||||
#endif()
|
||||
#
|
||||
#if (NOT NO_TUTORIALS)
|
||||
# add_subdirectory(tutorials)
|
||||
#endif()
|
||||
#
|
||||
#if (NOT NO_DOC)
|
||||
# add_subdirectory(documentation)
|
||||
#endif()
|
||||
174
src/osd/LICENSE.txt
Normal file
174
src/osd/LICENSE.txt
Normal file
@@ -0,0 +1,174 @@
|
||||
|
||||
Modified Apache 2.0 License
|
||||
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor
|
||||
and its affiliates, except as required to comply with Section 4(c) of
|
||||
the License and to reproduce the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
3
src/osd/README.md
Normal file
3
src/osd/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Code grabbed from OpenSubdiv-aarch64(v3.4.3(2020 April))
|
||||
|
||||
https://github.com/syoyo/OpenSubdiv-aarch64
|
||||
358
src/osd/opensubdiv/CMakeLists.txt
Normal file
358
src/osd/opensubdiv/CMakeLists.txt
Normal file
@@ -0,0 +1,358 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
# with the following modification; you may not use this file except in
|
||||
# compliance with the Apache License and the following modification to it:
|
||||
# Section 6. Trademarks. is deleted and replaced with:
|
||||
#
|
||||
# 6. Trademarks. This License does not grant permission to use the trade
|
||||
# names, trademarks, service marks, or product names of the Licensor
|
||||
# and its affiliates, except as required to comply with Section 4(c) of
|
||||
# the License and to reproduce the content of the NOTICE file.
|
||||
#
|
||||
# You may obtain a copy of the Apache License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the Apache License with the above modification is
|
||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the Apache License for the specific
|
||||
# language governing permissions and limitations under the Apache License.
|
||||
#
|
||||
|
||||
if (NOT NO_LIB)
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
include_directories(
|
||||
"${PROJECT_SOURCE_DIR}/opensubdiv"
|
||||
)
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# platform dependent tweaks
|
||||
if(APPLE OR UNIX)
|
||||
set(PLATFORM_COMPILE_FLAGS -fPIC)
|
||||
elseif(WIN32)
|
||||
|
||||
endif()
|
||||
|
||||
add_definitions(
|
||||
${PLATFORM_COMPILE_FLAGS}
|
||||
)
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
if( OPENMP_FOUND )
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
list(APPEND PLATFORM_CPU_LIBRARIES gomp)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if( TBB_FOUND )
|
||||
include_directories("${TBB_INCLUDE_DIR}")
|
||||
list(APPEND PLATFORM_CPU_LIBRARIES
|
||||
${TBB_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(OPENGL_FOUND OR OPENCL_FOUND OR DXSDK_FOUND OR METAL_FOUND)
|
||||
add_subdirectory(tools/stringify)
|
||||
endif()
|
||||
|
||||
if( OPENGL_FOUND )
|
||||
include_directories(${OPENGL_LOADER_INCLUDE_DIRS})
|
||||
list(APPEND PLATFORM_GPU_LIBRARIES
|
||||
${OPENGL_LOADER_LIBRARIES}
|
||||
)
|
||||
set(OPENGL_LOADER_OBJS $<TARGET_OBJECTS:glLoader_obj>)
|
||||
elseif( OPENGLES_FOUND )
|
||||
include_directories("${OPENGLES_INCLUDE_DIR}")
|
||||
list(APPEND PLATFORM_GPU_LIBRARIES
|
||||
${OPENGLES_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
if( DXSDK_FOUND )
|
||||
include_directories( "${DXSDK_INCLUDE_DIR}" )
|
||||
list(APPEND PLATFORM_GPU_LIBRARIES
|
||||
${DXSDK_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
if( METAL_FOUND )
|
||||
include_directories( "${METAL_INCLUDE_DIR}" )
|
||||
list(APPEND PLATFORM_GPU_LIBRARIES
|
||||
${METAL_LIBRARIES}
|
||||
)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
|
||||
endif()
|
||||
|
||||
if ( OPENCL_FOUND )
|
||||
include_directories( "${OPENCL_INCLUDE_DIRS}" )
|
||||
list(APPEND PLATFORM_GPU_LIBRARIES
|
||||
${OPENCL_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
if( CUDA_FOUND )
|
||||
include_directories( "${CUDA_INCLUDE_DIRS}" )
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
add_subdirectory(hbr)
|
||||
|
||||
add_subdirectory(sdc)
|
||||
|
||||
add_subdirectory(vtr)
|
||||
|
||||
add_subdirectory(far)
|
||||
|
||||
add_subdirectory(osd)
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
install( FILES version.h
|
||||
DESTINATION
|
||||
"${CMAKE_INCDIR_BASE}"
|
||||
PERMISSIONS
|
||||
OWNER_READ
|
||||
GROUP_READ
|
||||
WORLD_READ )
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# Build static libs ------------------------------------
|
||||
add_library(osd_static_cpu
|
||||
STATIC
|
||||
version.cpp
|
||||
$<TARGET_OBJECTS:sdc_obj>
|
||||
$<TARGET_OBJECTS:vtr_obj>
|
||||
$<TARGET_OBJECTS:far_obj>
|
||||
$<TARGET_OBJECTS:osd_cpu_obj>
|
||||
)
|
||||
|
||||
set_target_properties(osd_static_cpu
|
||||
PROPERTIES
|
||||
OUTPUT_NAME osdCPU
|
||||
CLEAN_DIRECT_OUTPUT 1
|
||||
FOLDER "opensubdiv"
|
||||
)
|
||||
|
||||
target_link_libraries(osd_static_cpu
|
||||
${PLATFORM_CPU_LIBRARIES}
|
||||
)
|
||||
|
||||
install( TARGETS osd_static_cpu DESTINATION "${CMAKE_LIBDIR_BASE}" )
|
||||
|
||||
if( OSD_GPU )
|
||||
# this macro uses FindCUDA.cmake to compile .cu kernel files
|
||||
# the target then adds the other obj dependencies and include files
|
||||
osd_add_possibly_cuda_library(osd_static_gpu "opensubdiv"
|
||||
STATIC
|
||||
version.cpp
|
||||
$<TARGET_OBJECTS:osd_gpu_obj>
|
||||
${OPENGL_LOADER_OBJS}
|
||||
${CUDA_KERNEL_FILES}
|
||||
)
|
||||
set_target_properties(osd_static_gpu PROPERTIES OUTPUT_NAME osdGPU CLEAN_DIRECT_OUTPUT 1)
|
||||
|
||||
target_link_libraries(osd_static_gpu
|
||||
${PLATFORM_CPU_LIBRARIES} ${PLATFORM_GPU_LIBRARIES}
|
||||
)
|
||||
|
||||
install( TARGETS osd_static_gpu DESTINATION "${CMAKE_LIBDIR_BASE}" )
|
||||
endif()
|
||||
|
||||
|
||||
# Build dynamic libs ----------------------------------
|
||||
if (BUILD_SHARED_LIBS AND NOT WIN32 AND NOT IOS)
|
||||
|
||||
# generate dynamic-link targets
|
||||
|
||||
#---------------------------------------------------
|
||||
add_library(osd_dynamic_cpu
|
||||
SHARED
|
||||
version.cpp
|
||||
$<TARGET_OBJECTS:sdc_obj>
|
||||
$<TARGET_OBJECTS:vtr_obj>
|
||||
$<TARGET_OBJECTS:far_obj>
|
||||
$<TARGET_OBJECTS:osd_cpu_obj>
|
||||
)
|
||||
|
||||
if (NOT ANDROID)
|
||||
set_target_properties(osd_dynamic_cpu
|
||||
PROPERTIES
|
||||
OUTPUT_NAME osdCPU
|
||||
CLEAN_DIRECT_OUTPUT 1
|
||||
SOVERSION ${OSD_SONAME}
|
||||
)
|
||||
else()
|
||||
set_target_properties(osd_dynamic_cpu
|
||||
PROPERTIES
|
||||
OUTPUT_NAME osdCPU
|
||||
CLEAN_DIRECT_OUTPUT 1
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(osd_dynamic_cpu
|
||||
${PLATFORM_CPU_LIBRARIES}
|
||||
)
|
||||
|
||||
install( TARGETS osd_dynamic_cpu LIBRARY DESTINATION "${CMAKE_LIBDIR_BASE}" )
|
||||
|
||||
#---------------------------------------------------
|
||||
if( OSD_GPU )
|
||||
osd_add_possibly_cuda_library(osd_dynamic_gpu "opensubdiv"
|
||||
SHARED
|
||||
version.cpp
|
||||
$<TARGET_OBJECTS:osd_gpu_obj>
|
||||
${OPENGL_LOADER_OBJS}
|
||||
${CUDA_KERNEL_FILES}
|
||||
)
|
||||
|
||||
if (NOT ANDROID)
|
||||
set_target_properties(osd_dynamic_gpu
|
||||
PROPERTIES
|
||||
OUTPUT_NAME osdGPU
|
||||
CLEAN_DIRECT_OUTPUT 1
|
||||
SOVERSION ${OSD_SONAME}
|
||||
)
|
||||
else()
|
||||
set_target_properties(osd_dynamic_gpu
|
||||
PROPERTIES
|
||||
OUTPUT_NAME osdGPU
|
||||
CLEAN_DIRECT_OUTPUT 1
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(osd_dynamic_gpu
|
||||
osd_dynamic_cpu
|
||||
${PLATFORM_CPU_LIBRARIES} ${PLATFORM_GPU_LIBRARIES}
|
||||
)
|
||||
|
||||
install( TARGETS osd_dynamic_gpu LIBRARY DESTINATION "${CMAKE_LIBDIR_BASE}" )
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
# Build frameworks ----------------------------------
|
||||
if(APPLE)
|
||||
get_directory_property(OSD_HEADER_FILES DIRECTORY ${CMAKE_SOURCE_DIR}/opensubdiv/osd DEFINITION PUBLIC_HEADER_FILES)
|
||||
get_directory_property(FAR_HEADER_FILES DIRECTORY ${CMAKE_SOURCE_DIR}/opensubdiv/far DEFINITION PUBLIC_HEADER_FILES)
|
||||
get_directory_property(SDC_HEADER_FILES DIRECTORY ${CMAKE_SOURCE_DIR}/opensubdiv/sdc DEFINITION PUBLIC_HEADER_FILES)
|
||||
get_directory_property(HBR_HEADER_FILES DIRECTORY ${CMAKE_SOURCE_DIR}/opensubdiv/hbr DEFINITION PUBLIC_HEADER_FILES)
|
||||
get_directory_property(VTR_HEADER_FILES DIRECTORY ${CMAKE_SOURCE_DIR}/opensubdiv/vtr DEFINITION PUBLIC_HEADER_FILES)
|
||||
|
||||
|
||||
foreach(file ${OSD_HEADER_FILES})
|
||||
list(APPEND PUBLIC_HEADER_FILES "osd/${file}")
|
||||
endforeach(file)
|
||||
|
||||
foreach(file ${FAR_HEADER_FILES})
|
||||
list(APPEND PUBLIC_HEADER_FILES "far/${file}")
|
||||
endforeach(file)
|
||||
|
||||
foreach(file ${SDC_HEADER_FILES})
|
||||
list(APPEND PUBLIC_HEADER_FILES "sdc/${file}")
|
||||
endforeach(file)
|
||||
|
||||
foreach(file ${HBR_HEADER_FILES})
|
||||
list(APPEND PUBLIC_HEADER_FILES "hbr/${file}")
|
||||
endforeach(file)
|
||||
|
||||
foreach(file ${VTR_HEADER_FILES})
|
||||
list(APPEND PUBLIC_HEADER_FILES "vtr/${file}")
|
||||
endforeach(file)
|
||||
|
||||
list(APPEND PUBLIC_HEADER_FILES "version.h")
|
||||
|
||||
#static framework
|
||||
add_library(osd_static_framework
|
||||
STATIC
|
||||
version.cpp
|
||||
$<TARGET_OBJECTS:sdc_obj>
|
||||
$<TARGET_OBJECTS:vtr_obj>
|
||||
$<TARGET_OBJECTS:far_obj>
|
||||
$<TARGET_OBJECTS:osd_cpu_obj>
|
||||
$<TARGET_OBJECTS:osd_gpu_obj>
|
||||
${OPENGL_LOADER_OBJS}
|
||||
)
|
||||
|
||||
set_target_properties(
|
||||
osd_static_framework
|
||||
PROPERTIES
|
||||
FRAMEWORK true
|
||||
INSTALL_NAME_DIR "@rpath/OpenSubdiv.framework/OpenSubdiv"
|
||||
INSTALL_RPATH "@executable_path/Frameworks;@loader_path/Frameworks"
|
||||
OUTPUT_NAME OpenSubdiv
|
||||
CLEAN_DIRECT_OUTPUT true
|
||||
)
|
||||
|
||||
target_link_libraries(osd_static_framework
|
||||
${PLATFORM_CPU_LIBRARIES} ${PLATFORM_GPU_LIBRARIES}
|
||||
)
|
||||
|
||||
install( TARGETS osd_static_framework
|
||||
LIBRARY DESTINATION "${CMAKE_LIBDIR_BASE}"
|
||||
FRAMEWORK DESTINATION "${CMAKE_LIBDIR_BASE}"
|
||||
PUBLIC_HEADER DESTINATION "${CMAKE_INCDIR_BASE}"
|
||||
ARCHIVE DESTINATION "${CMAKE_LIBDIR_BASE}")
|
||||
|
||||
|
||||
#shared framework
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_library(osd_dynamic_framework
|
||||
SHARED
|
||||
version.cpp
|
||||
$<TARGET_OBJECTS:sdc_obj>
|
||||
$<TARGET_OBJECTS:vtr_obj>
|
||||
$<TARGET_OBJECTS:far_obj>
|
||||
$<TARGET_OBJECTS:osd_cpu_obj>
|
||||
$<TARGET_OBJECTS:osd_gpu_obj>
|
||||
${OPENGL_LOADER_OBJS}
|
||||
)
|
||||
|
||||
set_target_properties(
|
||||
osd_dynamic_framework
|
||||
PROPERTIES
|
||||
RPATH true
|
||||
FRAMEWORK true
|
||||
INSTALL_NAME_DIR "@rpath/OpenSubdiv.framework/OpenSubdiv"
|
||||
INSTALL_RPATH "@executable_path/Frameworks;@loader_path/Frameworks"
|
||||
OUTPUT_NAME OpenSubdiv
|
||||
CLEAN_DIRECT_OUTPUT true
|
||||
)
|
||||
|
||||
target_link_libraries(osd_dynamic_framework
|
||||
${PLATFORM_CPU_LIBRARIES} ${PLATFORM_GPU_LIBRARIES}
|
||||
)
|
||||
|
||||
install( TARGETS osd_dynamic_framework
|
||||
FRAMEWORK DESTINATION "${CMAKE_LIBDIR_BASE}"
|
||||
LIBRARY DESTINATION "${CMAKE_LIBDIR_BASE}"
|
||||
PUBLIC_HEADER DESTINATION "${CMAKE_INCDIR_BASE}"
|
||||
PRIVATE_HEADER DESTINATION "${CMAKE_INCDIR_BASE}"
|
||||
)
|
||||
|
||||
foreach(file ${PUBLIC_HEADER_FILES})
|
||||
add_custom_command(TARGET osd_dynamic_framework POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${CMAKE_SOURCE_DIR}/opensubdiv/${file}"
|
||||
"$<TARGET_FILE_DIR:osd_dynamic_framework>/Headers/${file}"
|
||||
)
|
||||
endforeach(file)
|
||||
|
||||
add_custom_command(TARGET osd_dynamic_framework POST_BUILD
|
||||
COMMAND ln -sf
|
||||
"Versions/Current/Headers"
|
||||
"$<TARGET_FILE_DIR:osd_dynamic_framework>/../../Headers"
|
||||
)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
108
src/osd/opensubdiv/far/CMakeLists.txt
Normal file
108
src/osd/opensubdiv/far/CMakeLists.txt
Normal file
@@ -0,0 +1,108 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
# with the following modification; you may not use this file except in
|
||||
# compliance with the Apache License and the following modification to it:
|
||||
# Section 6. Trademarks. is deleted and replaced with:
|
||||
#
|
||||
# 6. Trademarks. This License does not grant permission to use the trade
|
||||
# names, trademarks, service marks, or product names of the Licensor
|
||||
# and its affiliates, except as required to comply with Section 4(c) of
|
||||
# the License and to reproduce the content of the NOTICE file.
|
||||
#
|
||||
# You may obtain a copy of the Apache License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the Apache License with the above modification is
|
||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the Apache License for the specific
|
||||
# language governing permissions and limitations under the Apache License.
|
||||
#
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# source & headers
|
||||
set(SOURCE_FILES
|
||||
bilinearPatchBuilder.cpp
|
||||
catmarkPatchBuilder.cpp
|
||||
error.cpp
|
||||
loopPatchBuilder.cpp
|
||||
patchBasis.cpp
|
||||
patchBuilder.cpp
|
||||
patchDescriptor.cpp
|
||||
patchMap.cpp
|
||||
patchTable.cpp
|
||||
patchTableFactory.cpp
|
||||
ptexIndices.cpp
|
||||
stencilTable.cpp
|
||||
stencilTableFactory.cpp
|
||||
stencilBuilder.cpp
|
||||
topologyDescriptor.cpp
|
||||
topologyRefiner.cpp
|
||||
topologyRefinerFactory.cpp
|
||||
)
|
||||
|
||||
set(PRIVATE_HEADER_FILES
|
||||
bilinearPatchBuilder.h
|
||||
catmarkPatchBuilder.h
|
||||
loopPatchBuilder.h
|
||||
patchBasis.h
|
||||
patchBuilder.h
|
||||
sparseMatrix.h
|
||||
stencilBuilder.h
|
||||
)
|
||||
|
||||
set(PUBLIC_HEADER_FILES
|
||||
error.h
|
||||
patchDescriptor.h
|
||||
patchParam.h
|
||||
patchMap.h
|
||||
patchTable.h
|
||||
patchTableFactory.h
|
||||
primvarRefiner.h
|
||||
ptexIndices.h
|
||||
stencilTable.h
|
||||
stencilTableFactory.h
|
||||
topologyDescriptor.h
|
||||
topologyLevel.h
|
||||
topologyRefiner.h
|
||||
topologyRefinerFactory.h
|
||||
types.h
|
||||
)
|
||||
|
||||
set(DOXY_HEADER_FILES ${PUBLIC_HEADER_FILES})
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
if (NOT NO_LIB)
|
||||
|
||||
# Compile objs first for both the CPU and GPU libs -----
|
||||
add_library(far_obj
|
||||
OBJECT
|
||||
${SOURCE_FILES}
|
||||
${PRIVATE_HEADER_FILES}
|
||||
${PUBLIC_HEADER_FILES}
|
||||
)
|
||||
|
||||
set_target_properties(far_obj
|
||||
PROPERTIES
|
||||
FOLDER "opensubdiv"
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
osd_add_doxy_headers( "${DOXY_HEADER_FILES}" )
|
||||
|
||||
install(
|
||||
FILES
|
||||
${PUBLIC_HEADER_FILES}
|
||||
DESTINATION
|
||||
"${CMAKE_INCDIR_BASE}/far"
|
||||
PERMISSIONS
|
||||
OWNER_READ
|
||||
GROUP_READ
|
||||
WORLD_READ )
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
107
src/osd/opensubdiv/far/bilinearPatchBuilder.cpp
Normal file
107
src/osd/opensubdiv/far/bilinearPatchBuilder.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
//
|
||||
// Copyright 2018 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../far/bilinearPatchBuilder.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
using Vtr::internal::Level;
|
||||
using Vtr::internal::FVarLevel;
|
||||
using Vtr::internal::Refinement;
|
||||
|
||||
namespace Far {
|
||||
|
||||
namespace {
|
||||
|
||||
//
|
||||
// The patch type associated with each basis for Bilinear -- quickly indexed
|
||||
// from an array. The patch type here is essentially the quad form of each
|
||||
// basis.
|
||||
//
|
||||
PatchDescriptor::Type patchTypeFromBasisArray[] = {
|
||||
PatchDescriptor::NON_PATCH, // undefined
|
||||
PatchDescriptor::QUADS, // regular
|
||||
PatchDescriptor::GREGORY_BASIS, // Gregory
|
||||
PatchDescriptor::QUADS, // linear
|
||||
PatchDescriptor::NON_PATCH }; // Bezier -- for future use
|
||||
};
|
||||
|
||||
BilinearPatchBuilder::BilinearPatchBuilder(
|
||||
TopologyRefiner const& refiner, Options const& options) :
|
||||
PatchBuilder(refiner, options) {
|
||||
|
||||
_regPatchType = patchTypeFromBasisArray[_options.regBasisType];
|
||||
_irregPatchType = (_options.irregBasisType == BASIS_UNSPECIFIED)
|
||||
? _regPatchType
|
||||
: patchTypeFromBasisArray[_options.irregBasisType];
|
||||
|
||||
_nativePatchType = PatchDescriptor::QUADS;
|
||||
_linearPatchType = PatchDescriptor::QUADS;
|
||||
}
|
||||
|
||||
BilinearPatchBuilder::~BilinearPatchBuilder() {
|
||||
}
|
||||
|
||||
PatchDescriptor::Type
|
||||
BilinearPatchBuilder::patchTypeFromBasis(BasisType basis) const {
|
||||
|
||||
return patchTypeFromBasisArray[(int)basis];
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
int
|
||||
BilinearPatchBuilder::convertSourcePatch(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<REAL> & matrix) const {
|
||||
|
||||
assert("Conversion from Bilinear patches to other bases not yet supported" == 0);
|
||||
|
||||
// For suppressing warnings until implemented...
|
||||
if (sourcePatch.GetNumSourcePoints() == 0) return -1;
|
||||
if (patchType == PatchDescriptor::NON_PATCH) return -1;
|
||||
if (matrix.GetNumRows() <= 0) return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
BilinearPatchBuilder::convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<float> & matrix) const {
|
||||
return convertSourcePatch(sourcePatch, patchType, matrix);
|
||||
}
|
||||
int
|
||||
BilinearPatchBuilder::convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<double> & matrix) const {
|
||||
return convertSourcePatch(sourcePatch, patchType, matrix);
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
73
src/osd/opensubdiv/far/bilinearPatchBuilder.h
Normal file
73
src/osd/opensubdiv/far/bilinearPatchBuilder.h
Normal file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// Copyright 2017 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_BILINEAR_PATCH_BUILDER_H
|
||||
#define OPENSUBDIV3_FAR_BILINEAR_PATCH_BUILDER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/patchBuilder.h"
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// BilinearPatchBuilder
|
||||
//
|
||||
// Declaration of PatchBuilder subclass supporting Sdc::SCHEME_BILINEAR.
|
||||
// Required virtual methods are included, along with any customizations
|
||||
// local to their implementation.
|
||||
//
|
||||
class BilinearPatchBuilder : public PatchBuilder {
|
||||
public:
|
||||
BilinearPatchBuilder(TopologyRefiner const& refiner, Options const& options);
|
||||
virtual ~BilinearPatchBuilder();
|
||||
|
||||
protected:
|
||||
virtual PatchDescriptor::Type patchTypeFromBasis(BasisType basis) const;
|
||||
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<float> & matrix) const;
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<double> & matrix) const;
|
||||
private:
|
||||
template <typename REAL>
|
||||
int convertSourcePatch(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<REAL> & matrix) const;
|
||||
};
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_BILINEAR_PATCH_BUILDER_H */
|
||||
2006
src/osd/opensubdiv/far/catmarkPatchBuilder.cpp
Normal file
2006
src/osd/opensubdiv/far/catmarkPatchBuilder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
76
src/osd/opensubdiv/far/catmarkPatchBuilder.h
Normal file
76
src/osd/opensubdiv/far/catmarkPatchBuilder.h
Normal file
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// Copyright 2017 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_CATMARK_PATCH_BUILDER_H
|
||||
#define OPENSUBDIV3_FAR_CATMARK_PATCH_BUILDER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/patchBuilder.h"
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// CatmarkPatchBuilder
|
||||
//
|
||||
// Declaration of PatchBuilder subclass supporting Sdc::SCHEME_CATMARK.
|
||||
// Required virtual methods are included, along with any customizations
|
||||
// local to their implementation.
|
||||
//
|
||||
class CatmarkPatchBuilder : public PatchBuilder {
|
||||
public:
|
||||
CatmarkPatchBuilder(TopologyRefiner const& refiner, Options const& options);
|
||||
virtual ~CatmarkPatchBuilder();
|
||||
|
||||
protected:
|
||||
virtual PatchDescriptor::Type patchTypeFromBasis(BasisType basis) const;
|
||||
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<float> & matrix) const;
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<double> & matrix) const;
|
||||
|
||||
private:
|
||||
typedef SparseMatrix<float> ConversionMatrix;
|
||||
|
||||
template <typename REAL>
|
||||
int convertSourcePatch(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<REAL> & matrix) const;
|
||||
};
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_CATMARK_PATCH_BUILDER_H */
|
||||
107
src/osd/opensubdiv/far/error.cpp
Normal file
107
src/osd/opensubdiv/far/error.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../far/error.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// Statics for the publicly assignable callbacks and the methods to
|
||||
// assign them (disable static assignment warnings when doing so):
|
||||
//
|
||||
static ErrorCallbackFunc errorFunc = 0;
|
||||
static WarningCallbackFunc warningFunc = 0;
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning disable 1711
|
||||
#endif
|
||||
|
||||
void SetErrorCallback(ErrorCallbackFunc func) {
|
||||
errorFunc = func;
|
||||
}
|
||||
|
||||
void SetWarningCallback(WarningCallbackFunc func) {
|
||||
warningFunc = func;
|
||||
}
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning enable 1711
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// The default error and warning callbacks eventually belong in the
|
||||
// internal namespace:
|
||||
//
|
||||
void Error(ErrorType err, const char *format, ...) {
|
||||
|
||||
static char const * errorTypeLabel[] = {
|
||||
"No Error",
|
||||
"Fatal Error",
|
||||
"Coding Error (internal)",
|
||||
"Coding Error",
|
||||
"Error"
|
||||
};
|
||||
|
||||
assert(err!=FAR_NO_ERROR);
|
||||
|
||||
char message[10240];
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
vsnprintf(message, 10240, format, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
if (errorFunc) {
|
||||
errorFunc(err, message);
|
||||
} else {
|
||||
printf("%s: %s\n", errorTypeLabel[err], message);
|
||||
}
|
||||
}
|
||||
|
||||
void Warning(const char *format, ...) {
|
||||
|
||||
char message[10240];
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
vsnprintf(message, 10240, format, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
if (warningFunc) {
|
||||
warningFunc(message);
|
||||
} else {
|
||||
fprintf(stdout, "Warning: %s\n", message);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
95
src/osd/opensubdiv/far/error.h
Normal file
95
src/osd/opensubdiv/far/error.h
Normal file
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_ERROR_H
|
||||
#define OPENSUBDIV3_FAR_ERROR_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
typedef enum {
|
||||
FAR_NO_ERROR, ///< No error. Move along.
|
||||
FAR_FATAL_ERROR, ///< Issue a fatal error and end the program.
|
||||
FAR_INTERNAL_CODING_ERROR, ///< Issue an internal programming error, but continue execution.
|
||||
FAR_CODING_ERROR, ///< Issue a generic programming error, but continue execution.
|
||||
FAR_RUNTIME_ERROR ///< Issue a generic runtime error, but continue execution.
|
||||
} ErrorType;
|
||||
|
||||
|
||||
/// \brief The error callback function type (default is "printf")
|
||||
typedef void (*ErrorCallbackFunc)(ErrorType err, const char *message);
|
||||
|
||||
/// \brief Sets the error callback function (default is "printf")
|
||||
///
|
||||
/// \note This function is not thread-safe !
|
||||
///
|
||||
/// @param func function pointer to the callback function
|
||||
///
|
||||
void SetErrorCallback(ErrorCallbackFunc func);
|
||||
|
||||
|
||||
/// \brief The warning callback function type (default is "printf")
|
||||
typedef void (*WarningCallbackFunc)(const char *message);
|
||||
|
||||
/// \brief Sets the warning callback function (default is "printf")
|
||||
///
|
||||
/// \note This function is not thread-safe !
|
||||
///
|
||||
/// @param func function pointer to the callback function
|
||||
///
|
||||
void SetWarningCallback(WarningCallbackFunc func);
|
||||
|
||||
|
||||
//
|
||||
// The following are intended for internal use only (and will eventually
|
||||
// be moved within namespace internal)
|
||||
//
|
||||
|
||||
/// \brief Sends an OSD error with a message (internal use only)
|
||||
///
|
||||
/// @param err the error type
|
||||
///
|
||||
/// @param format the format of the message (followed by arguments)
|
||||
///
|
||||
void Error(ErrorType err, const char *format, ...);
|
||||
|
||||
/// \brief Sends an OSD warning message (internal use only)
|
||||
///
|
||||
/// @param format the format of the message (followed by arguments)
|
||||
///
|
||||
void Warning(const char *format, ...);
|
||||
|
||||
|
||||
} // end namespace
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_FAR_ERROR_H
|
||||
1888
src/osd/opensubdiv/far/loopPatchBuilder.cpp
Normal file
1888
src/osd/opensubdiv/far/loopPatchBuilder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
73
src/osd/opensubdiv/far/loopPatchBuilder.h
Normal file
73
src/osd/opensubdiv/far/loopPatchBuilder.h
Normal file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// Copyright 2017 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_LOOP_PATCH_BUILDER_H
|
||||
#define OPENSUBDIV3_FAR_LOOP_PATCH_BUILDER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/patchBuilder.h"
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// LoopPatchBuilder
|
||||
//
|
||||
// Declaration of PatchBuilder subclass supporting Sdc::SCHEME_LOOP.
|
||||
// Required virtual methods are included, along with any customizations
|
||||
// local to their implementation.
|
||||
//
|
||||
class LoopPatchBuilder : public PatchBuilder {
|
||||
public:
|
||||
LoopPatchBuilder(TopologyRefiner const& refiner, Options const& options);
|
||||
virtual ~LoopPatchBuilder();
|
||||
|
||||
protected:
|
||||
virtual PatchDescriptor::Type patchTypeFromBasis(BasisType basis) const;
|
||||
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<float> & matrix) const;
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<double> & matrix) const;
|
||||
private:
|
||||
template <typename REAL>
|
||||
int convertSourcePatch(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<REAL> & matrix) const;
|
||||
};
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_LOOP_PATCH_BUILDER_H */
|
||||
1401
src/osd/opensubdiv/far/patchBasis.cpp
Normal file
1401
src/osd/opensubdiv/far/patchBasis.cpp
Normal file
File diff suppressed because it is too large
Load Diff
110
src/osd/opensubdiv/far/patchBasis.h
Normal file
110
src/osd/opensubdiv/far/patchBasis.h
Normal file
@@ -0,0 +1,110 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_PATCH_BASIS_H
|
||||
#define OPENSUBDIV3_FAR_PATCH_BASIS_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/patchParam.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
namespace internal {
|
||||
|
||||
//
|
||||
// XXXX barfowl: These functions are being kept internal while more complete
|
||||
// underlying support for all patch types is being worked out. The set of
|
||||
// bases supported here is actually larger than PatchDescriptor::Type -- with
|
||||
// Bezier available for internal use. A new and more complete set of types
|
||||
// is warranted (without the non-patch types associated with PatchDescriptor)
|
||||
// along with an interface to query properties associated with them.
|
||||
//
|
||||
// Note that with the high-level functions here that operate on all patch
|
||||
// types, it is not strictly necessary to expose the low-level methods in
|
||||
// currant usage.
|
||||
//
|
||||
|
||||
//
|
||||
// Low-level basis evaluation (normalized, unscaled) for quad patch types:
|
||||
//
|
||||
template <typename REAL>
|
||||
int EvalBasisLinear(REAL s, REAL t,
|
||||
REAL wP[4], REAL wDs[4] = 0, REAL wDt[4] = 0, REAL wDss[4] = 0, REAL wDst[4] = 0, REAL wDtt[4] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisBezier(REAL s, REAL t,
|
||||
REAL wP[16], REAL wDs[16] = 0, REAL wDt[16] = 0, REAL wDss[16] = 0, REAL wDst[16] = 0, REAL wDtt[16] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisBSpline(REAL s, REAL t,
|
||||
REAL wP[16], REAL wDs[16] = 0, REAL wDt[16] = 0, REAL wDss[16] = 0, REAL wDst[16] = 0, REAL wDtt[16] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisGregory(REAL s, REAL t,
|
||||
REAL wP[20], REAL wDs[20] = 0, REAL wDt[20] = 0, REAL wDss[20] = 0, REAL wDst[20] = 0, REAL wDtt[20] = 0);
|
||||
|
||||
//
|
||||
// Low-level basis evaluation (normalized, unscaled) for triangular patch types:
|
||||
//
|
||||
template <typename REAL>
|
||||
int EvalBasisLinearTri(REAL s, REAL t,
|
||||
REAL wP[3], REAL wDs[3] = 0, REAL wDt[3] = 0, REAL wDss[3] = 0, REAL wDst[3] = 0, REAL wDtt[3] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisBezierTri(REAL s, REAL t,
|
||||
REAL wP[15], REAL wDs[15] = 0, REAL wDt[15] = 0, REAL wDss[15] = 0, REAL wDst[15] = 0, REAL wDtt[15] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisBoxSplineTri(REAL s, REAL t,
|
||||
REAL wP[12], REAL wDs[12] = 0, REAL wDt[12] = 0, REAL wDss[12] = 0, REAL wDst[12] = 0, REAL wDtt[12] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisGregoryTri(REAL s, REAL t,
|
||||
REAL wP[18], REAL wDs[18] = 0, REAL wDt[18] = 0, REAL wDss[18] = 0, REAL wDst[18] = 0, REAL wDtt[18] = 0);
|
||||
|
||||
|
||||
//
|
||||
// High-level basis evaluation for all types using PatchParam:
|
||||
//
|
||||
template <typename REAL>
|
||||
int EvaluatePatchBasisNormalized(int patchType, PatchParam const & param, REAL s, REAL t,
|
||||
REAL wP[], REAL wDs[] = 0, REAL wDt[] = 0, REAL wDss[] = 0, REAL wDst[] = 0, REAL wDtt[] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvaluatePatchBasis(int patchType, PatchParam const & param, REAL s, REAL t,
|
||||
REAL wP[], REAL wDs[] = 0, REAL wDt[] = 0, REAL wDss[] = 0, REAL wDst[] = 0, REAL wDtt[] = 0);
|
||||
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PATCH_BASIS_H */
|
||||
1624
src/osd/opensubdiv/far/patchBuilder.cpp
Normal file
1624
src/osd/opensubdiv/far/patchBuilder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
332
src/osd/opensubdiv/far/patchBuilder.h
Normal file
332
src/osd/opensubdiv/far/patchBuilder.h
Normal file
@@ -0,0 +1,332 @@
|
||||
//
|
||||
// Copyright 2017 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_PATCH_BUILDER_H
|
||||
#define OPENSUBDIV3_FAR_PATCH_BUILDER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../sdc/types.h"
|
||||
#include "../far/types.h"
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../far/patchDescriptor.h"
|
||||
#include "../far/patchParam.h"
|
||||
#include "../far/ptexIndices.h"
|
||||
#include "../far/sparseMatrix.h"
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// SourcePatch
|
||||
//
|
||||
// This is a local utility class that captures the full local topology of an
|
||||
// arbitrarily irregular patch, i.e. a patch which may have one or all corners
|
||||
// irregular. Given the topology at each corner the entire collection of
|
||||
// points involved is identified and oriented consistently.
|
||||
//
|
||||
// Note (barfowl):
|
||||
// This was originally a class internal to PatchBuilder, but there is some
|
||||
// redundancy between it and the Level::VSpan used more publicly to identify
|
||||
// irregular corner topology. Replacing VSpan with SourcePatch is now under
|
||||
// consideration, and doing so will impact its public/private interface (which
|
||||
// was left public to give PatchBuilder access).
|
||||
// A simpler constructor to initialize an instance given a set of Corners
|
||||
// would also be preferable if made more public (i.e. public for use within
|
||||
// the library, not exported to clients) -- eliminating the need for the
|
||||
// explicit initialization and required call to the Finalize() method that
|
||||
// the PatchBuilder currently performs internally.
|
||||
//
|
||||
class SourcePatch {
|
||||
public:
|
||||
struct Corner {
|
||||
Corner() { std::memset(this, 0, sizeof(Corner)); }
|
||||
|
||||
LocalIndex _numFaces; // valence of corner vertex
|
||||
LocalIndex _patchFace; // location of patch within incident faces
|
||||
|
||||
unsigned short _boundary : 1;
|
||||
unsigned short _sharp : 1;
|
||||
unsigned short _dart : 1;
|
||||
|
||||
// For internal bookkeeping -- consider hiding or moving elsewhere
|
||||
unsigned short _sharesWithPrev : 1;
|
||||
unsigned short _sharesWithNext : 1;
|
||||
unsigned short _val2Interior : 1;
|
||||
unsigned short _val2Adjacent : 1;
|
||||
};
|
||||
|
||||
public:
|
||||
SourcePatch() { std::memset(this, 0, sizeof(SourcePatch)); }
|
||||
~SourcePatch() { }
|
||||
|
||||
// To be called after all Corners have been initialized (hope to
|
||||
// replace this with alternative constructor at some point)
|
||||
void Finalize(int size3or4);
|
||||
|
||||
int GetNumSourcePoints() const { return _numSourcePoints; }
|
||||
int GetMaxValence() const { return _maxValence; }
|
||||
int GetMaxRingSize() const { return _maxRingSize; }
|
||||
|
||||
int GetCornerRingSize(int corner) const { return _ringSizes[corner]; }
|
||||
int GetCornerRingPoints(int corner, int points[]) const;
|
||||
|
||||
// public/private access needs to be reviewed when/if used more publicly
|
||||
//private:
|
||||
public:
|
||||
// The SourcePatch is fully defined by its Corner members
|
||||
Corner _corners[4];
|
||||
int _numCorners;
|
||||
|
||||
// Additional members (derived from Corners) to help assemble corner rings:
|
||||
int _numSourcePoints;
|
||||
int _maxValence;
|
||||
int _maxRingSize;
|
||||
|
||||
int _ringSizes[4];
|
||||
int _localRingSizes[4];
|
||||
int _localRingOffsets[4];
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// PatchBuilder
|
||||
//
|
||||
// This is the main class to assist the identification of limit surface
|
||||
// patches from faces in a TopologyRefiner for assembly into other, larger
|
||||
// datatypes.
|
||||
//
|
||||
// The PatchBuilder takes a const reference to a refiner and supports
|
||||
// arbitrarily refined hierarchies, i.e. it is not restricted to uniform or
|
||||
// adaptive refinement strategies and does not include any logic relating
|
||||
// to the origin of the hierarchy. It can associate a patch with any face
|
||||
// in the hierarchy (subject to a few minimum requirements) -- leaving the
|
||||
// decision as to which faces/patches are appropriate to its client.
|
||||
//
|
||||
// PatchBuilder is an abstract base class with a subclass derived to support
|
||||
// each subdivision scheme -- as such, construction relies on a factory
|
||||
// method to create an instance of the appropriate subclass. Only two pure
|
||||
// virtual methods are required (other than the required destructor):
|
||||
//
|
||||
// - determine the patch type for a subdivision scheme given a more
|
||||
// general basis specification (e.g. Bezier, Gregory, Linear, etc)
|
||||
//
|
||||
// - convert the vertices in the subdivision hierarchy into points of a
|
||||
// specified patch type, using computations specific to that scheme
|
||||
//
|
||||
// The base class handles the more general topological analysis that
|
||||
// determines the nature of a patch associated with each face -- providing
|
||||
// both queries to the client, along with more involved methods to extract
|
||||
// or convert data associated with the patches. There is no concrete "Patch"
|
||||
// class to which all clients would be required to conform. The queries and
|
||||
// data returned are provided for clients to assemble into patches or other
|
||||
// aggregates as they see fit.
|
||||
//
|
||||
// This is intended as an internal/private class for use within the library
|
||||
// for now -- possibly to be exported for use by clients when/if its
|
||||
// interface is appropriate and stable.
|
||||
//
|
||||
class PatchBuilder {
|
||||
public:
|
||||
//
|
||||
// A PatchBuilder is constructed given a patch "basis" rather than a
|
||||
// "type" to use with the subdivision scheme involved. The relevant
|
||||
// explicit patch types will be determined from the basis and scheme:
|
||||
//
|
||||
enum BasisType {
|
||||
BASIS_UNSPECIFIED,
|
||||
BASIS_REGULAR,
|
||||
BASIS_GREGORY,
|
||||
BASIS_LINEAR,
|
||||
BASIS_BEZIER // to be supported in future
|
||||
};
|
||||
|
||||
//
|
||||
// Required Options specify a patch basis to use for both regular and
|
||||
// irregular patches -- sparing the client the need to repeatedly
|
||||
// specify these for each face considered. Other options are included
|
||||
// to support legacy approximations:
|
||||
//
|
||||
struct Options {
|
||||
Options() : regBasisType(BASIS_UNSPECIFIED),
|
||||
irregBasisType(BASIS_UNSPECIFIED),
|
||||
fillMissingBoundaryPoints(false),
|
||||
approxInfSharpWithSmooth(false),
|
||||
approxSmoothCornerWithSharp(false) { }
|
||||
|
||||
BasisType regBasisType;
|
||||
BasisType irregBasisType;
|
||||
bool fillMissingBoundaryPoints;
|
||||
bool approxInfSharpWithSmooth;
|
||||
bool approxSmoothCornerWithSharp;
|
||||
};
|
||||
|
||||
public:
|
||||
//
|
||||
// Public construction (via factory method) and destruction:
|
||||
//
|
||||
static PatchBuilder* Create(TopologyRefiner const& refiner,
|
||||
Options const& options);
|
||||
virtual ~PatchBuilder();
|
||||
|
||||
//
|
||||
// High-level queries related to the subdivision scheme of the refiner, the
|
||||
// patch types associated with it and those chosen to represent its faces:
|
||||
//
|
||||
int GetRegularFaceSize() const { return _schemeRegFaceSize; }
|
||||
|
||||
BasisType GetRegularBasisType() const { return _options.regBasisType; }
|
||||
BasisType GetIrregularBasisType() const { return _options.irregBasisType; }
|
||||
|
||||
PatchDescriptor::Type GetRegularPatchType() const { return _regPatchType; }
|
||||
PatchDescriptor::Type GetIrregularPatchType() const { return _irregPatchType; }
|
||||
|
||||
PatchDescriptor::Type GetNativePatchType() const { return _nativePatchType; }
|
||||
PatchDescriptor::Type GetLinearPatchType() const { return _linearPatchType; }
|
||||
|
||||
//
|
||||
// Face-level queries to determine presence of patches:
|
||||
//
|
||||
bool IsFaceAPatch(int level, Index face) const;
|
||||
bool IsFaceALeaf(int level, Index face) const;
|
||||
|
||||
//
|
||||
// Patch-level topological queries:
|
||||
//
|
||||
bool IsPatchRegular(int level, Index face, int fvc = -1) const;
|
||||
|
||||
int GetRegularPatchBoundaryMask(int level, Index face, int fvc = -1) const;
|
||||
|
||||
void GetIrregularPatchCornerSpans(int level, Index face,
|
||||
Vtr::internal::Level::VSpan cornerSpans[4], int fvc = -1) const;
|
||||
|
||||
bool DoesFaceVaryingPatchMatch(int level, Index face, int fvc) const {
|
||||
return _refiner.getLevel(level).doesFaceFVarTopologyMatch(face, fvc);
|
||||
}
|
||||
|
||||
//
|
||||
// Patch-level control point retrieval and methods for converting source
|
||||
// points to a set of local points in a different basis
|
||||
//
|
||||
int GetRegularPatchPoints(int level, Index face,
|
||||
int regBoundaryMask, // compute internally when < 0
|
||||
Index patchPoints[],
|
||||
int fvc = -1) const;
|
||||
|
||||
template <typename REAL>
|
||||
int GetIrregularPatchConversionMatrix(int level, Index face,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
SparseMatrix<REAL> & matrix) const;
|
||||
|
||||
int GetIrregularPatchSourcePoints(int level, Index face,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
Index sourcePoints[],
|
||||
int fvc = -1) const;
|
||||
//
|
||||
// Queries related to "single-crease" patches -- currently a subset of
|
||||
// regular interior patches:
|
||||
//
|
||||
struct SingleCreaseInfo {
|
||||
int creaseEdgeInFace;
|
||||
float creaseSharpness;
|
||||
};
|
||||
bool IsRegularSingleCreasePatch(int level, Index face,
|
||||
SingleCreaseInfo & info) const;
|
||||
|
||||
//
|
||||
// Computing the PatchParam -- note the regrettable dependency on
|
||||
// PtexIndices but PatchParam is essentially tied to it indefinitely.
|
||||
// Better to pass it in than have the PatchBuilder build its own
|
||||
// PtexIndices.
|
||||
//
|
||||
// Consider creating a PatchParamFactory which can manage the PtexIndices
|
||||
// along with this method. It will then be able to generate additional
|
||||
// data to accelerate these computations.
|
||||
//
|
||||
PatchParam ComputePatchParam(int level, Index face,
|
||||
PtexIndices const& ptexIndices, bool isRegular = true,
|
||||
int boundaryMask = 0, bool computeTransitionMask = false) const;
|
||||
|
||||
protected:
|
||||
PatchBuilder(TopologyRefiner const& refiner, Options const& options);
|
||||
|
||||
// Internal methods supporting topology queries:
|
||||
int getRegularFacePoints(int level, Index face,
|
||||
Index patchPoints[], int fvc) const;
|
||||
|
||||
int getQuadRegularPatchPoints(int level, Index face,
|
||||
int regBoundaryMask, Index patchPoints[], int fvc) const;
|
||||
|
||||
int getTriRegularPatchPoints(int level, Index face,
|
||||
int regBoundaryMask, Index patchPoints[], int fvc) const;
|
||||
|
||||
// Internal methods using the SourcePatch:
|
||||
int assembleIrregularSourcePatch(int level, Index face,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
SourcePatch & sourcePatch) const;
|
||||
|
||||
int gatherIrregularSourcePoints(int level, Index face,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
SourcePatch & sourcePatch,
|
||||
Index patchPoints[], int fvc) const;
|
||||
|
||||
protected:
|
||||
//
|
||||
// Virtual methods to be provided by subclass for each scheme:
|
||||
//
|
||||
virtual PatchDescriptor::Type patchTypeFromBasis(BasisType basis) const = 0;
|
||||
|
||||
// Note overloading of the conversion for SparseMatrix<REAL>:
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<float> & matrix) const = 0;
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<double> & matrix) const = 0;
|
||||
|
||||
protected:
|
||||
TopologyRefiner const& _refiner;
|
||||
Options const _options;
|
||||
|
||||
Sdc::SchemeType _schemeType;
|
||||
int _schemeRegFaceSize;
|
||||
bool _schemeIsLinear;
|
||||
|
||||
PatchDescriptor::Type _regPatchType;
|
||||
PatchDescriptor::Type _irregPatchType;
|
||||
PatchDescriptor::Type _nativePatchType;
|
||||
PatchDescriptor::Type _linearPatchType;
|
||||
};
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PATCH_BUILDER_H */
|
||||
92
src/osd/opensubdiv/far/patchDescriptor.cpp
Normal file
92
src/osd/opensubdiv/far/patchDescriptor.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../far/patchDescriptor.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Lists of valid patch Descriptors for each subdivision scheme
|
||||
//
|
||||
// Historically this has only included the non-linear patch types, though
|
||||
// it is possible for linear patches to represent irregularities for both
|
||||
// Catmark and Loop, and the Bilinear scheme is adaptively refined into
|
||||
// linear quads (e.g. a pentagon becoming five quads).
|
||||
//
|
||||
|
||||
ConstPatchDescriptorArray
|
||||
PatchDescriptor::GetAdaptivePatchDescriptors(Sdc::SchemeType type) {
|
||||
|
||||
static PatchDescriptor _loopDescriptors[] = {
|
||||
PatchDescriptor(LOOP),
|
||||
PatchDescriptor(GREGORY_TRIANGLE),
|
||||
};
|
||||
|
||||
static PatchDescriptor _catmarkDescriptors[] = {
|
||||
PatchDescriptor(REGULAR),
|
||||
PatchDescriptor(GREGORY),
|
||||
PatchDescriptor(GREGORY_BOUNDARY),
|
||||
PatchDescriptor(GREGORY_BASIS),
|
||||
};
|
||||
|
||||
switch (type) {
|
||||
case Sdc::SCHEME_BILINEAR :
|
||||
return ConstPatchDescriptorArray(0, 0);
|
||||
case Sdc::SCHEME_CATMARK :
|
||||
return ConstPatchDescriptorArray(_catmarkDescriptors,
|
||||
(int)(sizeof(_catmarkDescriptors)/sizeof(PatchDescriptor)));
|
||||
case Sdc::SCHEME_LOOP :
|
||||
return ConstPatchDescriptorArray(_loopDescriptors,
|
||||
(int)(sizeof(_loopDescriptors)/sizeof(PatchDescriptor)));
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return ConstPatchDescriptorArray(0, 0);;
|
||||
}
|
||||
|
||||
void
|
||||
PatchDescriptor::print() const {
|
||||
static char const * types[13] = {
|
||||
"NON_PATCH", "POINTS", "LINES", "QUADS", "TRIANGLES", "LOOP",
|
||||
"REGULAR", "GREGORY", "GREGORY_BOUNDARY", "GREGORY_BASIS",
|
||||
"GREGORY_TRIANGLE"};
|
||||
|
||||
printf(" type %s\n",
|
||||
types[_type]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
187
src/osd/opensubdiv/far/patchDescriptor.h
Normal file
187
src/osd/opensubdiv/far/patchDescriptor.h
Normal file
@@ -0,0 +1,187 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_PATCH_DESCRIPTOR_H
|
||||
#define OPENSUBDIV3_FAR_PATCH_DESCRIPTOR_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/types.h"
|
||||
#include "../sdc/types.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
/// \brief Describes the type of a patch
|
||||
///
|
||||
/// Uniquely identifies all the different types of patches
|
||||
///
|
||||
class PatchDescriptor {
|
||||
|
||||
public:
|
||||
|
||||
enum Type {
|
||||
NON_PATCH = 0, ///< undefined
|
||||
|
||||
POINTS, ///< points (useful for cage drawing)
|
||||
LINES, ///< lines (useful for cage drawing)
|
||||
|
||||
QUADS, ///< 4-sided quadrilateral (bilinear)
|
||||
TRIANGLES, ///< 3-sided triangle
|
||||
|
||||
LOOP, ///< regular triangular patch for the Loop scheme
|
||||
|
||||
REGULAR, ///< regular B-Spline patch for the Catmark scheme
|
||||
GREGORY,
|
||||
GREGORY_BOUNDARY,
|
||||
GREGORY_BASIS,
|
||||
GREGORY_TRIANGLE
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Default constructor.
|
||||
PatchDescriptor() :
|
||||
_type(NON_PATCH) { }
|
||||
|
||||
/// \brief Constructor
|
||||
PatchDescriptor(int type) :
|
||||
_type(type) { }
|
||||
|
||||
/// \brief Copy Constructor
|
||||
PatchDescriptor( PatchDescriptor const & d ) :
|
||||
_type(d.GetType()) { }
|
||||
|
||||
/// \brief Returns the type of the patch
|
||||
Type GetType() const {
|
||||
return (Type)_type;
|
||||
}
|
||||
|
||||
/// \brief Returns true if the type is an adaptive (non-linear) patch
|
||||
static inline bool IsAdaptive(Type type) {
|
||||
return type > TRIANGLES;
|
||||
}
|
||||
|
||||
/// \brief Returns true if the type is an adaptive patch
|
||||
bool IsAdaptive() const {
|
||||
return IsAdaptive( this->GetType() );
|
||||
}
|
||||
|
||||
/// \brief Returns the number of control vertices expected for a patch of the
|
||||
/// type described
|
||||
static inline short GetNumControlVertices( Type t );
|
||||
|
||||
/// \brief Deprecated @see PatchDescriptor#GetNumControlVertices
|
||||
static inline short GetNumFVarControlVertices( Type t );
|
||||
|
||||
/// \brief Returns the number of control vertices expected for a patch of the
|
||||
/// type described
|
||||
short GetNumControlVertices() const {
|
||||
return GetNumControlVertices( this->GetType() );
|
||||
}
|
||||
|
||||
/// \brief Deprecated @see PatchDescriptor#GetNumControlVertices
|
||||
short GetNumFVarControlVertices() const {
|
||||
return GetNumFVarControlVertices( this->GetType() );
|
||||
}
|
||||
|
||||
/// \brief Number of control vertices of Regular Patches in table.
|
||||
static short GetRegularPatchSize() { return 16; }
|
||||
|
||||
/// \brief Number of control vertices of Gregory (and Gregory Boundary) Patches in table.
|
||||
static short GetGregoryPatchSize() { return 4; }
|
||||
|
||||
/// \brief Number of control vertices of Gregory patch basis (20)
|
||||
static short GetGregoryBasisPatchSize() { return 20; }
|
||||
|
||||
|
||||
/// \brief Returns a vector of all the legal patch descriptors for the
|
||||
/// given adaptive subdivision scheme
|
||||
static Vtr::ConstArray<PatchDescriptor> GetAdaptivePatchDescriptors(Sdc::SchemeType type);
|
||||
|
||||
/// \brief Allows ordering of patches by type
|
||||
inline bool operator < ( PatchDescriptor const other ) const;
|
||||
|
||||
/// \brief True if the descriptors are identical
|
||||
inline bool operator == ( PatchDescriptor const other ) const;
|
||||
|
||||
// debug helper
|
||||
void print() const;
|
||||
|
||||
private:
|
||||
unsigned int _type;
|
||||
};
|
||||
|
||||
typedef Vtr::ConstArray<PatchDescriptor> ConstPatchDescriptorArray;
|
||||
|
||||
// Returns the number of control vertices expected for a patch of this type
|
||||
inline short
|
||||
PatchDescriptor::GetNumControlVertices( Type type ) {
|
||||
switch (type) {
|
||||
case REGULAR : return GetRegularPatchSize();
|
||||
case LOOP : return 12;
|
||||
case QUADS : return 4;
|
||||
case GREGORY :
|
||||
case GREGORY_BOUNDARY : return GetGregoryPatchSize();
|
||||
case GREGORY_BASIS : return GetGregoryBasisPatchSize();
|
||||
case GREGORY_TRIANGLE : return 18;
|
||||
case TRIANGLES : return 3;
|
||||
case LINES : return 2;
|
||||
case POINTS : return 1;
|
||||
default : return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the number of face-varying control vertices expected for a patch of this type
|
||||
inline short
|
||||
PatchDescriptor::GetNumFVarControlVertices( Type type ) {
|
||||
return PatchDescriptor::GetNumControlVertices(type);
|
||||
}
|
||||
|
||||
// Allows ordering of patches by type
|
||||
inline bool
|
||||
PatchDescriptor::operator < ( PatchDescriptor const other ) const {
|
||||
return (_type < other._type);
|
||||
}
|
||||
|
||||
// True if the descriptors are identical
|
||||
inline bool
|
||||
PatchDescriptor::operator == ( PatchDescriptor const other ) const {
|
||||
return _type == other._type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PATCH_DESCRIPTOR_H */
|
||||
207
src/osd/opensubdiv/far/patchMap.cpp
Normal file
207
src/osd/opensubdiv/far/patchMap.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../far/patchMap.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// Inline quadtree assembly methods used by the constructor:
|
||||
//
|
||||
|
||||
// sets all the children to point to the patch of given index
|
||||
inline void
|
||||
PatchMap::QuadNode::SetChildren(int index) {
|
||||
|
||||
for (int i=0; i<4; ++i) {
|
||||
children[i].isSet = true;
|
||||
children[i].isLeaf = true;
|
||||
children[i].index = index;
|
||||
}
|
||||
}
|
||||
|
||||
// sets the child in "quadrant" to point to the node or patch of the given index
|
||||
inline void
|
||||
PatchMap::QuadNode::SetChild(int quadrant, int index, bool isLeaf) {
|
||||
|
||||
assert(!children[quadrant].isSet);
|
||||
children[quadrant].isSet = true;
|
||||
children[quadrant].isLeaf = isLeaf;
|
||||
children[quadrant].index = index;
|
||||
}
|
||||
|
||||
inline void
|
||||
PatchMap::assignRootNode(QuadNode * node, int index) {
|
||||
|
||||
// Assign the given index to all children of the node (all leaves)
|
||||
node->SetChildren(index);
|
||||
}
|
||||
|
||||
inline PatchMap::QuadNode *
|
||||
PatchMap::assignLeafOrChildNode(QuadNode * node, bool isLeaf, int quadrant, int index) {
|
||||
|
||||
// Assign the node given if it is a leaf node, otherwise traverse
|
||||
// the node -- creating/assigning a new child node if needed
|
||||
|
||||
if (isLeaf) {
|
||||
node->SetChild(quadrant, index, true);
|
||||
return node;
|
||||
}
|
||||
if (node->children[quadrant].isSet) {
|
||||
return &_quadtree[node->children[quadrant].index];
|
||||
} else {
|
||||
int newChildNodeIndex = (int)_quadtree.size();
|
||||
_quadtree.push_back(QuadNode());
|
||||
node->SetChild(quadrant, newChildNodeIndex, false);
|
||||
return &_quadtree[newChildNodeIndex];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Constructor and initialization methods for the handles and quadtree:
|
||||
//
|
||||
PatchMap::PatchMap(PatchTable const & patchTable) :
|
||||
_minPatchFace(-1), _maxPatchFace(-1), _maxDepth(0) {
|
||||
|
||||
_patchesAreTriangular =
|
||||
patchTable.GetVaryingPatchDescriptor().GetNumControlVertices() == 3;
|
||||
|
||||
if (patchTable.GetNumPatchesTotal() > 0) {
|
||||
initializeHandles(patchTable);
|
||||
initializeQuadtree(patchTable);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PatchMap::initializeHandles(PatchTable const & patchTable) {
|
||||
|
||||
//
|
||||
// Populate the vector of patch Handles. Keep track of the min and max
|
||||
// face indices to allocate resources accordingly and limit queries:
|
||||
//
|
||||
_minPatchFace = (int) patchTable.GetPatchParamTable()[0].GetFaceId();
|
||||
_maxPatchFace = _minPatchFace;
|
||||
|
||||
int numArrays = (int) patchTable.GetNumPatchArrays();
|
||||
int numPatches = (int) patchTable.GetNumPatchesTotal();
|
||||
|
||||
_handles.resize(numPatches);
|
||||
|
||||
for (int pArray = 0, handleIndex = 0; pArray < numArrays; ++pArray) {
|
||||
|
||||
ConstPatchParamArray params = patchTable.GetPatchParams(pArray);
|
||||
|
||||
int patchSize = patchTable.GetPatchArrayDescriptor(pArray).GetNumControlVertices();
|
||||
|
||||
for (Index j=0; j < patchTable.GetNumPatches(pArray); ++j, ++handleIndex) {
|
||||
|
||||
Handle & h = _handles[handleIndex];
|
||||
|
||||
h.arrayIndex = pArray;
|
||||
h.patchIndex = handleIndex;
|
||||
h.vertIndex = j * patchSize;
|
||||
|
||||
int patchFaceId = params[j].GetFaceId();
|
||||
_minPatchFace = std::min(_minPatchFace, patchFaceId);
|
||||
_maxPatchFace = std::max(_maxPatchFace, patchFaceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PatchMap::initializeQuadtree(PatchTable const & patchTable) {
|
||||
|
||||
//
|
||||
// Reserve quadtree nodes for the worst case and prune later. Set the
|
||||
// initial size to accomodate the root node of each patch face:
|
||||
//
|
||||
int nPatchFaces = (_maxPatchFace - _minPatchFace) + 1;
|
||||
|
||||
int nHandles = (int)_handles.size();
|
||||
|
||||
_quadtree.reserve(nPatchFaces + nHandles);
|
||||
_quadtree.resize(nPatchFaces);
|
||||
|
||||
PatchParamTable const & params = patchTable.GetPatchParamTable();
|
||||
|
||||
for (int handle = 0; handle < nHandles; ++handle) {
|
||||
|
||||
PatchParam const & param = params[handle];
|
||||
|
||||
int depth = param.GetDepth();
|
||||
int rootDepth = param.NonQuadRoot();
|
||||
|
||||
_maxDepth = std::max(_maxDepth, depth);
|
||||
|
||||
QuadNode * node = &_quadtree[param.GetFaceId() - _minPatchFace];
|
||||
|
||||
if (depth == rootDepth) {
|
||||
assignRootNode(node, handle);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_patchesAreTriangular) {
|
||||
// Use the UV bits of the PatchParam directly for quad patches:
|
||||
int u = param.GetU();
|
||||
int v = param.GetV();
|
||||
|
||||
for (int j = rootDepth + 1; j <= depth; ++j) {
|
||||
int uBit = (u >> (depth - j)) & 1;
|
||||
int vBit = (v >> (depth - j)) & 1;
|
||||
|
||||
int quadrant = (vBit << 1) | uBit;
|
||||
|
||||
node = assignLeafOrChildNode(node, (j == depth), quadrant, handle);
|
||||
}
|
||||
} else {
|
||||
// Use an interior UV point of triangles to identify quadrants:
|
||||
double u = 0.25;
|
||||
double v = 0.25;
|
||||
param.UnnormalizeTriangle(u, v);
|
||||
|
||||
double median = 0.5;
|
||||
bool triRotated = false;
|
||||
|
||||
for (int j = rootDepth + 1; j <= depth; ++j, median *= 0.5) {
|
||||
int quadrant = transformUVToTriQuadrant(median, u, v, triRotated);
|
||||
|
||||
node = assignLeafOrChildNode(node, (j == depth), quadrant, handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Swap the Node vector with a copy to reduce worst case memory allocation:
|
||||
QuadTree tmpTree = _quadtree;
|
||||
_quadtree.swap(tmpTree);
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
240
src/osd/opensubdiv/far/patchMap.h
Normal file
240
src/osd/opensubdiv/far/patchMap.h
Normal file
@@ -0,0 +1,240 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_PATCH_MAP_H
|
||||
#define OPENSUBDIV3_FAR_PATCH_MAP_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/patchTable.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
/// \brief An quadtree-based map connecting coarse faces to their sub-patches
|
||||
///
|
||||
/// PatchTable::PatchArrays contain lists of patches that represent the limit
|
||||
/// surface of a mesh, sorted by their topological type. These arrays break the
|
||||
/// connection between coarse faces and their sub-patches.
|
||||
///
|
||||
/// The PatchMap provides a quad-tree based lookup structure that, given a singular
|
||||
/// parametric location, can efficiently return a handle to the sub-patch that
|
||||
/// contains this location.
|
||||
///
|
||||
class PatchMap {
|
||||
public:
|
||||
|
||||
typedef PatchTable::PatchHandle Handle;
|
||||
|
||||
/// \brief Constructor
|
||||
///
|
||||
/// @param patchTable A valid PatchTable
|
||||
///
|
||||
PatchMap( PatchTable const & patchTable );
|
||||
|
||||
/// \brief Returns a handle to the sub-patch of the face at the given (u,v).
|
||||
/// Note that the patch face ID corresponds to potentially quadrangulated
|
||||
/// face indices and not the base face indices (see Far::PtexIndices for more
|
||||
/// details).
|
||||
///
|
||||
/// @param patchFaceId The index of the patch (Ptex) face
|
||||
///
|
||||
/// @param u Local u parameter
|
||||
///
|
||||
/// @param v Local v parameter
|
||||
///
|
||||
/// @return A patch handle or 0 if the face is not supported (index
|
||||
/// out of bounds) or is tagged as a hole
|
||||
///
|
||||
Handle const * FindPatch( int patchFaceId, double u, double v ) const;
|
||||
|
||||
private:
|
||||
void initializeHandles(PatchTable const & patchTable);
|
||||
void initializeQuadtree(PatchTable const & patchTable);
|
||||
|
||||
private:
|
||||
// Quadtree node with 4 children, tree is just a vector of nodes
|
||||
struct QuadNode {
|
||||
QuadNode() { std::memset(this, 0, sizeof(QuadNode)); }
|
||||
|
||||
struct Child {
|
||||
unsigned int isSet : 1; // true if the child has been set
|
||||
unsigned int isLeaf : 1; // true if the child is a QuadNode
|
||||
unsigned int index : 30; // child index (either QuadNode or Handle)
|
||||
};
|
||||
|
||||
// sets all the children to point to the patch of given index
|
||||
void SetChildren(int index);
|
||||
|
||||
// sets the child in "quadrant" to point to the node or patch of the given index
|
||||
void SetChild(int quadrant, int index, bool isLeaf);
|
||||
|
||||
Child children[4];
|
||||
};
|
||||
typedef std::vector<QuadNode> QuadTree;
|
||||
|
||||
// Internal methods supporting quadtree construction and queries
|
||||
void assignRootNode(QuadNode * node, int index);
|
||||
QuadNode * assignLeafOrChildNode(QuadNode * node, bool isLeaf, int quad, int index);
|
||||
|
||||
template <class T>
|
||||
static int transformUVToQuadQuadrant(T const & median, T & u, T & v);
|
||||
template <class T>
|
||||
static int transformUVToTriQuadrant(T const & median, T & u, T & v, bool & rotated);
|
||||
|
||||
private:
|
||||
bool _patchesAreTriangular; // tri and quad assembly and search requirements differ
|
||||
|
||||
int _minPatchFace; // minimum patch face index supported by the map
|
||||
int _maxPatchFace; // maximum patch face index supported by the map
|
||||
int _maxDepth; // maximum depth of a patch in the tree
|
||||
|
||||
std::vector<Handle> _handles; // all the patches in the PatchTable
|
||||
std::vector<QuadNode> _quadtree; // quadtree nodes
|
||||
};
|
||||
|
||||
//
|
||||
// Given a median value for both U and V, these methods transform a (u,v) pair
|
||||
// into the quadrant that contains them and returns the quadrant index.
|
||||
//
|
||||
// Quadrant indexing for tri and quad patches -- consistent with PatchParam's
|
||||
// usage of UV bits:
|
||||
//
|
||||
// (0,1) o-----o-----o (1,1) (0,1) o (1,0) o-----o-----o (0,0)
|
||||
// | | | |\ \ 1 |\ 0 |
|
||||
// | 2 | 3 | | \ \ | \ |
|
||||
// | | | | 2 \ \| 3 \|
|
||||
// o-----o-----o o-----o o-----o
|
||||
// | | | |\ 3 |\ \ 2 |
|
||||
// | 0 | 1 | | \ | \ \ |
|
||||
// | | | | 0 \| 1 \ \|
|
||||
// (0,0) o-----o-----o (1,0) (0,0) o-----o-----o (1,0) o (0,1)
|
||||
//
|
||||
// The triangular case also takes and returns/affects the rotation of the
|
||||
// quadrant being searched and identified (quadrant 3 imparts a rotation).
|
||||
//
|
||||
template <class T>
|
||||
inline int
|
||||
PatchMap::transformUVToQuadQuadrant(T const & median, T & u, T & v) {
|
||||
|
||||
int uHalf = (u >= median);
|
||||
if (uHalf) u -= median;
|
||||
|
||||
int vHalf = (v >= median);
|
||||
if (vHalf) v -= median;
|
||||
|
||||
return (vHalf << 1) | uHalf;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int inline
|
||||
PatchMap::transformUVToTriQuadrant(T const & median, T & u, T & v, bool & rotated) {
|
||||
|
||||
if (!rotated) {
|
||||
if (u >= median) {
|
||||
u -= median;
|
||||
return 1;
|
||||
}
|
||||
if (v >= median) {
|
||||
v -= median;
|
||||
return 2;
|
||||
}
|
||||
if ((u + v) >= median) {
|
||||
rotated = true;
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
if (u < median) {
|
||||
v -= median;
|
||||
return 1;
|
||||
}
|
||||
if (v < median) {
|
||||
u -= median;
|
||||
return 2;
|
||||
}
|
||||
u -= median;
|
||||
v -= median;
|
||||
if ((u + v) < median) {
|
||||
rotated = false;
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a handle to the sub-patch of the face at the given (u,v).
|
||||
inline PatchMap::Handle const *
|
||||
PatchMap::FindPatch( int faceid, double u, double v ) const {
|
||||
|
||||
//
|
||||
// Reject patch faces not supported by this map, or those corresponding
|
||||
// to holes or otherwise unassigned (the root node for a patch will
|
||||
// have all or no quadrants set):
|
||||
//
|
||||
if ((faceid < _minPatchFace) || (faceid > _maxPatchFace)) return 0;
|
||||
|
||||
QuadNode const * node = &_quadtree[faceid - _minPatchFace];
|
||||
|
||||
if (!node->children[0].isSet) return 0;
|
||||
|
||||
//
|
||||
// Search the tree for the sub-patch containing the given (u,v)
|
||||
//
|
||||
assert( (u>=0.0) && (u<=1.0) && (v>=0.0) && (v<=1.0) );
|
||||
|
||||
double median = 0.5;
|
||||
bool triRotated = false;
|
||||
|
||||
for (int depth = 0; depth <= _maxDepth; ++depth, median *= 0.5) {
|
||||
|
||||
int quadrant = _patchesAreTriangular
|
||||
? transformUVToTriQuadrant(median, u, v, triRotated)
|
||||
: transformUVToQuadQuadrant(median, u, v);
|
||||
|
||||
// holes should have been rejected at the root node of the face
|
||||
assert(node->children[quadrant].isSet);
|
||||
|
||||
if (node->children[quadrant].isLeaf) {
|
||||
return &_handles[node->children[quadrant].index];
|
||||
} else {
|
||||
node = &_quadtree[node->children[quadrant].index];
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PATCH_PARAM */
|
||||
332
src/osd/opensubdiv/far/patchParam.h
Normal file
332
src/osd/opensubdiv/far/patchParam.h
Normal file
@@ -0,0 +1,332 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_PATCH_PARAM_H
|
||||
#define OPENSUBDIV3_FAR_PATCH_PARAM_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/types.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
/// \brief Patch parameterization
|
||||
///
|
||||
/// Topological refinement splits coarse mesh faces into refined faces.
|
||||
///
|
||||
/// This patch parameterzation describes the relationship between one
|
||||
/// of these refined faces and its corresponding coarse face. It is used
|
||||
/// both for refined faces that are represented as full limit surface
|
||||
/// parametric patches as well as for refined faces represented as simple
|
||||
/// triangles or quads. This parameterization is needed to interpolate
|
||||
/// primvar data across a refined face.
|
||||
///
|
||||
/// The U,V and refinement level parameters describe the scale and offset
|
||||
/// needed to map a location on the patch between levels of refinement.
|
||||
/// The encoding of these values exploits the quad-tree organization of
|
||||
/// the faces produced by subdivision. We encode the U,V origin of the
|
||||
/// patch using two 10-bit integer values and the refinement level as
|
||||
/// a 4-bit integer. This is sufficient to represent up through 10 levels
|
||||
/// of refinement.
|
||||
///
|
||||
/// Special consideration must be given to the refined faces resulting from
|
||||
/// irregular coarse faces. We adopt a convention similar to Ptex texture
|
||||
/// mapping and define the parameterization for these faces in terms of the
|
||||
/// regular faces resulting from the first topological splitting of the
|
||||
/// irregular coarse face.
|
||||
///
|
||||
/// When computing the basis functions needed to evaluate the limit surface
|
||||
/// parametric patch representing a refined face, we also need to know which
|
||||
/// edges of the patch are interpolated boundaries. These edges are encoded
|
||||
/// as a boundary bitmask identifying the boundary edges of the patch in
|
||||
/// sequential order starting from the first vertex of the refined face.
|
||||
///
|
||||
/// A sparse topological refinement (like feature adaptive refinement) can
|
||||
/// produce refined faces that are adjacent to faces at the next level of
|
||||
/// subdivision. We identify these transitional edges with a transition
|
||||
/// bitmask using the same encoding as the boundary bitmask.
|
||||
///
|
||||
/// For triangular subdivision schemes we specify the parameterization using
|
||||
/// a similar method. Alternate triangles at a given level of refinement
|
||||
/// are parameterized from their opposite corners and encoded as occupying
|
||||
/// the opposite diagonal of the quad-tree hierarchy. The third barycentric
|
||||
/// coordinate is dependent on and can be derived from the other two
|
||||
/// coordinates. This encoding also takes inspiration from the Ptex
|
||||
/// texture mapping specification.
|
||||
///
|
||||
/// Bitfield layout :
|
||||
///
|
||||
/// Field0 | Bits | Content
|
||||
/// -----------|:----:|------------------------------------------------------
|
||||
/// faceId | 28 | the faceId of the patch
|
||||
/// transition | 4 | transition edge mask encoding
|
||||
///
|
||||
/// Field1 | Bits | Content
|
||||
/// -----------|:----:|------------------------------------------------------
|
||||
/// level | 4 | the subdivision level of the patch
|
||||
/// nonquad | 1 | whether patch is refined from a non-quad face
|
||||
/// regular | 1 | whether patch is regular
|
||||
/// unused | 1 | unused
|
||||
/// boundary | 5 | boundary edge mask encoding
|
||||
/// v | 10 | log2 value of u parameter at first patch corner
|
||||
/// u | 10 | log2 value of v parameter at first patch corner
|
||||
///
|
||||
/// Note : the bitfield is not expanded in the struct due to differences in how
|
||||
/// GPU & CPU compilers pack bit-fields and endian-ness.
|
||||
///
|
||||
/*!
|
||||
\verbatim
|
||||
Quad Patch Parameterization
|
||||
|
||||
(0,1) (1,1)
|
||||
+-------+-------+---------------+
|
||||
| | | |
|
||||
| L2 | L2 | |
|
||||
|0,3 |1,3 | |
|
||||
+-------+-------+ L1 |
|
||||
| | | |
|
||||
| L2 | L2 | |
|
||||
|0,2 |1,2 |1,1 |
|
||||
+-------+-------+---------------+
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| L1 | L1 |
|
||||
| | |
|
||||
| | |
|
||||
|0,0 |1,0 |
|
||||
+---------------+---------------+
|
||||
(0,0) (1,0)
|
||||
\endverbatim
|
||||
*/
|
||||
/*!
|
||||
\verbatim
|
||||
Triangle Patch Parameterization
|
||||
|
||||
(0,1) (1,1) (0,1,0)
|
||||
+-------+-------+---------------+ +
|
||||
| \ | \ | \ | | \
|
||||
|L2 \ |L2 \ | \ | | \
|
||||
|0,3 \ |1,3 \ | \ | | L2 \
|
||||
+-------+-------+ \ | +-------+
|
||||
| \ | \ | L1 \ | | \ L2 | \
|
||||
|L2 \ |L2 \ | \ | | \ | \
|
||||
|0,2 \ |1,2 \ |1,1 \ | | L2 \ | L2 \
|
||||
+-------+-------+---------------+ +-------+-------+
|
||||
| \ | \ | | \ | \
|
||||
| \ | \ | | \ | \
|
||||
| \ | \ | | \ L1 | \
|
||||
| \ | \ | | \ | \
|
||||
| L1 \ | L1 \ | | L1 \ | L1 \
|
||||
| \ | \ | | \ | \
|
||||
|0,0 \ |1,0 \ | | \ | \
|
||||
+---------------+---------------+ +---------------+---------------+
|
||||
(0,0) (1,0) (0,0,1) (1,0,0)
|
||||
\endverbatim
|
||||
*/
|
||||
|
||||
struct PatchParam {
|
||||
/// \brief Sets the values of the bit fields
|
||||
///
|
||||
/// @param faceid face index
|
||||
///
|
||||
/// @param u value of the u parameter for the first corner of the face
|
||||
/// @param v value of the v parameter for the first corner of the face
|
||||
///
|
||||
/// @param depth subdivision level of the patch
|
||||
/// @param nonquad true if the root face is not a quad
|
||||
///
|
||||
/// @param boundary 5-bits identifying boundary edges (and verts for tris)
|
||||
/// @param transition 4-bits identifying transition edges
|
||||
///
|
||||
/// @param regular whether the patch is regular
|
||||
///
|
||||
void Set(Index faceid, short u, short v,
|
||||
unsigned short depth, bool nonquad,
|
||||
unsigned short boundary, unsigned short transition,
|
||||
bool regular = false);
|
||||
|
||||
/// \brief Resets everything to 0
|
||||
void Clear() { field0 = field1 = 0; }
|
||||
|
||||
/// \brief Returns the faceid
|
||||
Index GetFaceId() const { return Index(unpack(field0,28,0)); }
|
||||
|
||||
/// \brief Returns the log2 value of the u parameter at
|
||||
/// the first corner of the patch
|
||||
unsigned short GetU() const { return (unsigned short)unpack(field1,10,22); }
|
||||
|
||||
/// \brief Returns the log2 value of the v parameter at
|
||||
/// the first corner of the patch
|
||||
unsigned short GetV() const { return (unsigned short)unpack(field1,10,12); }
|
||||
|
||||
/// \brief Returns the transition edge encoding for the patch.
|
||||
unsigned short GetTransition() const { return (unsigned short)unpack(field0,4,28); }
|
||||
|
||||
/// \brief Returns the boundary edge encoding for the patch.
|
||||
unsigned short GetBoundary() const { return (unsigned short)unpack(field1,5,7); }
|
||||
|
||||
/// \brief True if the parent base face is a non-quad
|
||||
bool NonQuadRoot() const { return (unpack(field1,1,4) != 0); }
|
||||
|
||||
/// \brief Returns the level of subdivision of the patch
|
||||
unsigned short GetDepth() const { return (unsigned short)unpack(field1,4,0); }
|
||||
|
||||
/// \brief Returns the fraction of unit parametric space covered by this face.
|
||||
float GetParamFraction() const;
|
||||
|
||||
/// \brief A (u,v) pair in the fraction of parametric space covered by this
|
||||
/// face is mapped into a normalized parametric space.
|
||||
///
|
||||
/// @param u u parameter
|
||||
/// @param v v parameter
|
||||
///
|
||||
template <typename REAL>
|
||||
void Normalize( REAL & u, REAL & v ) const;
|
||||
template <typename REAL>
|
||||
void NormalizeTriangle( REAL & u, REAL & v ) const;
|
||||
|
||||
/// \brief A (u,v) pair in a normalized parametric space is mapped back into the
|
||||
/// fraction of parametric space covered by this face.
|
||||
///
|
||||
/// @param u u parameter
|
||||
/// @param v v parameter
|
||||
///
|
||||
template <typename REAL>
|
||||
void Unnormalize( REAL & u, REAL & v ) const;
|
||||
template <typename REAL>
|
||||
void UnnormalizeTriangle( REAL & u, REAL & v ) const;
|
||||
|
||||
/// \brief Returns if a triangular patch is parametrically rotated 180 degrees
|
||||
bool IsTriangleRotated() const;
|
||||
|
||||
/// \brief Returns whether the patch is regular
|
||||
bool IsRegular() const { return (unpack(field1,1,5) != 0); }
|
||||
|
||||
unsigned int field0:32;
|
||||
unsigned int field1:32;
|
||||
|
||||
private:
|
||||
unsigned int pack(unsigned int value, int width, int offset) const {
|
||||
return (unsigned int)((value & ((1<<width)-1)) << offset);
|
||||
}
|
||||
|
||||
unsigned int unpack(unsigned int value, int width, int offset) const {
|
||||
return (unsigned int)((value >> offset) & ((1<<width)-1));
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<PatchParam> PatchParamTable;
|
||||
|
||||
typedef Vtr::Array<PatchParam> PatchParamArray;
|
||||
typedef Vtr::ConstArray<PatchParam> ConstPatchParamArray;
|
||||
|
||||
inline void
|
||||
PatchParam::Set(Index faceid, short u, short v,
|
||||
unsigned short depth, bool nonquad,
|
||||
unsigned short boundary, unsigned short transition,
|
||||
bool regular) {
|
||||
field0 = pack(faceid, 28, 0) |
|
||||
pack(transition, 4, 28);
|
||||
|
||||
field1 = pack(u, 10, 22) |
|
||||
pack(v, 10, 12) |
|
||||
pack(boundary, 5, 7) |
|
||||
pack(regular, 1, 5) |
|
||||
pack(nonquad, 1, 4) |
|
||||
pack(depth, 4, 0);
|
||||
}
|
||||
|
||||
inline float
|
||||
PatchParam::GetParamFraction( ) const {
|
||||
return 1.0f / (float)(1 << (GetDepth() - NonQuadRoot()));
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
PatchParam::Normalize( REAL & u, REAL & v ) const {
|
||||
|
||||
REAL fracInv = (REAL)(1.0f / GetParamFraction());
|
||||
|
||||
u = u * fracInv - (REAL)GetU();
|
||||
v = v * fracInv - (REAL)GetV();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
PatchParam::Unnormalize( REAL & u, REAL & v ) const {
|
||||
|
||||
REAL frac = (REAL)GetParamFraction();
|
||||
|
||||
u = (u + (REAL)GetU()) * frac;
|
||||
v = (v + (REAL)GetV()) * frac;
|
||||
}
|
||||
|
||||
inline bool
|
||||
PatchParam::IsTriangleRotated() const {
|
||||
|
||||
return (GetU() + GetV()) >= (1 << GetDepth());
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
PatchParam::NormalizeTriangle( REAL & u, REAL & v ) const {
|
||||
|
||||
if (IsTriangleRotated()) {
|
||||
REAL fracInv = (REAL)(1.0f / GetParamFraction());
|
||||
|
||||
int depthFactor = 1 << GetDepth();
|
||||
u = (REAL)(depthFactor - GetU()) - (u * fracInv);
|
||||
v = (REAL)(depthFactor - GetV()) - (v * fracInv);
|
||||
} else {
|
||||
Normalize(u, v);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
PatchParam::UnnormalizeTriangle( REAL & u, REAL & v ) const {
|
||||
|
||||
if (IsTriangleRotated()) {
|
||||
REAL frac = GetParamFraction();
|
||||
|
||||
int depthFactor = 1 << GetDepth();
|
||||
u = ((REAL)(depthFactor - GetU()) - u) * frac;
|
||||
v = ((REAL)(depthFactor - GetV()) - v) * frac;
|
||||
} else {
|
||||
Unnormalize(u, v);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PATCH_PARAM */
|
||||
708
src/osd/opensubdiv/far/patchTable.cpp
Normal file
708
src/osd/opensubdiv/far/patchTable.cpp
Normal file
@@ -0,0 +1,708 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../far/patchTable.h"
|
||||
#include "../far/patchBasis.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
PatchTable::PatchTable(int maxvalence) :
|
||||
_maxValence(maxvalence),
|
||||
_localPointStencils(),
|
||||
_localPointVaryingStencils(),
|
||||
_varyingDesc(Far::PatchDescriptor::QUADS),
|
||||
_isUniformLinear(false),
|
||||
_vertexPrecisionIsDouble(false),
|
||||
_varyingPrecisionIsDouble(false),
|
||||
_faceVaryingPrecisionIsDouble(false) {
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
// XXXX manuelk we need to eliminate this constructor (C++11 smart pointers)
|
||||
PatchTable::PatchTable(PatchTable const & src) :
|
||||
_maxValence(src._maxValence),
|
||||
_numPtexFaces(src._numPtexFaces),
|
||||
_patchArrays(src._patchArrays),
|
||||
_patchVerts(src._patchVerts),
|
||||
_paramTable(src._paramTable),
|
||||
_quadOffsetsTable(src._quadOffsetsTable),
|
||||
_vertexValenceTable(src._vertexValenceTable),
|
||||
_localPointStencils(src._localPointStencils),
|
||||
_localPointVaryingStencils(src._localPointVaryingStencils),
|
||||
_varyingDesc(src._varyingDesc),
|
||||
_fvarChannels(src._fvarChannels),
|
||||
_sharpnessIndices(src._sharpnessIndices),
|
||||
_sharpnessValues(src._sharpnessValues),
|
||||
_isUniformLinear(src._isUniformLinear),
|
||||
_vertexPrecisionIsDouble(src._vertexPrecisionIsDouble),
|
||||
_varyingPrecisionIsDouble(src._varyingPrecisionIsDouble),
|
||||
_faceVaryingPrecisionIsDouble(src._faceVaryingPrecisionIsDouble) {
|
||||
|
||||
if (src._localPointStencils) {
|
||||
if (src._vertexPrecisionIsDouble) {
|
||||
_localPointStencils.Set(
|
||||
new StencilTableReal<double>(*src._localPointStencils.Get<double>()));
|
||||
} else {
|
||||
_localPointStencils.Set(
|
||||
new StencilTableReal<float>(*src._localPointStencils.Get<float>()));
|
||||
}
|
||||
}
|
||||
if (src._localPointVaryingStencils) {
|
||||
if (src._varyingPrecisionIsDouble) {
|
||||
_localPointVaryingStencils.Set(
|
||||
new StencilTableReal<double>(*src._localPointVaryingStencils.Get<double>()));
|
||||
} else {
|
||||
_localPointVaryingStencils.Set(
|
||||
new StencilTableReal<float>(*src._localPointVaryingStencils.Get<float>()));
|
||||
}
|
||||
}
|
||||
if (! src._localPointFaceVaryingStencils.empty()) {
|
||||
_localPointFaceVaryingStencils.resize(src._localPointFaceVaryingStencils.size());
|
||||
for (int fvc=0; fvc<(int)_localPointFaceVaryingStencils.size(); ++fvc) {
|
||||
if (src._localPointFaceVaryingStencils[fvc]) {
|
||||
if (src._faceVaryingPrecisionIsDouble) {
|
||||
_localPointFaceVaryingStencils[fvc].Set(new StencilTableReal<double>(
|
||||
*src._localPointFaceVaryingStencils[fvc].Get<double>()));
|
||||
} else {
|
||||
_localPointFaceVaryingStencils[fvc].Set(new StencilTableReal<float>(
|
||||
*src._localPointFaceVaryingStencils[fvc].Get<float>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PatchTable::~PatchTable() {
|
||||
if (_vertexPrecisionIsDouble) {
|
||||
delete _localPointStencils.Get<double>();
|
||||
} else {
|
||||
delete _localPointStencils.Get<float>();
|
||||
}
|
||||
|
||||
if (_varyingPrecisionIsDouble) {
|
||||
delete _localPointVaryingStencils.Get<double>();
|
||||
} else {
|
||||
delete _localPointVaryingStencils.Get<float>();
|
||||
}
|
||||
|
||||
for (int fvc=0; fvc<(int)_localPointFaceVaryingStencils.size(); ++fvc) {
|
||||
if (_faceVaryingPrecisionIsDouble) {
|
||||
delete _localPointFaceVaryingStencils[fvc].Get<double>();
|
||||
} else {
|
||||
delete _localPointFaceVaryingStencils[fvc].Get<float>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// PatchArrays
|
||||
//
|
||||
struct PatchTable::PatchArray {
|
||||
|
||||
PatchArray(PatchDescriptor d, int np, Index v, Index p, Index qo) :
|
||||
desc(d), numPatches(np), vertIndex(v),
|
||||
patchIndex(p), quadOffsetIndex (qo) { }
|
||||
|
||||
void print() const;
|
||||
|
||||
PatchDescriptor desc; // type of patches in the array
|
||||
|
||||
int numPatches; // number of patches in the array
|
||||
|
||||
Index vertIndex, // index to the first control vertex
|
||||
patchIndex, // absolute index of the first patch in the array
|
||||
quadOffsetIndex; // index of the first quad offset entry
|
||||
|
||||
};
|
||||
|
||||
// debug helper
|
||||
void
|
||||
PatchTable::PatchArray::print() const {
|
||||
desc.print();
|
||||
printf(" numPatches=%d vertIndex=%d patchIndex=%d "
|
||||
"quadOffsetIndex=%d\n", numPatches, vertIndex, patchIndex,
|
||||
quadOffsetIndex);
|
||||
}
|
||||
inline PatchTable::PatchArray &
|
||||
PatchTable::getPatchArray(Index arrayIndex) {
|
||||
assert(arrayIndex<(Index)GetNumPatchArrays());
|
||||
return _patchArrays[arrayIndex];
|
||||
}
|
||||
inline PatchTable::PatchArray const &
|
||||
PatchTable::getPatchArray(Index arrayIndex) const {
|
||||
assert(arrayIndex<(Index)GetNumPatchArrays());
|
||||
return _patchArrays[arrayIndex];
|
||||
}
|
||||
void
|
||||
PatchTable::reservePatchArrays(int numPatchArrays) {
|
||||
_patchArrays.reserve(numPatchArrays);
|
||||
}
|
||||
|
||||
//
|
||||
// FVarPatchChannel
|
||||
//
|
||||
// Stores a record for each patch in the primitive :
|
||||
//
|
||||
// - Each patch in the PatchTable has a corresponding patch in each
|
||||
// face-varying patch channel. Patch vertex indices are sorted in the same
|
||||
// patch-type order as PatchTable::PTables. Face-varying data for a patch
|
||||
// can therefore be quickly accessed by using the patch primitive ID as
|
||||
// index into patchValueOffsets to locate the face-varying control vertex
|
||||
// indices.
|
||||
//
|
||||
// - Face-varying channels can have a different interpolation modes
|
||||
//
|
||||
// - Unlike "vertex" patches, there are no transition masks required
|
||||
// for face-varying patches.
|
||||
//
|
||||
// - Face-varying patches still require boundary edge masks.
|
||||
//
|
||||
// - currently most patches with sharp boundaries but smooth interiors have
|
||||
// to be isolated to level 10 : we need a special type of bicubic patch
|
||||
// similar to single-crease to resolve this condition without requiring
|
||||
// isolation if possible
|
||||
//
|
||||
struct PatchTable::FVarPatchChannel {
|
||||
|
||||
Sdc::Options::FVarLinearInterpolation interpolation;
|
||||
|
||||
PatchDescriptor regDesc;
|
||||
PatchDescriptor irregDesc;
|
||||
|
||||
int stride;
|
||||
|
||||
std::vector<Index> patchValues;
|
||||
std::vector<PatchParam> patchParam;
|
||||
};
|
||||
|
||||
void
|
||||
PatchTable::allocateVaryingVertices(
|
||||
PatchDescriptor desc, int numPatches) {
|
||||
_varyingDesc = desc;
|
||||
_varyingVerts.resize(numPatches*desc.GetNumControlVertices());
|
||||
}
|
||||
|
||||
inline PatchTable::FVarPatchChannel &
|
||||
PatchTable::getFVarPatchChannel(int channel) {
|
||||
assert(channel>=0 && channel<(int)_fvarChannels.size());
|
||||
return _fvarChannels[channel];
|
||||
}
|
||||
inline PatchTable::FVarPatchChannel const &
|
||||
PatchTable::getFVarPatchChannel(int channel) const {
|
||||
assert(channel>=0 && channel<(int)_fvarChannels.size());
|
||||
return _fvarChannels[channel];
|
||||
}
|
||||
void
|
||||
PatchTable::allocateFVarPatchChannels(int numChannels) {
|
||||
_fvarChannels.resize(numChannels);
|
||||
}
|
||||
void
|
||||
PatchTable::allocateFVarPatchChannelValues(
|
||||
PatchDescriptor regDesc, PatchDescriptor irregDesc,
|
||||
int numPatches, int channel) {
|
||||
FVarPatchChannel & c = getFVarPatchChannel(channel);
|
||||
c.regDesc = regDesc;
|
||||
c.irregDesc = irregDesc;
|
||||
|
||||
c.stride = std::max(regDesc.GetNumControlVertices(),
|
||||
irregDesc.GetNumControlVertices());
|
||||
|
||||
c.patchValues.resize(numPatches * c.stride);
|
||||
c.patchParam.resize(numPatches);
|
||||
}
|
||||
void
|
||||
PatchTable::setFVarPatchChannelLinearInterpolation(
|
||||
Sdc::Options::FVarLinearInterpolation interpolation, int channel) {
|
||||
FVarPatchChannel & c = getFVarPatchChannel(channel);
|
||||
c.interpolation = interpolation;
|
||||
}
|
||||
|
||||
//
|
||||
// PatchTable
|
||||
//
|
||||
|
||||
inline int
|
||||
getPatchSize(PatchDescriptor desc) {
|
||||
return desc.GetNumControlVertices();
|
||||
}
|
||||
|
||||
void
|
||||
PatchTable::pushPatchArray(PatchDescriptor desc, int npatches,
|
||||
Index * vidx, Index * pidx, Index * qoidx) {
|
||||
|
||||
if (npatches>0) {
|
||||
_patchArrays.push_back(PatchArray(
|
||||
desc, npatches, *vidx, *pidx, qoidx ? *qoidx : 0));
|
||||
int nverts = getPatchSize(desc);
|
||||
*vidx += npatches * nverts;
|
||||
*pidx += npatches;
|
||||
if (qoidx) {
|
||||
*qoidx += (desc.GetType() == PatchDescriptor::GREGORY) ?
|
||||
npatches*nverts : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
PatchTable::getPatchIndex(int arrayIndex, int patchIndex) const {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
assert(patchIndex<pa.numPatches);
|
||||
return pa.patchIndex + patchIndex;
|
||||
}
|
||||
Index *
|
||||
PatchTable::getSharpnessIndices(int arrayIndex) {
|
||||
return &_sharpnessIndices[getPatchArray(arrayIndex).patchIndex];
|
||||
}
|
||||
|
||||
float *
|
||||
PatchTable::getSharpnessValues(int arrayIndex) {
|
||||
return &_sharpnessValues[getPatchArray(arrayIndex).patchIndex];
|
||||
}
|
||||
|
||||
PatchDescriptor
|
||||
PatchTable::GetPatchDescriptor(PatchHandle const & handle) const {
|
||||
return getPatchArray(handle.arrayIndex).desc;
|
||||
}
|
||||
|
||||
PatchDescriptor
|
||||
PatchTable::GetPatchArrayDescriptor(int arrayIndex) const {
|
||||
return getPatchArray(arrayIndex).desc;
|
||||
}
|
||||
|
||||
int
|
||||
PatchTable::GetNumPatchArrays() const {
|
||||
return (int)_patchArrays.size();
|
||||
}
|
||||
int
|
||||
PatchTable::GetNumPatches(int arrayIndex) const {
|
||||
return getPatchArray(arrayIndex).numPatches;
|
||||
}
|
||||
int
|
||||
PatchTable::GetNumPatchesTotal() const {
|
||||
// there is one PatchParam record for each patch in the mesh
|
||||
return (int)_paramTable.size();
|
||||
}
|
||||
int
|
||||
PatchTable::GetNumControlVertices(int arrayIndex) const {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
return pa.numPatches * getPatchSize(pa.desc);
|
||||
}
|
||||
|
||||
Index
|
||||
PatchTable::findPatchArray(PatchDescriptor desc) {
|
||||
for (int i=0; i<(int)_patchArrays.size(); ++i) {
|
||||
if (_patchArrays[i].desc==desc)
|
||||
return i;
|
||||
}
|
||||
return Vtr::INDEX_INVALID;
|
||||
}
|
||||
IndexArray
|
||||
PatchTable::getPatchArrayVertices(int arrayIndex) {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
int size = getPatchSize(pa.desc);
|
||||
assert(pa.vertIndex<(Index)_patchVerts.size());
|
||||
return IndexArray(&_patchVerts[pa.vertIndex], pa.numPatches * size);
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchArrayVertices(int arrayIndex) const {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
int size = getPatchSize(pa.desc);
|
||||
assert(pa.vertIndex<(Index)_patchVerts.size());
|
||||
return ConstIndexArray(&_patchVerts[pa.vertIndex], pa.numPatches * size);
|
||||
}
|
||||
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchVertices(PatchHandle const & handle) const {
|
||||
PatchArray const & pa = getPatchArray(handle.arrayIndex);
|
||||
Index vert = pa.vertIndex + handle.vertIndex;
|
||||
return ConstIndexArray(&_patchVerts[vert], getPatchSize(pa.desc));
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchVertices(int arrayIndex, int patchIndex) const {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
int size = getPatchSize(pa.desc);
|
||||
assert((pa.vertIndex + patchIndex*size)<(Index)_patchVerts.size());
|
||||
return ConstIndexArray(&_patchVerts[pa.vertIndex + patchIndex*size], size);
|
||||
}
|
||||
|
||||
PatchParam
|
||||
PatchTable::GetPatchParam(PatchHandle const & handle) const {
|
||||
assert(handle.patchIndex < (Index)_paramTable.size());
|
||||
return _paramTable[handle.patchIndex];
|
||||
}
|
||||
PatchParam
|
||||
PatchTable::GetPatchParam(int arrayIndex, int patchIndex) const {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
assert((pa.patchIndex + patchIndex) < (int)_paramTable.size());
|
||||
return _paramTable[pa.patchIndex + patchIndex];
|
||||
}
|
||||
PatchParamArray
|
||||
PatchTable::getPatchParams(int arrayIndex) {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
return PatchParamArray(&_paramTable[pa.patchIndex], pa.numPatches);
|
||||
}
|
||||
ConstPatchParamArray const
|
||||
PatchTable::GetPatchParams(int arrayIndex) const {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
return ConstPatchParamArray(&_paramTable[pa.patchIndex], pa.numPatches);
|
||||
}
|
||||
|
||||
float
|
||||
PatchTable::GetSingleCreasePatchSharpnessValue(PatchHandle const & handle) const {
|
||||
assert((handle.patchIndex) < (int)_sharpnessIndices.size());
|
||||
Index index = _sharpnessIndices[handle.patchIndex];
|
||||
if (index == Vtr::INDEX_INVALID) {
|
||||
return 0.0f;
|
||||
}
|
||||
assert(index < (Index)_sharpnessValues.size());
|
||||
return _sharpnessValues[index];
|
||||
}
|
||||
float
|
||||
PatchTable::GetSingleCreasePatchSharpnessValue(int arrayIndex, int patchIndex) const {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
assert((pa.patchIndex + patchIndex) < (int)_sharpnessIndices.size());
|
||||
Index index = _sharpnessIndices[pa.patchIndex + patchIndex];
|
||||
if (index == Vtr::INDEX_INVALID) {
|
||||
return 0.0f;
|
||||
}
|
||||
assert(index < (Index)_sharpnessValues.size());
|
||||
return _sharpnessValues[index];
|
||||
}
|
||||
|
||||
int
|
||||
PatchTable::GetNumLocalPoints() const {
|
||||
if (!_localPointStencils) return 0;
|
||||
return _vertexPrecisionIsDouble
|
||||
? _localPointStencils.Get<double>()->GetNumStencils()
|
||||
: _localPointStencils.Get<float>()->GetNumStencils();
|
||||
}
|
||||
int
|
||||
PatchTable::GetNumLocalPointsVarying() const {
|
||||
if (!_localPointVaryingStencils) return 0;
|
||||
return _varyingPrecisionIsDouble
|
||||
? _localPointVaryingStencils.Get<double>()->GetNumStencils()
|
||||
: _localPointVaryingStencils.Get<float>()->GetNumStencils();
|
||||
}
|
||||
int
|
||||
PatchTable::GetNumLocalPointsFaceVarying(int channel) const {
|
||||
if (channel>=0 && channel<(int)_localPointFaceVaryingStencils.size()) {
|
||||
if (!_localPointFaceVaryingStencils[channel]) return 0;
|
||||
return _faceVaryingPrecisionIsDouble
|
||||
? _localPointFaceVaryingStencils[channel].Get<double>()->GetNumStencils()
|
||||
: _localPointFaceVaryingStencils[channel].Get<float>()->GetNumStencils();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PatchTable::ConstQuadOffsetsArray
|
||||
PatchTable::GetPatchQuadOffsets(PatchHandle const & handle) const {
|
||||
PatchArray const & pa = getPatchArray(handle.arrayIndex);
|
||||
return Vtr::ConstArray<unsigned int>(&_quadOffsetsTable[pa.quadOffsetIndex + handle.vertIndex], 4);
|
||||
}
|
||||
bool
|
||||
PatchTable::IsFeatureAdaptive() const {
|
||||
|
||||
return !_isUniformLinear;
|
||||
}
|
||||
|
||||
PatchDescriptor
|
||||
PatchTable::GetVaryingPatchDescriptor() const {
|
||||
return _varyingDesc;
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchVaryingVertices(PatchHandle const & handle) const {
|
||||
if (_varyingVerts.empty()) {
|
||||
return ConstIndexArray();
|
||||
}
|
||||
int numVaryingCVs = _varyingDesc.GetNumControlVertices();
|
||||
Index start = handle.patchIndex * numVaryingCVs;
|
||||
return ConstIndexArray(&_varyingVerts[start], numVaryingCVs);
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchVaryingVertices(int array, int patch) const {
|
||||
if (_varyingVerts.empty()) {
|
||||
return ConstIndexArray();
|
||||
}
|
||||
PatchArray const & pa = getPatchArray(array);
|
||||
int numVaryingCVs = _varyingDesc.GetNumControlVertices();
|
||||
Index start = (pa.patchIndex + patch) * numVaryingCVs;
|
||||
return ConstIndexArray(&_varyingVerts[start], numVaryingCVs);
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchArrayVaryingVertices(int array) const {
|
||||
if (_varyingVerts.empty()) {
|
||||
return ConstIndexArray();
|
||||
}
|
||||
PatchArray const & pa = getPatchArray(array);
|
||||
int numVaryingCVs = _varyingDesc.GetNumControlVertices();
|
||||
Index start = pa.patchIndex * numVaryingCVs;
|
||||
Index count = pa.numPatches * numVaryingCVs;
|
||||
return ConstIndexArray(&_varyingVerts[start], count);
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetVaryingVertices() const {
|
||||
if (_varyingVerts.empty()) {
|
||||
return ConstIndexArray();
|
||||
}
|
||||
return ConstIndexArray(&_varyingVerts[0], (int)_varyingVerts.size());
|
||||
}
|
||||
IndexArray
|
||||
PatchTable::getPatchArrayVaryingVertices(int arrayIndex) {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
int numVaryingCVs = _varyingDesc.GetNumControlVertices();
|
||||
Index start = pa.patchIndex * numVaryingCVs;
|
||||
return IndexArray(&_varyingVerts[start], pa.numPatches * numVaryingCVs);
|
||||
}
|
||||
void
|
||||
PatchTable::populateVaryingVertices() {
|
||||
// In order to support evaluation of varying data we need to access
|
||||
// the varying values indexed by the zero ring vertices of the vertex
|
||||
// patch. This indexing is redundant for triangles and quads and
|
||||
// could be made redunant for other patch types if we reorganized
|
||||
// the vertex patch indices so that the zero ring indices always occured
|
||||
// first. This will also need to be updated when we add support for
|
||||
// triangle patches.
|
||||
int numVaryingCVs = _varyingDesc.GetNumControlVertices();
|
||||
for (int arrayIndex=0; arrayIndex<(int)_patchArrays.size(); ++arrayIndex) {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
PatchDescriptor::Type patchType = pa.desc.GetType();
|
||||
for (int patch=0; patch<pa.numPatches; ++patch) {
|
||||
ConstIndexArray vertexCVs = GetPatchVertices(arrayIndex, patch);
|
||||
int start = (pa.patchIndex + patch) * numVaryingCVs;
|
||||
if (patchType == PatchDescriptor::REGULAR) {
|
||||
_varyingVerts[start+0] = vertexCVs[5];
|
||||
_varyingVerts[start+1] = vertexCVs[6];
|
||||
_varyingVerts[start+2] = vertexCVs[10];
|
||||
_varyingVerts[start+3] = vertexCVs[9];
|
||||
} else if (patchType == PatchDescriptor::GREGORY_BASIS) {
|
||||
_varyingVerts[start+0] = vertexCVs[0];
|
||||
_varyingVerts[start+1] = vertexCVs[5];
|
||||
_varyingVerts[start+2] = vertexCVs[10];
|
||||
_varyingVerts[start+3] = vertexCVs[15];
|
||||
} else if (patchType == PatchDescriptor::QUADS) {
|
||||
_varyingVerts[start+0] = vertexCVs[0];
|
||||
_varyingVerts[start+1] = vertexCVs[1];
|
||||
_varyingVerts[start+2] = vertexCVs[2];
|
||||
_varyingVerts[start+3] = vertexCVs[3];
|
||||
} else if (patchType == PatchDescriptor::TRIANGLES) {
|
||||
_varyingVerts[start+0] = vertexCVs[0];
|
||||
_varyingVerts[start+1] = vertexCVs[1];
|
||||
_varyingVerts[start+2] = vertexCVs[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
PatchTable::GetNumFVarChannels() const {
|
||||
return (int)_fvarChannels.size();
|
||||
}
|
||||
Sdc::Options::FVarLinearInterpolation
|
||||
PatchTable::GetFVarChannelLinearInterpolation(int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return c.interpolation;
|
||||
}
|
||||
PatchDescriptor
|
||||
PatchTable::GetFVarPatchDescriptorRegular(int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return c.regDesc;
|
||||
}
|
||||
PatchDescriptor
|
||||
PatchTable::GetFVarPatchDescriptorIrregular(int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return c.irregDesc;
|
||||
}
|
||||
PatchDescriptor
|
||||
PatchTable::GetFVarPatchDescriptor(int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return c.irregDesc;
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetFVarValues(int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return ConstIndexArray(&c.patchValues[0], (int)c.patchValues.size());
|
||||
}
|
||||
int
|
||||
PatchTable::GetFVarValueStride(int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return c.stride;
|
||||
}
|
||||
IndexArray
|
||||
PatchTable::getFVarValues(int channel) {
|
||||
FVarPatchChannel & c = getFVarPatchChannel(channel);
|
||||
return IndexArray(&c.patchValues[0], (int)c.patchValues.size());
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::getPatchFVarValues(int patch, int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
int ncvsThisPatch = c.patchParam[patch].IsRegular()
|
||||
? c.regDesc.GetNumControlVertices()
|
||||
: c.irregDesc.GetNumControlVertices();
|
||||
return ConstIndexArray(&c.patchValues[patch * c.stride], ncvsThisPatch);
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchFVarValues(PatchHandle const & handle, int channel) const {
|
||||
return getPatchFVarValues(handle.patchIndex, channel);
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchFVarValues(int arrayIndex, int patchIndex, int channel) const {
|
||||
return getPatchFVarValues(getPatchIndex(arrayIndex, patchIndex), channel);
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchArrayFVarValues(int array, int channel) const {
|
||||
PatchArray const & pa = getPatchArray(array);
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
int ncvs = c.stride;
|
||||
int start = pa.patchIndex * ncvs;
|
||||
int count = pa.numPatches * ncvs;
|
||||
return ConstIndexArray(&c.patchValues[start], count);
|
||||
}
|
||||
PatchParam
|
||||
PatchTable::getPatchFVarPatchParam(int patch, int channel) const {
|
||||
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return c.patchParam[patch];
|
||||
}
|
||||
PatchParam
|
||||
PatchTable::GetPatchFVarPatchParam(PatchHandle const & handle, int channel) const {
|
||||
return getPatchFVarPatchParam(handle.patchIndex, channel);
|
||||
}
|
||||
PatchParam
|
||||
PatchTable::GetPatchFVarPatchParam(int arrayIndex, int patchIndex, int channel) const {
|
||||
return getPatchFVarPatchParam(getPatchIndex(arrayIndex, patchIndex), channel);
|
||||
}
|
||||
ConstPatchParamArray
|
||||
PatchTable::GetPatchArrayFVarPatchParams(int array, int channel) const {
|
||||
PatchArray const & pa = getPatchArray(array);
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return ConstPatchParamArray(&c.patchParam[pa.patchIndex], pa.numPatches);
|
||||
}
|
||||
ConstPatchParamArray
|
||||
PatchTable::GetFVarPatchParams(int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return ConstPatchParamArray(&c.patchParam[0], (int)c.patchParam.size());
|
||||
}
|
||||
PatchParamArray
|
||||
PatchTable::getFVarPatchParams(int channel) {
|
||||
FVarPatchChannel & c = getFVarPatchChannel(channel);
|
||||
return PatchParamArray(&c.patchParam[0], (int)c.patchParam.size());
|
||||
}
|
||||
|
||||
void
|
||||
PatchTable::print() const {
|
||||
printf("patchTable (0x%p)\n", this);
|
||||
printf(" numPatches = %d\n", GetNumPatchesTotal());
|
||||
for (int i=0; i<GetNumPatchArrays(); ++i) {
|
||||
printf(" patchArray %d:\n", i);
|
||||
PatchArray const & pa = getPatchArray(i);
|
||||
pa.print();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Evaluate basis functions for vertex and derivatives at (s,t):
|
||||
//
|
||||
template <typename REAL>
|
||||
void
|
||||
PatchTable::EvaluateBasis(
|
||||
PatchHandle const & handle, REAL s, REAL t,
|
||||
REAL wP[], REAL wDs[], REAL wDt[],
|
||||
REAL wDss[], REAL wDst[], REAL wDtt[]) const {
|
||||
|
||||
PatchParam const & param = _paramTable[handle.patchIndex];
|
||||
PatchDescriptor::Type patchType = GetPatchArrayDescriptor(handle.arrayIndex).GetType();
|
||||
|
||||
internal::EvaluatePatchBasis(patchType, param, s, t, wP, wDs, wDt, wDss, wDst, wDtt);
|
||||
}
|
||||
|
||||
//
|
||||
// Evaluate basis functions for varying and derivatives at (s,t):
|
||||
//
|
||||
template <typename REAL>
|
||||
void
|
||||
PatchTable::EvaluateBasisVarying(
|
||||
PatchHandle const & handle, REAL s, REAL t,
|
||||
REAL wP[], REAL wDs[], REAL wDt[],
|
||||
REAL wDss[], REAL wDst[], REAL wDtt[]) const {
|
||||
|
||||
PatchParam const & param = _paramTable[handle.patchIndex];
|
||||
PatchDescriptor::Type patchType = GetVaryingPatchDescriptor().GetType();
|
||||
|
||||
internal::EvaluatePatchBasis(patchType, param, s, t, wP, wDs, wDt, wDss, wDst, wDtt);
|
||||
}
|
||||
|
||||
//
|
||||
// Evaluate basis functions for face-varying and derivatives at (s,t):
|
||||
//
|
||||
template <typename REAL>
|
||||
void
|
||||
PatchTable::EvaluateBasisFaceVarying(
|
||||
PatchHandle const & handle, REAL s, REAL t,
|
||||
REAL wP[], REAL wDs[], REAL wDt[],
|
||||
REAL wDss[], REAL wDst[], REAL wDtt[],
|
||||
int channel) const {
|
||||
|
||||
PatchParam param = getPatchFVarPatchParam(handle.patchIndex, channel);
|
||||
PatchDescriptor::Type patchType = param.IsRegular()
|
||||
? GetFVarPatchDescriptorRegular(channel).GetType()
|
||||
: GetFVarPatchDescriptorIrregular(channel).GetType();
|
||||
|
||||
internal::EvaluatePatchBasis(patchType, param, s, t, wP, wDs, wDt, wDss, wDst, wDtt);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Explicit instantiation of EvaluateBasis...() methods for float and double:
|
||||
//
|
||||
template void PatchTable::EvaluateBasis<float>(PatchHandle const & handle,
|
||||
float s, float t, float wP[], float wDs[], float wDt[],
|
||||
float wDss[], float wDst[], float wDtt[]) const;
|
||||
template void PatchTable::EvaluateBasisVarying<float>(PatchHandle const & handle,
|
||||
float s, float t, float wP[], float wDs[], float wDt[],
|
||||
float wDss[], float wDst[], float wDtt[]) const;
|
||||
template void PatchTable::EvaluateBasisFaceVarying<float>(PatchHandle const & handle,
|
||||
float s, float t, float wP[], float wDs[], float wDt[],
|
||||
float wDss[], float wDst[], float wDtt[], int channel) const;
|
||||
|
||||
template void PatchTable::EvaluateBasis<double>(PatchHandle const & handle,
|
||||
double s, double t, double wP[], double wDs[], double wDt[],
|
||||
double wDss[], double wDst[], double wDtt[]) const;
|
||||
template void PatchTable::EvaluateBasisVarying<double>(PatchHandle const & handle,
|
||||
double s, double t, double wP[], double wDs[], double wDt[],
|
||||
double wDss[], double wDst[], double wDtt[]) const;
|
||||
template void PatchTable::EvaluateBasisFaceVarying<double>(PatchHandle const & handle,
|
||||
double s, double t, double wP[], double wDs[], double wDt[],
|
||||
double wDss[], double wDst[], double wDtt[], int channel) const;
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
861
src/osd/opensubdiv/far/patchTable.h
Normal file
861
src/osd/opensubdiv/far/patchTable.h
Normal file
@@ -0,0 +1,861 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_PATCH_TABLE_H
|
||||
#define OPENSUBDIV3_FAR_PATCH_TABLE_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/patchDescriptor.h"
|
||||
#include "../far/patchParam.h"
|
||||
#include "../far/stencilTable.h"
|
||||
|
||||
#include "../sdc/options.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
/// \brief Container for arrays of parametric patches
|
||||
///
|
||||
/// PatchTable contains topology and parametric information about the patches
|
||||
/// generated by the Refinement process. Patches in the table are sorted into
|
||||
/// arrays based on their PatchDescriptor Type.
|
||||
///
|
||||
/// Note : PatchTable can be accessed either using a PatchHandle or a
|
||||
/// combination of array and patch indices.
|
||||
///
|
||||
/// XXXX manuelk we should add a PatchIterator that can dereference into
|
||||
/// a PatchHandle for fast linear traversal of the table
|
||||
///
|
||||
class PatchTable {
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Handle that can be used as unique patch identifier within PatchTable
|
||||
class PatchHandle {
|
||||
// XXXX manuelk members will eventually be made private
|
||||
public:
|
||||
|
||||
friend class PatchTable;
|
||||
friend class PatchMap;
|
||||
|
||||
Index arrayIndex, // Array index of the patch
|
||||
patchIndex, // Absolute Index of the patch
|
||||
vertIndex; // Relative offset to the first CV of the patch in array
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Copy constructor
|
||||
PatchTable(PatchTable const & src);
|
||||
|
||||
/// \brief Destructor
|
||||
~PatchTable();
|
||||
|
||||
/// \brief True if the patches are of feature adaptive types
|
||||
bool IsFeatureAdaptive() const;
|
||||
|
||||
/// \brief Returns the total number of control vertex indices in the table
|
||||
int GetNumControlVerticesTotal() const {
|
||||
return (int)_patchVerts.size();
|
||||
}
|
||||
|
||||
/// \brief Returns the total number of patches stored in the table
|
||||
int GetNumPatchesTotal() const;
|
||||
|
||||
/// \brief Returns max vertex valence
|
||||
int GetMaxValence() const { return _maxValence; }
|
||||
|
||||
/// \brief Returns the total number of ptex faces in the mesh
|
||||
int GetNumPtexFaces() const { return _numPtexFaces; }
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Individual patches
|
||||
///
|
||||
/// \anchor individual_patches
|
||||
///
|
||||
/// \brief Accessors for individual patches
|
||||
///
|
||||
|
||||
/// \brief Returns the PatchDescriptor for the patch identified by \p handle
|
||||
PatchDescriptor GetPatchDescriptor(PatchHandle const & handle) const;
|
||||
|
||||
/// \brief Returns the control vertex indices for the patch identified by \p handle
|
||||
ConstIndexArray GetPatchVertices(PatchHandle const & handle) const;
|
||||
|
||||
/// \brief Returns a PatchParam for the patch identified by \p handle
|
||||
PatchParam GetPatchParam(PatchHandle const & handle) const;
|
||||
|
||||
/// \brief Returns the control vertex indices for \p patch in \p array
|
||||
ConstIndexArray GetPatchVertices(int array, int patch) const;
|
||||
|
||||
/// \brief Returns the PatchParam for \p patch in \p array
|
||||
PatchParam GetPatchParam(int array, int patch) const;
|
||||
//@}
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Arrays of patches
|
||||
///
|
||||
/// \anchor arrays_of_patches
|
||||
///
|
||||
/// \brief Accessors for arrays of patches of the same type
|
||||
///
|
||||
|
||||
/// \brief Returns the number of patch arrays in the table
|
||||
int GetNumPatchArrays() const;
|
||||
|
||||
/// \brief Returns the number of patches in \p array
|
||||
int GetNumPatches(int array) const;
|
||||
|
||||
/// \brief Returns the number of control vertices in \p array
|
||||
int GetNumControlVertices(int array) const;
|
||||
|
||||
/// \brief Returns the PatchDescriptor for the patches in \p array
|
||||
PatchDescriptor GetPatchArrayDescriptor(int array) const;
|
||||
|
||||
/// \brief Returns the control vertex indices for the patches in \p array
|
||||
ConstIndexArray GetPatchArrayVertices(int array) const;
|
||||
|
||||
/// \brief Returns the PatchParams for the patches in \p array
|
||||
ConstPatchParamArray const GetPatchParams(int array) const;
|
||||
//@}
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Change of basis patches
|
||||
///
|
||||
/// \anchor change_of_basis_patches
|
||||
///
|
||||
/// \brief Accessors for change of basis patches
|
||||
///
|
||||
///
|
||||
|
||||
/// \brief Returns the number of local vertex points.
|
||||
int GetNumLocalPoints() const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point vertex values
|
||||
StencilTable const *GetLocalPointStencilTable() const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point vertex values
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const *GetLocalPointStencilTable() const;
|
||||
|
||||
/// \brief Tests if the precision of the stencil table to compute local point
|
||||
/// vertex values matches the given floating point type \<REAL\>.
|
||||
template <typename REAL> bool LocalPointStencilPrecisionMatchesType() const;
|
||||
|
||||
/// \brief Updates local point vertex values.
|
||||
///
|
||||
/// @param src Buffer with primvar data for the base and refined
|
||||
/// vertex values
|
||||
///
|
||||
/// @param dst Destination buffer for the computed local point
|
||||
/// vertex values
|
||||
///
|
||||
/// For more flexibility computing local vertex points, retrieval of
|
||||
/// the local point stencil table and use of its public methods is
|
||||
/// recommended or often required.
|
||||
///
|
||||
template <class T> void
|
||||
ComputeLocalPointValues(T const *src, T *dst) const;
|
||||
|
||||
|
||||
/// \brief Returns the number of local varying points.
|
||||
int GetNumLocalPointsVarying() const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point varying values
|
||||
StencilTable const *GetLocalPointVaryingStencilTable() const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point varying values
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const *GetLocalPointVaryingStencilTable() const;
|
||||
|
||||
/// \brief Tests if the precision of the stencil table to compute local point
|
||||
/// varying values matches the given floating point type \<REAL\>.
|
||||
template <typename REAL> bool LocalPointVaryingStencilPrecisionMatchesType() const;
|
||||
|
||||
/// \brief Updates local point varying values.
|
||||
///
|
||||
/// @param src Buffer with primvar data for the base and refined
|
||||
/// varying values
|
||||
///
|
||||
/// @param dst Destination buffer for the computed local point
|
||||
/// varying values
|
||||
///
|
||||
/// For more flexibility computing local varying points, retrieval of
|
||||
/// the local point varying stencil table and use of its public methods
|
||||
/// is recommended or often required.
|
||||
///
|
||||
template <class T> void
|
||||
ComputeLocalPointValuesVarying(T const *src, T *dst) const;
|
||||
|
||||
|
||||
/// \brief Returns the number of local face-varying points for \p channel
|
||||
int GetNumLocalPointsFaceVarying(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point face-varying values
|
||||
StencilTable const *GetLocalPointFaceVaryingStencilTable(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point face-varying values
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const * GetLocalPointFaceVaryingStencilTable(int channel = 0) const;
|
||||
|
||||
/// \brief Tests if the precision of the stencil table to compute local point
|
||||
/// face-varying values matches the given floating point type \<REAL\>.
|
||||
template <typename REAL> bool LocalPointFaceVaryingStencilPrecisionMatchesType() const;
|
||||
|
||||
/// \brief Updates local point face-varying values.
|
||||
///
|
||||
/// @param src Buffer with primvar data for the base and refined
|
||||
/// face-varying values
|
||||
///
|
||||
/// @param dst Destination buffer for the computed local point
|
||||
/// face-varying values
|
||||
///
|
||||
/// @param channel face-varying channel
|
||||
///
|
||||
/// For more flexibility computing local face-varying points, retrieval
|
||||
/// of the local point face-varying stencil table and use of its public
|
||||
/// methods is recommended or often required.
|
||||
///
|
||||
template <class T> void
|
||||
ComputeLocalPointValuesFaceVarying(T const *src, T *dst, int channel = 0) const;
|
||||
//@}
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Legacy gregory patch evaluation buffers
|
||||
|
||||
/// \brief Accessors for the gregory patch evaluation buffers.
|
||||
/// These methods will be deprecated.
|
||||
///
|
||||
typedef Vtr::ConstArray<unsigned int> ConstQuadOffsetsArray;
|
||||
|
||||
/// \brief Returns the 'QuadOffsets' for the Gregory patch identified by \p handle
|
||||
ConstQuadOffsetsArray GetPatchQuadOffsets(PatchHandle const & handle) const;
|
||||
|
||||
typedef std::vector<Index> VertexValenceTable;
|
||||
|
||||
/// \brief Returns the 'VertexValences' table (vertex neighborhoods table)
|
||||
VertexValenceTable const & GetVertexValenceTable() const {
|
||||
return _vertexValenceTable;
|
||||
}
|
||||
//@}
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Single-crease patches
|
||||
///
|
||||
/// \anchor single_crease_patches
|
||||
///
|
||||
/// \brief Accessors for single-crease patch edge sharpness
|
||||
///
|
||||
|
||||
/// \brief Returns the crease sharpness for the patch identified by \p handle
|
||||
/// if it is a single-crease patch, or 0.0f
|
||||
float GetSingleCreasePatchSharpnessValue(PatchHandle const & handle) const;
|
||||
|
||||
/// \brief Returns the crease sharpness for the \p patch in \p array
|
||||
/// if it is a single-crease patch, or 0.0f
|
||||
float GetSingleCreasePatchSharpnessValue(int array, int patch) const;
|
||||
//@}
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Varying data
|
||||
///
|
||||
/// \anchor varying_data
|
||||
///
|
||||
/// \brief Accessors for varying data
|
||||
///
|
||||
|
||||
/// \brief Returns the varying patch descriptor
|
||||
PatchDescriptor GetVaryingPatchDescriptor() const;
|
||||
|
||||
/// \brief Returns the varying vertex indices for a given patch
|
||||
ConstIndexArray GetPatchVaryingVertices(PatchHandle const & handle) const;
|
||||
|
||||
/// \brief Returns the varying vertex indices for a given patch
|
||||
ConstIndexArray GetPatchVaryingVertices(int array, int patch) const;
|
||||
|
||||
/// \brief Returns the varying vertex indices for the patches in \p array
|
||||
ConstIndexArray GetPatchArrayVaryingVertices(int array) const;
|
||||
|
||||
/// \brief Returns an array of varying vertex indices for the patches.
|
||||
ConstIndexArray GetVaryingVertices() const;
|
||||
//@}
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Face-varying channels
|
||||
///
|
||||
/// \anchor face_varying_channels
|
||||
///
|
||||
/// \brief Accessors for face-varying channels
|
||||
///
|
||||
|
||||
/// \brief Returns the number of face-varying channels
|
||||
int GetNumFVarChannels() const;
|
||||
|
||||
/// \brief Returns the regular patch descriptor for \p channel
|
||||
PatchDescriptor GetFVarPatchDescriptorRegular(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the irregular patch descriptor for \p channel
|
||||
PatchDescriptor GetFVarPatchDescriptorIrregular(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the default/irregular patch descriptor for \p channel
|
||||
PatchDescriptor GetFVarPatchDescriptor(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the value indices for a given patch in \p channel
|
||||
ConstIndexArray GetPatchFVarValues(PatchHandle const & handle, int channel = 0) const;
|
||||
|
||||
/// \brief Returns the value indices for a given patch in \p channel
|
||||
ConstIndexArray GetPatchFVarValues(int array, int patch, int channel = 0) const;
|
||||
|
||||
/// \brief Returns the value indices for the patches in \p array in \p channel
|
||||
ConstIndexArray GetPatchArrayFVarValues(int array, int channel = 0) const;
|
||||
|
||||
/// \brief Returns an array of value indices for the patches in \p channel
|
||||
ConstIndexArray GetFVarValues(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the stride between patches in the value index array of \p channel
|
||||
int GetFVarValueStride(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the value indices for a given patch in \p channel
|
||||
PatchParam GetPatchFVarPatchParam(PatchHandle const & handle, int channel = 0) const;
|
||||
|
||||
/// \brief Returns the face-varying params for a given patch \p channel
|
||||
PatchParam GetPatchFVarPatchParam(int array, int patch, int channel = 0) const;
|
||||
|
||||
/// \brief Returns the face-varying for a given patch in \p array in \p channel
|
||||
ConstPatchParamArray GetPatchArrayFVarPatchParams(int array, int channel = 0) const;
|
||||
|
||||
/// \brief Returns an array of face-varying patch param for \p channel
|
||||
ConstPatchParamArray GetFVarPatchParams(int channel = 0) const;
|
||||
|
||||
/// \brief Deprecated @see PatchTable#GetFVarPatchDescriptor
|
||||
Sdc::Options::FVarLinearInterpolation GetFVarChannelLinearInterpolation(int channel = 0) const;
|
||||
//@}
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Direct accessors
|
||||
///
|
||||
/// \warning These direct accessors are left for convenience, but they are
|
||||
/// likely going to be deprecated in future releases
|
||||
///
|
||||
|
||||
typedef std::vector<Index> PatchVertsTable;
|
||||
|
||||
/// \brief Get the table of patch control vertices
|
||||
PatchVertsTable const & GetPatchControlVerticesTable() const { return _patchVerts; }
|
||||
|
||||
/// \brief Returns the PatchParamTable (PatchParams order matches patch array sorting)
|
||||
PatchParamTable const & GetPatchParamTable() const { return _paramTable; }
|
||||
|
||||
/// \brief Returns a sharpness index table for each patch (if exists)
|
||||
std::vector<Index> const &GetSharpnessIndexTable() const { return _sharpnessIndices; }
|
||||
|
||||
/// \brief Returns sharpness values table
|
||||
std::vector<float> const &GetSharpnessValues() const { return _sharpnessValues; }
|
||||
|
||||
typedef std::vector<unsigned int> QuadOffsetsTable;
|
||||
|
||||
/// \brief Returns the quad-offsets table
|
||||
QuadOffsetsTable const & GetQuadOffsetsTable() const {
|
||||
return _quadOffsetsTable;
|
||||
}
|
||||
//@}
|
||||
|
||||
/// debug helper
|
||||
void print() const;
|
||||
|
||||
public:
|
||||
|
||||
//@{
|
||||
/// @name Evaluation methods
|
||||
///
|
||||
|
||||
/// \brief Evaluate basis functions for position and derivatives at a
|
||||
/// given (u,v) parametric location of a patch.
|
||||
///
|
||||
/// @param handle A patch handle identifying the sub-patch containing the
|
||||
/// (u,v) location
|
||||
///
|
||||
/// @param u Patch coordinate (in base face normalized space)
|
||||
///
|
||||
/// @param v Patch coordinate (in base face normalized space)
|
||||
///
|
||||
/// @param wP Weights (evaluated basis functions) for the position
|
||||
///
|
||||
/// @param wDu Weights (evaluated basis functions) for derivative wrt u
|
||||
///
|
||||
/// @param wDv Weights (evaluated basis functions) for derivative wrt v
|
||||
///
|
||||
/// @param wDuu Weights (evaluated basis functions) for 2nd derivative wrt u
|
||||
///
|
||||
/// @param wDuv Weights (evaluated basis functions) for 2nd derivative wrt u and v
|
||||
///
|
||||
/// @param wDvv Weights (evaluated basis functions) for 2nd derivative wrt v
|
||||
///
|
||||
template <typename REAL>
|
||||
void EvaluateBasis(PatchHandle const & handle, REAL u, REAL v,
|
||||
REAL wP[], REAL wDu[] = 0, REAL wDv[] = 0,
|
||||
REAL wDuu[] = 0, REAL wDuv[] = 0, REAL wDvv[] = 0) const;
|
||||
|
||||
/// \brief An overloaded version to assist template parameter resolution
|
||||
/// when explicitly declaring unused array arguments as 0.
|
||||
void EvaluateBasis(PatchHandle const & handle, float u, float v,
|
||||
float wP[], float wDu[] = 0, float wDv[] = 0,
|
||||
float wDuu[] = 0, float wDuv[] = 0, float wDvv[] = 0) const;
|
||||
|
||||
/// \brief An overloaded version to assist template parameter resolution
|
||||
/// when explicitly declaring unused array arguments as 0.
|
||||
void EvaluateBasis(PatchHandle const & handle, double u, double v,
|
||||
double wP[], double wDu[] = 0, double wDv[] = 0,
|
||||
double wDuu[] = 0, double wDuv[] = 0, double wDvv[] = 0) const;
|
||||
|
||||
/// \brief Evaluate basis functions for a varying value and
|
||||
/// derivatives at a given (u,v) parametric location of a patch.
|
||||
///
|
||||
/// @param handle A patch handle identifying the sub-patch containing the
|
||||
/// (u,v) location
|
||||
///
|
||||
/// @param u Patch coordinate (in base face normalized space)
|
||||
///
|
||||
/// @param v Patch coordinate (in base face normalized space)
|
||||
///
|
||||
/// @param wP Weights (evaluated basis functions) for the position
|
||||
///
|
||||
/// @param wDu Weights (evaluated basis functions) for derivative wrt u
|
||||
///
|
||||
/// @param wDv Weights (evaluated basis functions) for derivative wrt v
|
||||
///
|
||||
/// @param wDuu Weights (evaluated basis functions) for 2nd derivative wrt u
|
||||
///
|
||||
/// @param wDuv Weights (evaluated basis functions) for 2nd derivative wrt u and v
|
||||
///
|
||||
/// @param wDvv Weights (evaluated basis functions) for 2nd derivative wrt v
|
||||
///
|
||||
template <typename REAL>
|
||||
void EvaluateBasisVarying(PatchHandle const & handle, REAL u, REAL v,
|
||||
REAL wP[], REAL wDu[] = 0, REAL wDv[] = 0,
|
||||
REAL wDuu[] = 0, REAL wDuv[] = 0, REAL wDvv[] = 0) const;
|
||||
|
||||
/// \brief An overloaded version to assist template parameter resolution
|
||||
/// when explicitly declaring unused array arguments as 0.
|
||||
void EvaluateBasisVarying(PatchHandle const & handle, float u, float v,
|
||||
float wP[], float wDu[] = 0, float wDv[] = 0,
|
||||
float wDuu[] = 0, float wDuv[] = 0, float wDvv[] = 0) const;
|
||||
|
||||
/// \brief An overloaded version to assist template parameter resolution
|
||||
/// when explicitly declaring unused array arguments as 0.
|
||||
void EvaluateBasisVarying(PatchHandle const & handle, double u, double v,
|
||||
double wP[], double wDu[] = 0, double wDv[] = 0,
|
||||
double wDuu[] = 0, double wDuv[] = 0, double wDvv[] = 0) const;
|
||||
|
||||
/// \brief Evaluate basis functions for a face-varying value and
|
||||
/// derivatives at a given (u,v) parametric location of a patch.
|
||||
///
|
||||
/// @param handle A patch handle identifying the sub-patch containing the
|
||||
/// (u,v) location
|
||||
///
|
||||
/// @param u Patch coordinate (in base face normalized space)
|
||||
///
|
||||
/// @param v Patch coordinate (in base face normalized space)
|
||||
///
|
||||
/// @param wP Weights (evaluated basis functions) for the position
|
||||
///
|
||||
/// @param wDu Weights (evaluated basis functions) for derivative wrt u
|
||||
///
|
||||
/// @param wDv Weights (evaluated basis functions) for derivative wrt v
|
||||
///
|
||||
/// @param wDuu Weights (evaluated basis functions) for 2nd derivative wrt u
|
||||
///
|
||||
/// @param wDuv Weights (evaluated basis functions) for 2nd derivative wrt u and v
|
||||
///
|
||||
/// @param wDvv Weights (evaluated basis functions) for 2nd derivative wrt v
|
||||
///
|
||||
/// @param channel face-varying channel
|
||||
///
|
||||
template <typename REAL>
|
||||
void EvaluateBasisFaceVarying(PatchHandle const & handle, REAL u, REAL v,
|
||||
REAL wP[], REAL wDu[] = 0, REAL wDv[] = 0,
|
||||
REAL wDuu[] = 0, REAL wDuv[] = 0, REAL wDvv[] = 0,
|
||||
int channel = 0) const;
|
||||
|
||||
/// \brief An overloaded version to assist template parameter resolution
|
||||
/// when explicitly declaring unused array arguments as 0.
|
||||
void EvaluateBasisFaceVarying(PatchHandle const & handle, float u, float v,
|
||||
float wP[], float wDu[] = 0, float wDv[] = 0,
|
||||
float wDuu[] = 0, float wDuv[] = 0, float wDvv[] = 0,
|
||||
int channel = 0) const;
|
||||
|
||||
/// \brief An overloaded version to assist template parameter resolution
|
||||
/// when explicitly declaring unused array arguments as 0.
|
||||
void EvaluateBasisFaceVarying(PatchHandle const & handle, double u, double v,
|
||||
double wP[], double wDu[] = 0, double wDv[] = 0,
|
||||
double wDuu[] = 0, double wDuv[] = 0, double wDvv[] = 0,
|
||||
int channel = 0) const;
|
||||
//@}
|
||||
|
||||
protected:
|
||||
|
||||
friend class PatchTableBuilder;
|
||||
|
||||
// Factory constructor
|
||||
PatchTable(int maxvalence);
|
||||
|
||||
Index getPatchIndex(int array, int patch) const;
|
||||
|
||||
PatchParamArray getPatchParams(int arrayIndex);
|
||||
|
||||
Index * getSharpnessIndices(Index arrayIndex);
|
||||
float * getSharpnessValues(Index arrayIndex);
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
// Patch arrays
|
||||
//
|
||||
|
||||
struct PatchArray;
|
||||
typedef std::vector<PatchArray> PatchArrayVector;
|
||||
|
||||
PatchArray & getPatchArray(Index arrayIndex);
|
||||
PatchArray const & getPatchArray(Index arrayIndex) const;
|
||||
|
||||
void reservePatchArrays(int numPatchArrays);
|
||||
void pushPatchArray(PatchDescriptor desc, int npatches,
|
||||
Index * vidx, Index * pidx, Index * qoidx=0);
|
||||
|
||||
IndexArray getPatchArrayVertices(int arrayIndex);
|
||||
|
||||
Index findPatchArray(PatchDescriptor desc);
|
||||
|
||||
|
||||
//
|
||||
// Varying patch arrays
|
||||
//
|
||||
IndexArray getPatchArrayVaryingVertices(int arrayIndex);
|
||||
|
||||
void allocateVaryingVertices(
|
||||
PatchDescriptor desc, int numPatches);
|
||||
void populateVaryingVertices();
|
||||
|
||||
//
|
||||
// Face-varying patch channels
|
||||
//
|
||||
|
||||
struct FVarPatchChannel;
|
||||
typedef std::vector<FVarPatchChannel> FVarPatchChannelVector;
|
||||
|
||||
FVarPatchChannel & getFVarPatchChannel(int channel);
|
||||
FVarPatchChannel const & getFVarPatchChannel(int channel) const;
|
||||
|
||||
void allocateFVarPatchChannels(int numChannels);
|
||||
void allocateFVarPatchChannelValues(
|
||||
PatchDescriptor regDesc, PatchDescriptor irregDesc,
|
||||
int numPatches, int channel);
|
||||
|
||||
// deprecated
|
||||
void setFVarPatchChannelLinearInterpolation(
|
||||
Sdc::Options::FVarLinearInterpolation interpolation, int channel);
|
||||
|
||||
IndexArray getFVarValues(int channel);
|
||||
ConstIndexArray getPatchFVarValues(int patch, int channel) const;
|
||||
|
||||
PatchParamArray getFVarPatchParams(int channel);
|
||||
PatchParam getPatchFVarPatchParam(int patch, int channel) const;
|
||||
|
||||
private:
|
||||
//
|
||||
// Simple private class to hold stencil table pointers of varying precision,
|
||||
// where the discriminant of the precision is external.
|
||||
//
|
||||
// NOTE that this is a simple pointer container and NOT a smart pointer that
|
||||
// manages the ownership of the object referred to by it.
|
||||
//
|
||||
class StencilTablePtr {
|
||||
private:
|
||||
typedef StencilTableReal<float> float_type;
|
||||
typedef StencilTableReal<double> double_type;
|
||||
|
||||
union {
|
||||
float_type * _fPtr;
|
||||
double_type * _dPtr;
|
||||
};
|
||||
|
||||
public:
|
||||
StencilTablePtr() { _fPtr = 0; }
|
||||
StencilTablePtr(float_type * ptr) { _fPtr = ptr; }
|
||||
StencilTablePtr(double_type * ptr) { _dPtr = ptr; }
|
||||
|
||||
operator bool() const { return _fPtr != 0; }
|
||||
|
||||
void Set() { _fPtr = 0; }
|
||||
void Set(float_type * ptr) { _fPtr = ptr; }
|
||||
void Set(double_type * ptr) { _dPtr = ptr; }
|
||||
|
||||
template <typename REAL> StencilTableReal<REAL> * Get() const;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
// Topology
|
||||
//
|
||||
|
||||
int _maxValence, // highest vertex valence found in the mesh
|
||||
_numPtexFaces; // total number of ptex faces
|
||||
|
||||
PatchArrayVector _patchArrays; // Vector of descriptors for arrays of patches
|
||||
|
||||
std::vector<Index> _patchVerts; // Indices of the control vertices of the patches
|
||||
|
||||
PatchParamTable _paramTable; // PatchParam bitfields (one per patch)
|
||||
|
||||
//
|
||||
// Extraordinary vertex closed-form evaluation / endcap basis conversion
|
||||
//
|
||||
// XXXtakahito: these data will probably be replaced with mask coefficient or something
|
||||
// SchemeWorker populates.
|
||||
//
|
||||
QuadOffsetsTable _quadOffsetsTable; // Quad offsets (for Gregory patches)
|
||||
VertexValenceTable _vertexValenceTable; // Vertex valence table (for Gregory patches)
|
||||
|
||||
StencilTablePtr _localPointStencils; // local point conversion stencils
|
||||
StencilTablePtr _localPointVaryingStencils; // local point varying stencils
|
||||
|
||||
//
|
||||
// Varying data
|
||||
//
|
||||
PatchDescriptor _varyingDesc;
|
||||
|
||||
std::vector<Index> _varyingVerts;
|
||||
|
||||
//
|
||||
// Face-varying data
|
||||
//
|
||||
FVarPatchChannelVector _fvarChannels;
|
||||
|
||||
std::vector<StencilTablePtr> _localPointFaceVaryingStencils;
|
||||
|
||||
//
|
||||
// 'single-crease' patch sharpness tables
|
||||
//
|
||||
std::vector<Index> _sharpnessIndices; // Indices of single-crease sharpness (one per patch)
|
||||
std::vector<float> _sharpnessValues; // Sharpness values.
|
||||
|
||||
//
|
||||
// Construction history -- relevant to at least one public query:
|
||||
//
|
||||
unsigned int _isUniformLinear : 1;
|
||||
|
||||
//
|
||||
// Precision -- only applies to local-point stencil tables
|
||||
//
|
||||
unsigned int _vertexPrecisionIsDouble : 1;
|
||||
unsigned int _varyingPrecisionIsDouble : 1;
|
||||
unsigned int _faceVaryingPrecisionIsDouble : 1;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Template specializations for float/double -- to be defined before used:
|
||||
//
|
||||
template <> inline StencilTableReal<float> *
|
||||
PatchTable::StencilTablePtr::Get<float>() const { return _fPtr; }
|
||||
|
||||
template <> inline StencilTableReal<double> *
|
||||
PatchTable::StencilTablePtr::Get<double>() const { return _dPtr; }
|
||||
|
||||
template <> inline bool
|
||||
PatchTable::LocalPointStencilPrecisionMatchesType<float>() const {
|
||||
return !_vertexPrecisionIsDouble;
|
||||
}
|
||||
template <> inline bool
|
||||
PatchTable::LocalPointVaryingStencilPrecisionMatchesType<float>() const {
|
||||
return !_varyingPrecisionIsDouble;
|
||||
}
|
||||
template <> inline bool
|
||||
PatchTable::LocalPointFaceVaryingStencilPrecisionMatchesType<float>() const {
|
||||
return !_faceVaryingPrecisionIsDouble;
|
||||
}
|
||||
|
||||
template <> inline bool
|
||||
PatchTable::LocalPointStencilPrecisionMatchesType<double>() const {
|
||||
return _vertexPrecisionIsDouble;
|
||||
}
|
||||
template <> inline bool
|
||||
PatchTable::LocalPointVaryingStencilPrecisionMatchesType<double>() const {
|
||||
return _varyingPrecisionIsDouble;
|
||||
}
|
||||
template <> inline bool
|
||||
PatchTable::LocalPointFaceVaryingStencilPrecisionMatchesType<double>() const {
|
||||
return _faceVaryingPrecisionIsDouble;
|
||||
}
|
||||
|
||||
//
|
||||
// StencilTable access -- backward compatible and generic:
|
||||
//
|
||||
inline StencilTable const *
|
||||
PatchTable::GetLocalPointStencilTable() const {
|
||||
assert(LocalPointStencilPrecisionMatchesType<float>());
|
||||
return static_cast<StencilTable const *>(_localPointStencils.Get<float>());
|
||||
}
|
||||
inline StencilTable const *
|
||||
PatchTable::GetLocalPointVaryingStencilTable() const {
|
||||
assert(LocalPointVaryingStencilPrecisionMatchesType<float>());
|
||||
return static_cast<StencilTable const *>(
|
||||
_localPointVaryingStencils.Get<float>());
|
||||
}
|
||||
inline StencilTable const *
|
||||
PatchTable::GetLocalPointFaceVaryingStencilTable(int channel) const {
|
||||
assert(LocalPointFaceVaryingStencilPrecisionMatchesType<float>());
|
||||
if (channel >= 0 && channel < (int)_localPointFaceVaryingStencils.size()) {
|
||||
return static_cast<StencilTable const *>(
|
||||
_localPointFaceVaryingStencils[channel].Get<float>());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline StencilTableReal<REAL> const *
|
||||
PatchTable::GetLocalPointStencilTable() const {
|
||||
assert(LocalPointStencilPrecisionMatchesType<REAL>());
|
||||
return _localPointStencils.Get<REAL>();
|
||||
}
|
||||
template <typename REAL>
|
||||
inline StencilTableReal<REAL> const *
|
||||
PatchTable::GetLocalPointVaryingStencilTable() const {
|
||||
assert(LocalPointVaryingStencilPrecisionMatchesType<REAL>());
|
||||
return _localPointVaryingStencils.Get<REAL>();
|
||||
}
|
||||
template <typename REAL>
|
||||
inline StencilTableReal<REAL> const *
|
||||
PatchTable::GetLocalPointFaceVaryingStencilTable(int channel) const {
|
||||
assert(LocalPointFaceVaryingStencilPrecisionMatchesType<REAL>());
|
||||
if (channel >= 0 && channel < (int)_localPointFaceVaryingStencils.size()) {
|
||||
return _localPointFaceVaryingStencils[channel].Get<REAL>();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Computation of local point values:
|
||||
//
|
||||
template <class T>
|
||||
inline void
|
||||
PatchTable::ComputeLocalPointValues(T const *src, T *dst) const {
|
||||
assert(LocalPointStencilPrecisionMatchesType<float>());
|
||||
if (_localPointStencils) {
|
||||
_localPointStencils.Get<float>()->UpdateValues(src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void
|
||||
PatchTable::ComputeLocalPointValuesVarying(T const *src, T *dst) const {
|
||||
assert(LocalPointVaryingStencilPrecisionMatchesType<float>());
|
||||
if (_localPointVaryingStencils) {
|
||||
_localPointVaryingStencils.Get<float>()->UpdateValues(src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void
|
||||
PatchTable::ComputeLocalPointValuesFaceVarying(T const *src, T *dst, int channel) const {
|
||||
assert(LocalPointFaceVaryingStencilPrecisionMatchesType<float>());
|
||||
if (channel >= 0 && channel < (int)_localPointFaceVaryingStencils.size()) {
|
||||
if (_localPointFaceVaryingStencils[channel]) {
|
||||
_localPointFaceVaryingStencils[channel].Get<float>()->UpdateValues(src, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Basis evaluation overloads
|
||||
//
|
||||
inline void
|
||||
PatchTable::EvaluateBasis(PatchHandle const & handle, float u, float v,
|
||||
float wP[], float wDu[], float wDv[],
|
||||
float wDuu[], float wDuv[], float wDvv[]) const {
|
||||
|
||||
EvaluateBasis<float>(handle, u, v, wP, wDu, wDv, wDuu, wDuv, wDvv);
|
||||
}
|
||||
inline void
|
||||
PatchTable::EvaluateBasis(PatchHandle const & handle, double u, double v,
|
||||
double wP[], double wDu[], double wDv[],
|
||||
double wDuu[], double wDuv[], double wDvv[]) const {
|
||||
|
||||
EvaluateBasis<double>(handle, u, v, wP, wDu, wDv, wDuu, wDuv, wDvv);
|
||||
}
|
||||
|
||||
inline void
|
||||
PatchTable::EvaluateBasisVarying(PatchHandle const & handle, float u, float v,
|
||||
float wP[], float wDu[], float wDv[],
|
||||
float wDuu[], float wDuv[], float wDvv[]) const {
|
||||
|
||||
EvaluateBasisVarying<float>(handle, u, v, wP, wDu, wDv, wDuu, wDuv, wDvv);
|
||||
}
|
||||
inline void
|
||||
PatchTable::EvaluateBasisVarying(PatchHandle const & handle, double u, double v,
|
||||
double wP[], double wDu[], double wDv[],
|
||||
double wDuu[], double wDuv[], double wDvv[]) const {
|
||||
|
||||
EvaluateBasisVarying<double>(handle, u, v, wP, wDu, wDv, wDuu, wDuv, wDvv);
|
||||
}
|
||||
|
||||
inline void
|
||||
PatchTable::EvaluateBasisFaceVarying(PatchHandle const & handle, float u, float v,
|
||||
float wP[], float wDu[], float wDv[],
|
||||
float wDuu[], float wDuv[], float wDvv[], int channel) const {
|
||||
|
||||
EvaluateBasisFaceVarying<float>(handle, u, v, wP, wDu, wDv, wDuu, wDuv, wDvv, channel);
|
||||
}
|
||||
inline void
|
||||
PatchTable::EvaluateBasisFaceVarying(PatchHandle const & handle, double u, double v,
|
||||
double wP[], double wDu[], double wDv[],
|
||||
double wDuu[], double wDuv[], double wDvv[], int channel) const {
|
||||
|
||||
EvaluateBasisFaceVarying<double>(handle, u, v, wP, wDu, wDv, wDuu, wDuv, wDvv, channel);
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PATCH_TABLE */
|
||||
2050
src/osd/opensubdiv/far/patchTableFactory.cpp
Normal file
2050
src/osd/opensubdiv/far/patchTableFactory.cpp
Normal file
File diff suppressed because it is too large
Load Diff
232
src/osd/opensubdiv/far/patchTableFactory.h
Normal file
232
src/osd/opensubdiv/far/patchTableFactory.h
Normal file
@@ -0,0 +1,232 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_PATCH_TABLE_FACTORY_H
|
||||
#define OPENSUBDIV3_FAR_PATCH_TABLE_FACTORY_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../far/patchTable.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
/// \brief Factory for constructing a PatchTable from a TopologyRefiner
|
||||
///
|
||||
class PatchTableFactory {
|
||||
public:
|
||||
|
||||
/// \brief Public options for the PatchTable factory
|
||||
///
|
||||
struct Options {
|
||||
|
||||
/// \brief Choice for approximating irregular patches (end-caps)
|
||||
///
|
||||
/// This enum specifies how irregular patches (end-caps) are approximated.
|
||||
/// A basis is chosen, rather than a specific patch type, and has a
|
||||
/// corresponding patch type for each subdivision scheme, i.e. a quad and
|
||||
/// triangular patch type exists for each basis. These choices provide a
|
||||
/// trade-off between surface quality and performance.
|
||||
///
|
||||
enum EndCapType {
|
||||
ENDCAP_NONE = 0, ///< unspecified
|
||||
ENDCAP_BILINEAR_BASIS, ///< use linear patches (simple quads or tris)
|
||||
ENDCAP_BSPLINE_BASIS, ///< use BSpline-like patches (same patch type as regular)
|
||||
ENDCAP_GREGORY_BASIS, ///< use Gregory patches (highest quality, recommended default)
|
||||
ENDCAP_LEGACY_GREGORY ///< legacy option for 2.x style Gregory patches (Catmark only)
|
||||
};
|
||||
|
||||
Options(unsigned int maxIsolation=10) :
|
||||
generateAllLevels(false),
|
||||
includeBaseLevelIndices(true),
|
||||
includeFVarBaseLevelIndices(false),
|
||||
triangulateQuads(false),
|
||||
useSingleCreasePatch(false),
|
||||
useInfSharpPatch(false),
|
||||
maxIsolationLevel(maxIsolation),
|
||||
endCapType(ENDCAP_GREGORY_BASIS),
|
||||
shareEndCapPatchPoints(true),
|
||||
generateVaryingTables(true),
|
||||
generateVaryingLocalPoints(true),
|
||||
generateFVarTables(false),
|
||||
patchPrecisionDouble(false),
|
||||
fvarPatchPrecisionDouble(false),
|
||||
generateFVarLegacyLinearPatches(true),
|
||||
generateLegacySharpCornerPatches(true),
|
||||
numFVarChannels(-1),
|
||||
fvarChannelIndices(0)
|
||||
{ }
|
||||
|
||||
/// \brief Get endcap basis type
|
||||
EndCapType GetEndCapType() const { return (EndCapType)endCapType; }
|
||||
|
||||
/// \brief Set endcap basis type
|
||||
void SetEndCapType(EndCapType e) { endCapType = e; }
|
||||
|
||||
/// \brief Set precision of vertex patches
|
||||
template <typename REAL> void SetPatchPrecision();
|
||||
|
||||
/// \brief Set precision of face-varying patches
|
||||
template <typename REAL> void SetFVarPatchPrecision();
|
||||
|
||||
/// \brief Determine adaptive refinement options to match assigned patch options
|
||||
TopologyRefiner::AdaptiveOptions GetRefineAdaptiveOptions() const {
|
||||
TopologyRefiner::AdaptiveOptions adaptiveOptions(maxIsolationLevel);
|
||||
|
||||
adaptiveOptions.useInfSharpPatch = useInfSharpPatch;
|
||||
adaptiveOptions.useSingleCreasePatch = useSingleCreasePatch;
|
||||
adaptiveOptions.considerFVarChannels = generateFVarTables &&
|
||||
!generateFVarLegacyLinearPatches;
|
||||
return adaptiveOptions;
|
||||
}
|
||||
|
||||
unsigned int generateAllLevels : 1, ///< Generate levels from 'firstLevel' to 'maxLevel' (Uniform mode only)
|
||||
includeBaseLevelIndices : 1, ///< Include base level in patch point indices (Uniform mode only)
|
||||
includeFVarBaseLevelIndices : 1, ///< Include base level in face-varying patch point indices (Uniform mode only)
|
||||
triangulateQuads : 1, ///< Triangulate 'QUADS' primitives (Uniform mode only)
|
||||
|
||||
useSingleCreasePatch : 1, ///< Use single crease patch
|
||||
useInfSharpPatch : 1, ///< Use infinitely-sharp patch
|
||||
maxIsolationLevel : 4, ///< Cap adaptive feature isolation to the given level (max. 10)
|
||||
|
||||
// end-capping
|
||||
endCapType : 3, ///< EndCapType
|
||||
shareEndCapPatchPoints : 1, ///< Share endcap patch points among adjacent endcap patches.
|
||||
///< currently only work with GregoryBasis.
|
||||
|
||||
// varying
|
||||
generateVaryingTables : 1, ///< Generate varying patch tables
|
||||
generateVaryingLocalPoints : 1, ///< Generate local points with varying patches
|
||||
|
||||
// face-varying
|
||||
generateFVarTables : 1, ///< Generate face-varying patch tables
|
||||
|
||||
// precision
|
||||
patchPrecisionDouble : 1, ///< Generate double-precision stencils for vertex patches
|
||||
fvarPatchPrecisionDouble : 1, ///< Generate double-precision stencils for face-varying patches
|
||||
|
||||
// legacy behaviors (default to true)
|
||||
generateFVarLegacyLinearPatches : 1, ///< Generate all linear face-varying patches (legacy)
|
||||
generateLegacySharpCornerPatches : 1; ///< Generate sharp regular patches at smooth corners (legacy)
|
||||
|
||||
int numFVarChannels; ///< Number of channel indices and interpolation modes passed
|
||||
int const * fvarChannelIndices; ///< List containing the indices of the channels selected for the factory
|
||||
};
|
||||
|
||||
/// \brief Instantiates a PatchTable from a client-provided TopologyRefiner.
|
||||
///
|
||||
/// A PatchTable can be constructed from a TopologyRefiner that has been
|
||||
/// either adaptively or uniformly refined. In both cases, the resulting
|
||||
/// patches reference vertices in the various refined levels by index,
|
||||
/// and those indices accumulate with the levels in different ways.
|
||||
///
|
||||
/// For adaptively refined patches, patches are defined at different levels,
|
||||
/// including the base level, so the indices of patch vertices include
|
||||
/// vertices from all levels. A sparse set of patches can be created by
|
||||
/// restricting the patches generated to those descending from a given set
|
||||
/// of faces at the base level. This sparse set of base faces is expected
|
||||
/// to be a subset of the faces that were adaptively refined in the given
|
||||
/// TopologyRefiner, otherwise results are undefined.
|
||||
///
|
||||
/// For uniformly refined patches, all patches are completely defined within
|
||||
/// the last level. There is often no use for intermediate levels and they
|
||||
/// can usually be ignored. Indices of patch vertices might therefore be
|
||||
/// expected to be defined solely within the last level. While this is true
|
||||
/// for face-varying patches, for historical reasons it is not the case for
|
||||
/// vertex and varying patches. Indices for vertex and varying patches include
|
||||
/// the base level in addition to the last level while indices for face-varying
|
||||
/// patches include only the last level.
|
||||
///
|
||||
/// @param refiner TopologyRefiner from which to generate patches
|
||||
///
|
||||
/// @param options Options controlling the creation of the table
|
||||
///
|
||||
/// @param selectedFaces Only create patches for the given set of base faces.
|
||||
///
|
||||
/// @return A new instance of PatchTable
|
||||
///
|
||||
static PatchTable * Create(TopologyRefiner const & refiner,
|
||||
Options options = Options(),
|
||||
ConstIndexArray selectedFaces = ConstIndexArray());
|
||||
|
||||
public:
|
||||
// PatchFaceTag
|
||||
//
|
||||
// This simple struct was previously used within the factory to take inventory of
|
||||
// various kinds of patches to fully allocate buffers prior to populating them. It
|
||||
// was not intended to be exposed as part of the public interface.
|
||||
//
|
||||
// It is no longer used internally and is being kept here to respect preservation
|
||||
// of the public interface, but it will be deprecated at the earliest opportunity.
|
||||
//
|
||||
/// \brief Obsolete internal struct not intended for public use -- due to
|
||||
/// be deprecated.
|
||||
//
|
||||
struct PatchFaceTag {
|
||||
public:
|
||||
unsigned int _hasPatch : 1;
|
||||
unsigned int _isRegular : 1;
|
||||
unsigned int _transitionMask : 4;
|
||||
unsigned int _boundaryMask : 4;
|
||||
unsigned int _boundaryIndex : 2;
|
||||
unsigned int _boundaryCount : 3;
|
||||
unsigned int _hasBoundaryEdge : 3;
|
||||
unsigned int _isSingleCrease : 1;
|
||||
|
||||
void clear();
|
||||
void assignBoundaryPropertiesFromEdgeMask(int boundaryEdgeMask);
|
||||
void assignBoundaryPropertiesFromVertexMask(int boundaryVertexMask);
|
||||
void assignTransitionPropertiesFromEdgeMask(int boundaryVertexMask);
|
||||
};
|
||||
typedef std::vector<PatchFaceTag> PatchTagVector;
|
||||
};
|
||||
|
||||
|
||||
template <> inline void PatchTableFactory::Options::SetPatchPrecision<float>() {
|
||||
patchPrecisionDouble = false;
|
||||
}
|
||||
template <> inline void PatchTableFactory::Options::SetFVarPatchPrecision<float>() {
|
||||
fvarPatchPrecisionDouble = false;
|
||||
}
|
||||
|
||||
template <> inline void PatchTableFactory::Options::SetPatchPrecision<double>() {
|
||||
patchPrecisionDouble = true;
|
||||
}
|
||||
template <> inline void PatchTableFactory::Options::SetFVarPatchPrecision<double>() {
|
||||
fvarPatchPrecisionDouble = true;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PATCH_TABLE_FACTORY_H */
|
||||
1272
src/osd/opensubdiv/far/primvarRefiner.h
Normal file
1272
src/osd/opensubdiv/far/primvarRefiner.h
Normal file
File diff suppressed because it is too large
Load Diff
213
src/osd/opensubdiv/far/ptexIndices.cpp
Normal file
213
src/osd/opensubdiv/far/ptexIndices.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
#include "../far/ptexIndices.h"
|
||||
|
||||
#include "../far/error.h"
|
||||
#include "../vtr/level.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
|
||||
PtexIndices::PtexIndices(TopologyRefiner const &refiner) {
|
||||
initializePtexIndices(refiner);
|
||||
}
|
||||
|
||||
PtexIndices::~PtexIndices() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PtexIndices::initializePtexIndices(TopologyRefiner const &refiner) {
|
||||
|
||||
int regFaceSize = Sdc::SchemeTypeTraits::GetRegularFaceSize(
|
||||
refiner.GetSchemeType());
|
||||
|
||||
Vtr::internal::Level const & coarseLevel = refiner.getLevel(0);
|
||||
|
||||
int nfaces = coarseLevel.getNumFaces();
|
||||
_ptexIndices.resize(nfaces+1);
|
||||
int ptexID=0;
|
||||
for (int i = 0; i < nfaces; ++i) {
|
||||
_ptexIndices[i] = ptexID;
|
||||
Vtr::ConstIndexArray fverts = coarseLevel.getFaceVertices(i);
|
||||
ptexID += fverts.size()==regFaceSize ? 1 : fverts.size();
|
||||
}
|
||||
// last entry contains the number of ptex texture faces
|
||||
_ptexIndices[nfaces]=ptexID;
|
||||
}
|
||||
|
||||
int
|
||||
PtexIndices::GetNumFaces() const {
|
||||
return _ptexIndices.back();
|
||||
}
|
||||
|
||||
int
|
||||
PtexIndices::GetFaceId(Index f) const {
|
||||
assert(f<(int)_ptexIndices.size());
|
||||
return _ptexIndices[f];
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Returns the face adjacent to 'face' along edge 'edge'
|
||||
inline Index
|
||||
getAdjacentFace(Vtr::internal::Level const & level, Index edge, Index face) {
|
||||
Far::ConstIndexArray adjFaces = level.getEdgeFaces(edge);
|
||||
if (adjFaces.size()!=2) {
|
||||
return -1;
|
||||
}
|
||||
return (adjFaces[0]==face) ? adjFaces[1] : adjFaces[0];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PtexIndices::GetAdjacency(
|
||||
TopologyRefiner const &refiner,
|
||||
int face, int quadrant,
|
||||
int adjFaces[4], int adjEdges[4]) const {
|
||||
|
||||
int regFaceSize =
|
||||
Sdc::SchemeTypeTraits::GetRegularFaceSize(refiner.GetSchemeType());
|
||||
|
||||
Vtr::internal::Level const & level = refiner.getLevel(0);
|
||||
|
||||
ConstIndexArray fedges = level.getFaceEdges(face);
|
||||
|
||||
if (fedges.size() == regFaceSize) {
|
||||
|
||||
// Regular ptex quad face
|
||||
for (int i=0; i<regFaceSize; ++i) {
|
||||
int edge = fedges[i];
|
||||
Index adjface = getAdjacentFace(level, edge, face);
|
||||
if (adjface==-1) {
|
||||
adjFaces[i] = -1; // boundary or non-manifold
|
||||
adjEdges[i] = 0;
|
||||
} else {
|
||||
|
||||
ConstIndexArray aedges = level.getFaceEdges(adjface);
|
||||
if (aedges.size()==regFaceSize) {
|
||||
adjFaces[i] = _ptexIndices[adjface];
|
||||
adjEdges[i] = aedges.FindIndex(edge);
|
||||
assert(adjEdges[i]!=-1);
|
||||
} else {
|
||||
// neighbor is a sub-face
|
||||
adjFaces[i] = _ptexIndices[adjface] +
|
||||
(aedges.FindIndex(edge)+1)%aedges.size();
|
||||
adjEdges[i] = 3;
|
||||
}
|
||||
assert(adjFaces[i]!=-1);
|
||||
}
|
||||
}
|
||||
if (regFaceSize == 3) {
|
||||
adjFaces[3] = -1;
|
||||
adjEdges[3] = 0;
|
||||
}
|
||||
} else if (regFaceSize == 4) {
|
||||
|
||||
// Ptex sub-face 'quadrant' (non-quad)
|
||||
//
|
||||
// Ptex adjacency pattern for non-quads:
|
||||
//
|
||||
// v2
|
||||
/* o
|
||||
// / \
|
||||
// / \
|
||||
// /0 3\
|
||||
// / \
|
||||
// o_ 1 2 _o
|
||||
// / -_ _- \
|
||||
// / 2 -o- 1 \
|
||||
// /3 | 0\
|
||||
// / 1|2 \
|
||||
// / 0 | 3 \
|
||||
// o----------o----------o
|
||||
// v0 v1
|
||||
*/
|
||||
assert(quadrant>=0 && quadrant<fedges.size());
|
||||
|
||||
int nextQuadrant = (quadrant+1) % fedges.size(),
|
||||
prevQuadrant = (quadrant+fedges.size()-1) % fedges.size();
|
||||
|
||||
{ // resolve neighbors within the sub-face (edges 1 & 2)
|
||||
adjFaces[1] = _ptexIndices[face] + nextQuadrant;
|
||||
adjEdges[1] = 2;
|
||||
|
||||
adjFaces[2] = _ptexIndices[face] + prevQuadrant;
|
||||
adjEdges[2] = 1;
|
||||
}
|
||||
|
||||
{ // resolve neighbor outside the sub-face (edge 0)
|
||||
int edge0 = fedges[quadrant];
|
||||
Index adjface0 = getAdjacentFace(level, edge0, face);
|
||||
if (adjface0==-1) {
|
||||
adjFaces[0] = -1; // boundary or non-manifold
|
||||
adjEdges[0] = 0;
|
||||
} else {
|
||||
ConstIndexArray afedges = level.getFaceEdges(adjface0);
|
||||
if (afedges.size()==4) {
|
||||
adjFaces[0] = _ptexIndices[adjface0];
|
||||
adjEdges[0] = afedges.FindIndexIn4Tuple(edge0);
|
||||
} else {
|
||||
int subedge = (afedges.FindIndex(edge0)+1)%afedges.size();
|
||||
adjFaces[0] = _ptexIndices[adjface0] + subedge;
|
||||
adjEdges[0] = 3;
|
||||
}
|
||||
assert(adjFaces[0]!=-1);
|
||||
}
|
||||
|
||||
// resolve neighbor outside the sub-face (edge 3)
|
||||
int edge3 = fedges[prevQuadrant];
|
||||
Index adjface3 = getAdjacentFace(level, edge3, face);
|
||||
if (adjface3==-1) {
|
||||
adjFaces[3]=-1; // boundary or non-manifold
|
||||
adjEdges[3]=0;
|
||||
} else {
|
||||
ConstIndexArray afedges = level.getFaceEdges(adjface3);
|
||||
if (afedges.size()==4) {
|
||||
adjFaces[3] = _ptexIndices[adjface3];
|
||||
adjEdges[3] = afedges.FindIndexIn4Tuple(edge3);
|
||||
} else {
|
||||
int subedge = afedges.FindIndex(edge3);
|
||||
adjFaces[3] = _ptexIndices[adjface3] + subedge;
|
||||
adjEdges[3] = 0;
|
||||
}
|
||||
assert(adjFaces[3]!=-1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Far::Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in PtexIndices::GetAdjacency() -- "
|
||||
"irregular faces only supported for quad schemes.");
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
106
src/osd/opensubdiv/far/ptexIndices.h
Normal file
106
src/osd/opensubdiv/far/ptexIndices.h
Normal file
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_FAR_PTEX_INDICES_H
|
||||
#define OPENSUBDIV3_FAR_PTEX_INDICES_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../far/types.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
///
|
||||
/// \brief Object used to compute and query ptex face indices.
|
||||
///
|
||||
/// Given a refiner, constructing a PtexIndices object builds the mapping
|
||||
/// from coarse faces to ptex ids. Once built, the object can be used to
|
||||
/// query the mapping.
|
||||
///
|
||||
class PtexIndices {
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Constructor
|
||||
PtexIndices(TopologyRefiner const &refiner);
|
||||
|
||||
/// \brief Destructor
|
||||
~PtexIndices();
|
||||
|
||||
//@{
|
||||
///
|
||||
/// Ptex
|
||||
///
|
||||
|
||||
/// \brief Returns the number of ptex faces in the mesh
|
||||
///
|
||||
int GetNumFaces() const;
|
||||
|
||||
/// \brief Returns the ptex face index given a coarse face 'f' or -1
|
||||
///
|
||||
int GetFaceId(Index f) const;
|
||||
|
||||
/// \brief Returns ptex face adjacency information for a given coarse face
|
||||
///
|
||||
/// @param refiner refiner used to build this PtexIndices object.
|
||||
///
|
||||
/// @param face coarse face index
|
||||
///
|
||||
/// @param quadrant quadrant index if 'face' is not a quad (the local ptex
|
||||
/// sub-face index). Must be less than the number of face
|
||||
/// vertices.
|
||||
///
|
||||
/// @param adjFaces ptex face indices of adjacent faces
|
||||
///
|
||||
/// @param adjEdges ptex edge indices of adjacent faces
|
||||
///
|
||||
void GetAdjacency(
|
||||
TopologyRefiner const &refiner,
|
||||
int face, int quadrant,
|
||||
int adjFaces[4], int adjEdges[4]) const;
|
||||
|
||||
//@}
|
||||
|
||||
private:
|
||||
|
||||
void initializePtexIndices(TopologyRefiner const &refiner);
|
||||
|
||||
private:
|
||||
|
||||
std::vector<Index> _ptexIndices;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PTEX_INDICES_H */
|
||||
199
src/osd/opensubdiv/far/sparseMatrix.h
Normal file
199
src/osd/opensubdiv/far/sparseMatrix.h
Normal file
@@ -0,0 +1,199 @@
|
||||
//
|
||||
// Copyright 2017 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_SPARSE_MATRIX_H
|
||||
#define OPENSUBDIV3_FAR_SPARSE_MATRIX_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../vtr/array.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// SparseMatrix
|
||||
//
|
||||
// The SparseMatrix class is used by the PatchBuilder to store coefficients
|
||||
// for a set of patch points derived from some other set of points -- usually
|
||||
// the refined points in a subdivision level. The compressed sparse row
|
||||
// format (CSR) is used as it provides us with stencils for points that
|
||||
// correspond to rows and so can be more directly and efficiently copied.
|
||||
//
|
||||
// It has potential for other uses and so may eventually warrant a seperate
|
||||
// header file of its own. For now, in keeping with the trend of exposing
|
||||
// classes only where used, it is defined with the PatchBuilder.
|
||||
//
|
||||
// We may also want to explore the possibility of being able to assign
|
||||
// static buffers as members here -- allowing common matrices to be set
|
||||
// directly rather than repeatedly replicated.
|
||||
//
|
||||
template <typename REAL>
|
||||
class SparseMatrix {
|
||||
public:
|
||||
typedef int column_type;
|
||||
typedef REAL element_type;
|
||||
|
||||
public:
|
||||
// Declaration and access methods:
|
||||
SparseMatrix() : _numRows(0), _numColumns(0), _numElements(0) { }
|
||||
|
||||
int GetNumRows() const { return _numRows; }
|
||||
int GetNumColumns() const { return _numColumns; }
|
||||
int GetNumElements() const { return _numElements; }
|
||||
int GetCapacity() const;
|
||||
|
||||
int GetRowSize(int rowIndex) const {
|
||||
return _rowOffsets[rowIndex + 1] - _rowOffsets[rowIndex];
|
||||
}
|
||||
|
||||
Vtr::ConstArray<column_type> GetRowColumns( int rowIndex) const {
|
||||
return Vtr::ConstArray<column_type>(&_columns[_rowOffsets[rowIndex]],
|
||||
GetRowSize(rowIndex));
|
||||
}
|
||||
Vtr::ConstArray<element_type> GetRowElements(int rowIndex) const {
|
||||
return Vtr::ConstArray<element_type>(&_elements[_rowOffsets[rowIndex]],
|
||||
GetRowSize(rowIndex));
|
||||
}
|
||||
|
||||
Vtr::ConstArray<column_type> GetColumns() const {
|
||||
return Vtr::ConstArray<column_type>(&_columns[0], GetNumElements());
|
||||
}
|
||||
Vtr::ConstArray<element_type> GetElements() const {
|
||||
return Vtr::ConstArray<element_type>(&_elements[0], GetNumElements());
|
||||
}
|
||||
|
||||
public:
|
||||
// Modification methods
|
||||
void Resize(int numRows, int numColumns, int numNonZeroEntriesToReserve);
|
||||
void Copy(SparseMatrix const & srcMatrix);
|
||||
void Swap(SparseMatrix & otherMatrix);
|
||||
|
||||
void SetRowSize(int rowIndex, int size);
|
||||
|
||||
Vtr::Array<column_type> SetRowColumns( int rowIndex) {
|
||||
return Vtr::Array<column_type>(&_columns[_rowOffsets[rowIndex]],
|
||||
GetRowSize(rowIndex));
|
||||
}
|
||||
Vtr::Array<element_type> SetRowElements(int rowIndex) {
|
||||
return Vtr::Array<element_type>(&_elements[_rowOffsets[rowIndex]],
|
||||
GetRowSize(rowIndex));
|
||||
}
|
||||
|
||||
private:
|
||||
// Simple dimensions:
|
||||
int _numRows;
|
||||
int _numColumns;
|
||||
int _numElements;
|
||||
|
||||
std::vector<int> _rowOffsets; // remember one more entry here than rows
|
||||
|
||||
// XXXX (barfowl) - Note that the use of std::vector for the columns and
|
||||
// element arrays was causing performance issues in the incremental
|
||||
// resizing of consecutive rows, so we've been exploring alternatives...
|
||||
std::vector<column_type> _columns;
|
||||
std::vector<element_type> _elements;
|
||||
};
|
||||
|
||||
template <typename REAL>
|
||||
inline int
|
||||
SparseMatrix<REAL>::GetCapacity() const {
|
||||
|
||||
return (int) _elements.size();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
SparseMatrix<REAL>::Resize(int numRows, int numCols, int numElementsToReserve) {
|
||||
|
||||
_numRows = numRows;
|
||||
_numColumns = numCols;
|
||||
_numElements = 0;
|
||||
|
||||
_rowOffsets.resize(0);
|
||||
_rowOffsets.resize(_numRows + 1, -1);
|
||||
_rowOffsets[0] = 0;
|
||||
|
||||
if (numElementsToReserve > GetCapacity()) {
|
||||
_columns.resize(numElementsToReserve);
|
||||
_elements.resize(numElementsToReserve);
|
||||
}
|
||||
}
|
||||
template <typename REAL>
|
||||
inline void
|
||||
SparseMatrix<REAL>::SetRowSize(int rowIndex, int rowSize) {
|
||||
|
||||
assert(_rowOffsets[rowIndex] == _numElements);
|
||||
|
||||
int & newVectorSize = _rowOffsets[rowIndex + 1];
|
||||
newVectorSize = _rowOffsets[rowIndex] + rowSize;
|
||||
|
||||
_numElements = newVectorSize;
|
||||
if (newVectorSize > GetCapacity()) {
|
||||
_columns.resize(newVectorSize);
|
||||
_elements.resize(newVectorSize);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
SparseMatrix<REAL>::Copy(SparseMatrix const & src) {
|
||||
|
||||
_numRows = src._numRows;
|
||||
_numColumns = src._numColumns;
|
||||
|
||||
_rowOffsets = src._rowOffsets;
|
||||
|
||||
_numElements = src._numElements;
|
||||
|
||||
_columns = src._columns;
|
||||
_elements = src._elements;
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
SparseMatrix<REAL>::Swap(SparseMatrix & other) {
|
||||
|
||||
std::swap(_numRows, other._numRows);
|
||||
std::swap(_numColumns, other._numColumns);
|
||||
std::swap(_numElements, other._numElements);
|
||||
|
||||
_rowOffsets.swap(other._rowOffsets);
|
||||
_columns.swap(other._columns);
|
||||
_elements.swap(other._elements);
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_SPARSE_MATRIX_H */
|
||||
606
src/osd/opensubdiv/far/stencilBuilder.cpp
Normal file
606
src/osd/opensubdiv/far/stencilBuilder.cpp
Normal file
@@ -0,0 +1,606 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../far/stencilBuilder.h"
|
||||
#include "../far/topologyRefiner.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning (push)
|
||||
#pragma warning disable 1572
|
||||
#endif
|
||||
|
||||
template <typename REAL>
|
||||
inline bool isWeightZero(REAL w) { return (w == (REAL)0.0); }
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
struct Point1stDerivWeight {
|
||||
REAL p;
|
||||
REAL du;
|
||||
REAL dv;
|
||||
|
||||
Point1stDerivWeight()
|
||||
: p(0.0f), du(0.0f), dv(0.0f)
|
||||
{ }
|
||||
Point1stDerivWeight(REAL w)
|
||||
: p(w), du(w), dv(w)
|
||||
{ }
|
||||
Point1stDerivWeight(REAL w, REAL wDu, REAL wDv)
|
||||
: p(w), du(wDu), dv(wDv)
|
||||
{ }
|
||||
|
||||
friend Point1stDerivWeight operator*(Point1stDerivWeight lhs,
|
||||
Point1stDerivWeight const& rhs) {
|
||||
lhs.p *= rhs.p;
|
||||
lhs.du *= rhs.du;
|
||||
lhs.dv *= rhs.dv;
|
||||
return lhs;
|
||||
}
|
||||
Point1stDerivWeight& operator+=(Point1stDerivWeight const& rhs) {
|
||||
p += rhs.p;
|
||||
du += rhs.du;
|
||||
dv += rhs.dv;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename REAL>
|
||||
struct Point2ndDerivWeight {
|
||||
REAL p;
|
||||
REAL du;
|
||||
REAL dv;
|
||||
REAL duu;
|
||||
REAL duv;
|
||||
REAL dvv;
|
||||
|
||||
Point2ndDerivWeight()
|
||||
: p(0.0f), du(0.0f), dv(0.0f), duu(0.0f), duv(0.0f), dvv(0.0f)
|
||||
{ }
|
||||
Point2ndDerivWeight(REAL w)
|
||||
: p(w), du(w), dv(w), duu(w), duv(w), dvv(w)
|
||||
{ }
|
||||
Point2ndDerivWeight(REAL w, REAL wDu, REAL wDv,
|
||||
REAL wDuu, REAL wDuv, REAL wDvv)
|
||||
: p(w), du(wDu), dv(wDv), duu(wDuu), duv(wDuv), dvv(wDvv)
|
||||
{ }
|
||||
|
||||
friend Point2ndDerivWeight operator*(Point2ndDerivWeight lhs,
|
||||
Point2ndDerivWeight const& rhs) {
|
||||
lhs.p *= rhs.p;
|
||||
lhs.du *= rhs.du;
|
||||
lhs.dv *= rhs.dv;
|
||||
lhs.duu *= rhs.duu;
|
||||
lhs.duv *= rhs.duv;
|
||||
lhs.dvv *= rhs.dvv;
|
||||
return lhs;
|
||||
}
|
||||
Point2ndDerivWeight& operator+=(Point2ndDerivWeight const& rhs) {
|
||||
p += rhs.p;
|
||||
du += rhs.du;
|
||||
dv += rhs.dv;
|
||||
duu += rhs.duu;
|
||||
duv += rhs.duv;
|
||||
dvv += rhs.dvv;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// Stencil table constructor set.
|
||||
///
|
||||
template <typename REAL>
|
||||
class WeightTable {
|
||||
public:
|
||||
WeightTable(int coarseVerts,
|
||||
bool genCtrlVertStencils,
|
||||
bool compactWeights)
|
||||
: _size(0)
|
||||
, _lastOffset(0)
|
||||
, _coarseVertCount(coarseVerts)
|
||||
, _compactWeights(compactWeights)
|
||||
{
|
||||
// These numbers were chosen by profiling production assets at uniform
|
||||
// level 3.
|
||||
size_t n = std::max(coarseVerts,
|
||||
std::min(int(5*1024*1024),
|
||||
coarseVerts*2));
|
||||
_dests.reserve(n);
|
||||
_sources.reserve(n);
|
||||
_weights.reserve(n);
|
||||
|
||||
if (!genCtrlVertStencils)
|
||||
return;
|
||||
|
||||
// Generate trivial control vert stencils
|
||||
_sources.resize(coarseVerts);
|
||||
_weights.resize(coarseVerts);
|
||||
_dests.resize(coarseVerts);
|
||||
_indices.resize(coarseVerts);
|
||||
_sizes.resize(coarseVerts);
|
||||
|
||||
for (int i = 0; i < coarseVerts; i++) {
|
||||
_indices[i] = i;
|
||||
_sizes[i] = 1;
|
||||
_dests[i] = i;
|
||||
_sources[i] = i;
|
||||
_weights[i] = 1.0;
|
||||
}
|
||||
|
||||
_size = static_cast<int>(_sources.size());
|
||||
_lastOffset = _size - 1;
|
||||
}
|
||||
|
||||
template <class W, class WACCUM>
|
||||
void AddWithWeight(int src, int dest, W weight, WACCUM weights)
|
||||
{
|
||||
// Factorized stencils are expressed purely in terms of the control
|
||||
// mesh verts. Without this flattening, level_i's weights would point
|
||||
// to level_i-1, which would point to level_i-2, until the final level
|
||||
// points to the control verts.
|
||||
//
|
||||
// So here, we check if the incoming vert (src) is in the control mesh,
|
||||
// if it is, we can simply merge it without attempting to resolve it
|
||||
// first.
|
||||
if (src < _coarseVertCount) {
|
||||
merge(src, dest, weight, W(1.0), _lastOffset, _size, weights);
|
||||
return;
|
||||
}
|
||||
|
||||
// src is not in the control mesh, so resolve all contributing coarse
|
||||
// verts (src itself is made up of many control vert weights).
|
||||
//
|
||||
// Find the src stencil and number of contributing CVs.
|
||||
int len = _sizes[src];
|
||||
int start = _indices[src];
|
||||
|
||||
for (int i = start; i < start+len; i++) {
|
||||
// Invariant: by processing each level in order and each vertex in
|
||||
// dependent order, any src stencil vertex reference is guaranteed
|
||||
// to consist only of coarse verts: therefore resolving src verts
|
||||
// must yield verts in the coarse mesh.
|
||||
assert(_sources[i] < _coarseVertCount);
|
||||
|
||||
// Merge each of src's contributing verts into this stencil.
|
||||
merge(_sources[i], dest, weights.Get(i), weight,
|
||||
_lastOffset, _size, weights);
|
||||
}
|
||||
}
|
||||
|
||||
class Point1stDerivAccumulator {
|
||||
WeightTable* _tbl;
|
||||
public:
|
||||
Point1stDerivAccumulator(WeightTable* tbl) : _tbl(tbl)
|
||||
{ }
|
||||
void PushBack(Point1stDerivWeight<REAL> weight) {
|
||||
_tbl->_weights.push_back(weight.p);
|
||||
_tbl->_duWeights.push_back(weight.du);
|
||||
_tbl->_dvWeights.push_back(weight.dv);
|
||||
}
|
||||
void Add(size_t i, Point1stDerivWeight<REAL> weight) {
|
||||
_tbl->_weights[i] += weight.p;
|
||||
_tbl->_duWeights[i] += weight.du;
|
||||
_tbl->_dvWeights[i] += weight.dv;
|
||||
}
|
||||
Point1stDerivWeight<REAL> Get(size_t index) {
|
||||
return Point1stDerivWeight<REAL>(_tbl->_weights[index],
|
||||
_tbl->_duWeights[index],
|
||||
_tbl->_dvWeights[index]);
|
||||
}
|
||||
};
|
||||
Point1stDerivAccumulator GetPoint1stDerivAccumulator() {
|
||||
return Point1stDerivAccumulator(this);
|
||||
};
|
||||
|
||||
class Point2ndDerivAccumulator {
|
||||
WeightTable* _tbl;
|
||||
public:
|
||||
Point2ndDerivAccumulator(WeightTable* tbl) : _tbl(tbl)
|
||||
{ }
|
||||
void PushBack(Point2ndDerivWeight<REAL> weight) {
|
||||
_tbl->_weights.push_back(weight.p);
|
||||
_tbl->_duWeights.push_back(weight.du);
|
||||
_tbl->_dvWeights.push_back(weight.dv);
|
||||
_tbl->_duuWeights.push_back(weight.duu);
|
||||
_tbl->_duvWeights.push_back(weight.duv);
|
||||
_tbl->_dvvWeights.push_back(weight.dvv);
|
||||
}
|
||||
void Add(size_t i, Point2ndDerivWeight<REAL> weight) {
|
||||
_tbl->_weights[i] += weight.p;
|
||||
_tbl->_duWeights[i] += weight.du;
|
||||
_tbl->_dvWeights[i] += weight.dv;
|
||||
_tbl->_duuWeights[i] += weight.duu;
|
||||
_tbl->_duvWeights[i] += weight.duv;
|
||||
_tbl->_dvvWeights[i] += weight.dvv;
|
||||
}
|
||||
Point2ndDerivWeight<REAL> Get(size_t index) {
|
||||
return Point2ndDerivWeight<REAL>(_tbl->_weights[index],
|
||||
_tbl->_duWeights[index],
|
||||
_tbl->_dvWeights[index],
|
||||
_tbl->_duuWeights[index],
|
||||
_tbl->_duvWeights[index],
|
||||
_tbl->_dvvWeights[index]);
|
||||
}
|
||||
};
|
||||
Point2ndDerivAccumulator GetPoint2ndDerivAccumulator() {
|
||||
return Point2ndDerivAccumulator(this);
|
||||
};
|
||||
|
||||
class ScalarAccumulator {
|
||||
WeightTable* _tbl;
|
||||
public:
|
||||
ScalarAccumulator(WeightTable* tbl) : _tbl(tbl)
|
||||
{ }
|
||||
void PushBack(REAL weight) {
|
||||
_tbl->_weights.push_back(weight);
|
||||
}
|
||||
void Add(size_t i, REAL w) {
|
||||
_tbl->_weights[i] += w;
|
||||
}
|
||||
REAL Get(size_t index) {
|
||||
return _tbl->_weights[index];
|
||||
}
|
||||
};
|
||||
ScalarAccumulator GetScalarAccumulator() {
|
||||
return ScalarAccumulator(this);
|
||||
};
|
||||
|
||||
std::vector<int> const&
|
||||
GetOffsets() const { return _indices; }
|
||||
|
||||
std::vector<int> const&
|
||||
GetSizes() const { return _sizes; }
|
||||
|
||||
std::vector<int> const&
|
||||
GetSources() const { return _sources; }
|
||||
|
||||
std::vector<REAL> const&
|
||||
GetWeights() const { return _weights; }
|
||||
|
||||
std::vector<REAL> const&
|
||||
GetDuWeights() const { return _duWeights; }
|
||||
|
||||
std::vector<REAL> const&
|
||||
GetDvWeights() const { return _dvWeights; }
|
||||
|
||||
std::vector<REAL> const&
|
||||
GetDuuWeights() const { return _duuWeights; }
|
||||
|
||||
std::vector<REAL> const&
|
||||
GetDuvWeights() const { return _duvWeights; }
|
||||
|
||||
std::vector<REAL> const&
|
||||
GetDvvWeights() const { return _dvvWeights; }
|
||||
|
||||
void SetCoarseVertCount(int numVerts) {
|
||||
_coarseVertCount = numVerts;
|
||||
}
|
||||
private:
|
||||
|
||||
// Merge a vertex weight into the stencil table, if there is an existing
|
||||
// weight for a given source vertex it will be combined.
|
||||
//
|
||||
// PERFORMANCE: caution, this function is super hot.
|
||||
template <class W, class WACCUM>
|
||||
void merge(int src, int dst, W weight,
|
||||
// Delaying weight*factor multiplication hides memory latency of
|
||||
// accessing weight[i], yielding more stable performance.
|
||||
W weightFactor,
|
||||
// Similarly, passing offset & tableSize as params yields higher
|
||||
// performance than accessing the class members directly.
|
||||
int lastOffset, int tableSize, WACCUM weights)
|
||||
{
|
||||
// The lastOffset is the vertex we're currently processing, by
|
||||
// leveraging this we need not lookup the dest stencil size or offset.
|
||||
//
|
||||
// Additionally, if the client does not want the resulting verts
|
||||
// compacted, do not attempt to combine weights.
|
||||
if (_compactWeights && !_dests.empty() && _dests[lastOffset] == dst) {
|
||||
|
||||
// tableSize is exactly _sources.size(), but using tableSize is
|
||||
// significantly faster.
|
||||
for (int i = lastOffset; i < tableSize; i++) {
|
||||
|
||||
// If we find an existing vertex that matches src, we need to
|
||||
// combine the weights to avoid duplicate entries for src.
|
||||
if (_sources[i] == src) {
|
||||
weights.Add(i, weight*weightFactor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We haven't seen src yet, insert it as a new vertex weight.
|
||||
add(src, dst, weight*weightFactor, weights);
|
||||
}
|
||||
|
||||
// Add a new vertex weight to the stencil table.
|
||||
template <class W, class WACCUM>
|
||||
void add(int src, int dst, W weight, WACCUM weights)
|
||||
{
|
||||
// The _dests array has num(weights) elements mapping each individual
|
||||
// element back to a specific stencil. The array is constructed in such
|
||||
// a way that the current stencil being built is always at the end of
|
||||
// the array, so if the dests array is empty or back() doesn't match
|
||||
// dst, then we just started building a new stencil.
|
||||
if (_dests.empty() || dst != _dests.back()) {
|
||||
// _indices and _sizes always have num(stencils) elements so that
|
||||
// stencils can be directly looked up by their index in these
|
||||
// arrays. So here, ensure that they are large enough to hold the
|
||||
// new stencil about to be built.
|
||||
if (dst+1 > (int)_indices.size()) {
|
||||
_indices.resize(dst+1);
|
||||
_sizes.resize(dst+1);
|
||||
}
|
||||
// Initialize the new stencil's meta-data (offset, size).
|
||||
_indices[dst] = static_cast<int>(_sources.size());
|
||||
_sizes[dst] = 0;
|
||||
// Keep track of where the current stencil begins, which lets us
|
||||
// avoid having to look it up later.
|
||||
_lastOffset = static_cast<int>(_sources.size());
|
||||
}
|
||||
// Cache the number of elements as an optimization, it's faster than
|
||||
// calling size() on any of the vectors.
|
||||
_size++;
|
||||
|
||||
// Increment the current stencil element size.
|
||||
_sizes[dst]++;
|
||||
// Track this element as belonging to the stencil "dst".
|
||||
_dests.push_back(dst);
|
||||
|
||||
// Store the actual stencil data.
|
||||
_sources.push_back(src);
|
||||
weights.PushBack(weight);
|
||||
}
|
||||
|
||||
// The following vectors are explicitly stored as non-interleaved elements
|
||||
// to reduce cache misses.
|
||||
|
||||
// Stencil to destination vertex map.
|
||||
std::vector<int> _dests;
|
||||
|
||||
// The actual stencil data.
|
||||
std::vector<int> _sources;
|
||||
std::vector<REAL> _weights;
|
||||
std::vector<REAL> _duWeights;
|
||||
std::vector<REAL> _dvWeights;
|
||||
std::vector<REAL> _duuWeights;
|
||||
std::vector<REAL> _duvWeights;
|
||||
std::vector<REAL> _dvvWeights;
|
||||
|
||||
// Index data used to recover stencil-to-vertex mapping.
|
||||
std::vector<int> _indices;
|
||||
std::vector<int> _sizes;
|
||||
|
||||
// Acceleration members to avoid pointer chasing and reverse loops.
|
||||
int _size;
|
||||
int _lastOffset;
|
||||
int _coarseVertCount;
|
||||
bool _compactWeights;
|
||||
};
|
||||
|
||||
template <typename REAL>
|
||||
StencilBuilder<REAL>::StencilBuilder(int coarseVertCount,
|
||||
bool genCtrlVertStencils,
|
||||
bool compactWeights)
|
||||
: _weightTable(new WeightTable<REAL>(coarseVertCount,
|
||||
genCtrlVertStencils,
|
||||
compactWeights))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
StencilBuilder<REAL>::~StencilBuilder()
|
||||
{
|
||||
delete _weightTable;
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
size_t
|
||||
StencilBuilder<REAL>::GetNumVerticesTotal() const
|
||||
{
|
||||
return _weightTable->GetWeights().size();
|
||||
}
|
||||
|
||||
|
||||
template <typename REAL>
|
||||
int
|
||||
StencilBuilder<REAL>::GetNumVertsInStencil(size_t stencilIndex) const
|
||||
{
|
||||
if (stencilIndex > _weightTable->GetSizes().size() - 1)
|
||||
return 0;
|
||||
|
||||
return (int)_weightTable->GetSizes()[stencilIndex];
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
StencilBuilder<REAL>::SetCoarseVertCount(int numVerts)
|
||||
{
|
||||
_weightTable->SetCoarseVertCount(numVerts);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<int> const&
|
||||
StencilBuilder<REAL>::GetStencilOffsets() const {
|
||||
return _weightTable->GetOffsets();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<int> const&
|
||||
StencilBuilder<REAL>::GetStencilSizes() const {
|
||||
return _weightTable->GetSizes();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<int> const&
|
||||
StencilBuilder<REAL>::GetStencilSources() const {
|
||||
return _weightTable->GetSources();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<REAL> const&
|
||||
StencilBuilder<REAL>::GetStencilWeights() const {
|
||||
return _weightTable->GetWeights();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<REAL> const&
|
||||
StencilBuilder<REAL>::GetStencilDuWeights() const {
|
||||
return _weightTable->GetDuWeights();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<REAL> const&
|
||||
StencilBuilder<REAL>::GetStencilDvWeights() const {
|
||||
return _weightTable->GetDvWeights();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<REAL> const&
|
||||
StencilBuilder<REAL>::GetStencilDuuWeights() const {
|
||||
return _weightTable->GetDuuWeights();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<REAL> const&
|
||||
StencilBuilder<REAL>::GetStencilDuvWeights() const {
|
||||
return _weightTable->GetDuvWeights();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<REAL> const&
|
||||
StencilBuilder<REAL>::GetStencilDvvWeights() const {
|
||||
return _weightTable->GetDvvWeights();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
StencilBuilder<REAL>::Index::AddWithWeight(Index const & src, REAL weight)
|
||||
{
|
||||
// Ignore no-op weights.
|
||||
if (isWeightZero(weight)) {
|
||||
return;
|
||||
}
|
||||
_owner->_weightTable->AddWithWeight(src._index, _index, weight,
|
||||
_owner->_weightTable->GetScalarAccumulator());
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
StencilBuilder<REAL>::Index::AddWithWeight(StencilReal<REAL> const& src, REAL weight)
|
||||
{
|
||||
if (isWeightZero(weight)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int srcSize = *src.GetSizePtr();
|
||||
Vtr::Index const * srcIndices = src.GetVertexIndices();
|
||||
REAL const * srcWeights = src.GetWeights();
|
||||
|
||||
for (int i = 0; i < srcSize; ++i) {
|
||||
REAL w = srcWeights[i];
|
||||
if (isWeightZero(w)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vtr::Index srcIndex = srcIndices[i];
|
||||
|
||||
REAL wgt = weight * w;
|
||||
_owner->_weightTable->AddWithWeight(srcIndex, _index, wgt,
|
||||
_owner->_weightTable->GetScalarAccumulator());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
StencilBuilder<REAL>::Index::AddWithWeight(StencilReal<REAL> const& src,
|
||||
REAL weight, REAL du, REAL dv)
|
||||
{
|
||||
if (isWeightZero(weight) && isWeightZero(du) && isWeightZero(dv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int srcSize = *src.GetSizePtr();
|
||||
Vtr::Index const * srcIndices = src.GetVertexIndices();
|
||||
REAL const * srcWeights = src.GetWeights();
|
||||
|
||||
for (int i = 0; i < srcSize; ++i) {
|
||||
REAL w = srcWeights[i];
|
||||
if (isWeightZero(w)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vtr::Index srcIndex = srcIndices[i];
|
||||
|
||||
Point1stDerivWeight<REAL> wgt = Point1stDerivWeight<REAL>(weight, du, dv) * w;
|
||||
_owner->_weightTable->AddWithWeight(srcIndex, _index, wgt,
|
||||
_owner->_weightTable->GetPoint1stDerivAccumulator());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
StencilBuilder<REAL>::Index::AddWithWeight(StencilReal<REAL> const& src,
|
||||
REAL weight, REAL du, REAL dv, REAL duu, REAL duv, REAL dvv)
|
||||
{
|
||||
if (isWeightZero(weight) && isWeightZero(du) && isWeightZero(dv) &&
|
||||
isWeightZero(duu) && isWeightZero(duv) && isWeightZero(dvv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int srcSize = *src.GetSizePtr();
|
||||
Vtr::Index const * srcIndices = src.GetVertexIndices();
|
||||
REAL const * srcWeights = src.GetWeights();
|
||||
|
||||
for (int i = 0; i < srcSize; ++i) {
|
||||
REAL w = srcWeights[i];
|
||||
if (isWeightZero(w)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vtr::Index srcIndex = srcIndices[i];
|
||||
|
||||
Point2ndDerivWeight<REAL> wgt = Point2ndDerivWeight<REAL>(weight, du, dv, duu, duv, dvv) * w;
|
||||
_owner->_weightTable->AddWithWeight(srcIndex, _index, wgt,
|
||||
_owner->_weightTable->GetPoint2ndDerivAccumulator());
|
||||
}
|
||||
}
|
||||
|
||||
template class StencilBuilder<float>;
|
||||
template class StencilBuilder<double>;
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Far
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
115
src/osd/opensubdiv/far/stencilBuilder.h
Normal file
115
src/osd/opensubdiv/far/stencilBuilder.h
Normal file
@@ -0,0 +1,115 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_STENCILBUILDER_H
|
||||
#define OPENSUBDIV3_FAR_STENCILBUILDER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../version.h"
|
||||
#include "../far/stencilTable.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
namespace internal {
|
||||
|
||||
template <typename REAL> class WeightTable;
|
||||
|
||||
template <typename REAL>
|
||||
class StencilBuilder {
|
||||
public:
|
||||
StencilBuilder(int coarseVertCount,
|
||||
bool genCtrlVertStencils=true,
|
||||
bool compactWeights=true);
|
||||
~StencilBuilder();
|
||||
|
||||
// TODO: noncopyable.
|
||||
|
||||
size_t GetNumVerticesTotal() const;
|
||||
|
||||
int GetNumVertsInStencil(size_t stencilIndex) const;
|
||||
|
||||
void SetCoarseVertCount(int numVerts);
|
||||
|
||||
// Mapping from stencil[i] to its starting offset in the sources[] and weights[] arrays;
|
||||
std::vector<int> const& GetStencilOffsets() const;
|
||||
|
||||
// The number of contributing sources and weights in stencil[i]
|
||||
std::vector<int> const& GetStencilSizes() const;
|
||||
|
||||
// The absolute source vertex offsets.
|
||||
std::vector<int> const& GetStencilSources() const;
|
||||
|
||||
// The individual vertex weights, each weight is paired with one source.
|
||||
std::vector<REAL> const& GetStencilWeights() const;
|
||||
std::vector<REAL> const& GetStencilDuWeights() const;
|
||||
std::vector<REAL> const& GetStencilDvWeights() const;
|
||||
std::vector<REAL> const& GetStencilDuuWeights() const;
|
||||
std::vector<REAL> const& GetStencilDuvWeights() const;
|
||||
std::vector<REAL> const& GetStencilDvvWeights() const;
|
||||
|
||||
// Vertex Facade.
|
||||
class Index {
|
||||
public:
|
||||
Index(StencilBuilder* owner, int index)
|
||||
: _owner(owner)
|
||||
, _index(index)
|
||||
{}
|
||||
|
||||
// Add with point/vertex weight only.
|
||||
void AddWithWeight(Index const & src, REAL weight);
|
||||
void AddWithWeight(StencilReal<REAL> const& src, REAL weight);
|
||||
|
||||
// Add with first derivative.
|
||||
void AddWithWeight(StencilReal<REAL> const& src,
|
||||
REAL weight, REAL du, REAL dv);
|
||||
|
||||
// Add with first and second derivatives.
|
||||
void AddWithWeight(StencilReal<REAL> const& src,
|
||||
REAL weight, REAL du, REAL dv, REAL duu, REAL duv, REAL dvv);
|
||||
|
||||
Index operator[](int index) const {
|
||||
return Index(_owner, index+_index);
|
||||
}
|
||||
|
||||
int GetOffset() const { return _index; }
|
||||
|
||||
void Clear() {/*nothing to do here*/}
|
||||
private:
|
||||
StencilBuilder* _owner;
|
||||
int _index;
|
||||
};
|
||||
|
||||
private:
|
||||
WeightTable<REAL>* _weightTable;
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Far
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // FAR_STENCILBUILDER_H
|
||||
234
src/osd/opensubdiv/far/stencilTable.cpp
Normal file
234
src/osd/opensubdiv/far/stencilTable.cpp
Normal file
@@ -0,0 +1,234 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../version.h"
|
||||
#include "../far/stencilTable.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
|
||||
namespace {
|
||||
template <typename REAL>
|
||||
void
|
||||
copyStencilData(int numControlVerts,
|
||||
bool includeCoarseVerts,
|
||||
size_t firstOffset,
|
||||
std::vector<int> const* offsets,
|
||||
std::vector<int> * _offsets,
|
||||
std::vector<int> const* sizes,
|
||||
std::vector<int> * _sizes,
|
||||
std::vector<int> const* sources,
|
||||
std::vector<int> * _sources,
|
||||
std::vector<REAL> const* weights,
|
||||
std::vector<REAL> * _weights,
|
||||
std::vector<REAL> const* duWeights=NULL,
|
||||
std::vector<REAL> * _duWeights=NULL,
|
||||
std::vector<REAL> const* dvWeights=NULL,
|
||||
std::vector<REAL> * _dvWeights=NULL,
|
||||
std::vector<REAL> const* duuWeights=NULL,
|
||||
std::vector<REAL> * _duuWeights=NULL,
|
||||
std::vector<REAL> const* duvWeights=NULL,
|
||||
std::vector<REAL> * _duvWeights=NULL,
|
||||
std::vector<REAL> const* dvvWeights=NULL,
|
||||
std::vector<REAL> * _dvvWeights=NULL) {
|
||||
size_t start = includeCoarseVerts ? 0 : firstOffset;
|
||||
|
||||
_offsets->resize(offsets->size());
|
||||
_sizes->resize(sizes->size());
|
||||
_sources->resize(sources->size());
|
||||
_weights->resize(weights->size());
|
||||
if (_duWeights)
|
||||
_duWeights->resize(duWeights->size());
|
||||
if (_dvWeights)
|
||||
_dvWeights->resize(dvWeights->size());
|
||||
if (_duuWeights)
|
||||
_duuWeights->resize(duuWeights->size());
|
||||
if (_duvWeights)
|
||||
_duvWeights->resize(duvWeights->size());
|
||||
if (_dvvWeights)
|
||||
_dvvWeights->resize(dvvWeights->size());
|
||||
|
||||
// The stencils are probably not in order, so we must copy/sort them.
|
||||
// Note here that loop index 'i' represents stencil_i for vertex_i.
|
||||
int curOffset = 0;
|
||||
|
||||
size_t stencilCount = 0,
|
||||
weightCount = 0;
|
||||
|
||||
for ( size_t i=start; i<offsets->size(); i++ ) {
|
||||
// Once we've copied out all the control verts, jump to the offset
|
||||
// where the actual stencils begin.
|
||||
if (includeCoarseVerts && (int)i == numControlVerts)
|
||||
i = firstOffset;
|
||||
|
||||
// Copy the stencil.
|
||||
int sz = (*sizes)[i];
|
||||
int off = (*offsets)[i];
|
||||
|
||||
(*_offsets)[stencilCount] = curOffset;
|
||||
(*_sizes)[stencilCount] = sz;
|
||||
|
||||
std::memcpy(&(*_sources)[curOffset],
|
||||
&(*sources)[off], sz*sizeof(int));
|
||||
std::memcpy(&(*_weights)[curOffset],
|
||||
&(*weights)[off], sz*sizeof(REAL));
|
||||
|
||||
if (_duWeights && !_duWeights->empty()) {
|
||||
std::memcpy(&(*_duWeights)[curOffset],
|
||||
&(*duWeights)[off], sz*sizeof(REAL));
|
||||
}
|
||||
if (_dvWeights && !_dvWeights->empty()) {
|
||||
std::memcpy(&(*_dvWeights)[curOffset],
|
||||
&(*dvWeights)[off], sz*sizeof(REAL));
|
||||
}
|
||||
|
||||
if (_duuWeights && !_duuWeights->empty()) {
|
||||
std::memcpy(&(*_duuWeights)[curOffset],
|
||||
&(*duuWeights)[off], sz*sizeof(REAL));
|
||||
}
|
||||
if (_duvWeights && !_duvWeights->empty()) {
|
||||
std::memcpy(&(*_duvWeights)[curOffset],
|
||||
&(*duvWeights)[off], sz*sizeof(REAL));
|
||||
}
|
||||
if (_dvvWeights && !_dvvWeights->empty()) {
|
||||
std::memcpy(&(*_dvvWeights)[curOffset],
|
||||
&(*dvvWeights)[off], sz*sizeof(REAL));
|
||||
}
|
||||
|
||||
curOffset += sz;
|
||||
stencilCount++;
|
||||
weightCount += sz;
|
||||
}
|
||||
|
||||
_offsets->resize(stencilCount);
|
||||
_sizes->resize(stencilCount);
|
||||
_sources->resize(weightCount);
|
||||
|
||||
if (_duWeights && !_duWeights->empty())
|
||||
_duWeights->resize(weightCount);
|
||||
if (_dvWeights && !_dvWeights->empty())
|
||||
_dvWeights->resize(weightCount);
|
||||
|
||||
if (_duuWeights && !_duuWeights->empty())
|
||||
_duuWeights->resize(weightCount);
|
||||
if (_duvWeights && !_duvWeights->empty())
|
||||
_duvWeights->resize(weightCount);
|
||||
if (_dvvWeights && !_dvvWeights->empty())
|
||||
_dvvWeights->resize(weightCount);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL>::StencilTableReal(int numControlVerts,
|
||||
std::vector<int> const& offsets,
|
||||
std::vector<int> const& sizes,
|
||||
std::vector<int> const& sources,
|
||||
std::vector<REAL> const& weights,
|
||||
bool includeCoarseVerts,
|
||||
size_t firstOffset)
|
||||
: _numControlVertices(numControlVerts) {
|
||||
copyStencilData(numControlVerts,
|
||||
includeCoarseVerts,
|
||||
firstOffset,
|
||||
&offsets, &_offsets,
|
||||
&sizes, &_sizes,
|
||||
&sources, &_indices,
|
||||
&weights, &_weights);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
StencilTableReal<REAL>::Clear() {
|
||||
_numControlVertices=0;
|
||||
_sizes.clear();
|
||||
_offsets.clear();
|
||||
_indices.clear();
|
||||
_weights.clear();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
LimitStencilTableReal<REAL>::LimitStencilTableReal(
|
||||
int numControlVerts,
|
||||
std::vector<int> const& offsets,
|
||||
std::vector<int> const& sizes,
|
||||
std::vector<int> const& sources,
|
||||
std::vector<REAL> const& weights,
|
||||
std::vector<REAL> const& duWeights,
|
||||
std::vector<REAL> const& dvWeights,
|
||||
std::vector<REAL> const& duuWeights,
|
||||
std::vector<REAL> const& duvWeights,
|
||||
std::vector<REAL> const& dvvWeights,
|
||||
bool includeCoarseVerts,
|
||||
size_t firstOffset)
|
||||
: StencilTableReal<REAL>(numControlVerts) {
|
||||
copyStencilData(numControlVerts,
|
||||
includeCoarseVerts,
|
||||
firstOffset,
|
||||
&offsets, &this->_offsets,
|
||||
&sizes, &this->_sizes,
|
||||
&sources, &this->_indices,
|
||||
&weights, &this->_weights,
|
||||
&duWeights, &_duWeights,
|
||||
&dvWeights, &_dvWeights,
|
||||
&duuWeights, &_duuWeights,
|
||||
&duvWeights, &_duvWeights,
|
||||
&dvvWeights, &_dvvWeights);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
LimitStencilTableReal<REAL>::Clear() {
|
||||
StencilTableReal<REAL>::Clear();
|
||||
_duWeights.clear();
|
||||
_dvWeights.clear();
|
||||
_duuWeights.clear();
|
||||
_duvWeights.clear();
|
||||
_dvvWeights.clear();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Explicit instantiation for float and double:
|
||||
//
|
||||
template class StencilReal<float>;
|
||||
template class StencilReal<double>;
|
||||
|
||||
template class LimitStencilReal<float>;
|
||||
template class LimitStencilReal<double>;
|
||||
|
||||
template class StencilTableReal<float>;
|
||||
template class StencilTableReal<double>;
|
||||
|
||||
template class LimitStencilTableReal<float>;
|
||||
template class LimitStencilTableReal<double>;
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
793
src/osd/opensubdiv/far/stencilTable.h
Normal file
793
src/osd/opensubdiv/far/stencilTable.h
Normal file
@@ -0,0 +1,793 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_STENCILTABLE_H
|
||||
#define OPENSUBDIV3_FAR_STENCILTABLE_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/types.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
// Forward declarations for friends:
|
||||
class PatchTableBuilder;
|
||||
|
||||
template <typename REAL> class StencilTableFactoryReal;
|
||||
template <typename REAL> class LimitStencilTableFactoryReal;
|
||||
|
||||
/// \brief Vertex stencil descriptor
|
||||
///
|
||||
/// Allows access and manipulation of a single stencil in a StencilTable.
|
||||
///
|
||||
template <typename REAL>
|
||||
class StencilReal {
|
||||
public:
|
||||
|
||||
/// \brief Default constructor
|
||||
StencilReal() {}
|
||||
|
||||
/// \brief Constructor
|
||||
///
|
||||
/// @param size Table pointer to the size of the stencil
|
||||
///
|
||||
/// @param indices Table pointer to the vertex indices of the stencil
|
||||
///
|
||||
/// @param weights Table pointer to the vertex weights of the stencil
|
||||
///
|
||||
StencilReal(int * size, Index * indices, REAL * weights)
|
||||
: _size(size), _indices(indices), _weights(weights) { }
|
||||
|
||||
/// \brief Copy constructor
|
||||
StencilReal(StencilReal const & other) {
|
||||
_size = other._size;
|
||||
_indices = other._indices;
|
||||
_weights = other._weights;
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the stencil
|
||||
int GetSize() const {
|
||||
return *_size;
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the stencil as a pointer
|
||||
int * GetSizePtr() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
/// \brief Returns the control vertices' indices
|
||||
Index const * GetVertexIndices() const {
|
||||
return _indices;
|
||||
}
|
||||
|
||||
/// \brief Returns the interpolation weights
|
||||
REAL const * GetWeights() const {
|
||||
return _weights;
|
||||
}
|
||||
|
||||
/// \brief Advance to the next stencil in the table
|
||||
void Next() {
|
||||
int stride = *_size;
|
||||
++_size;
|
||||
_indices += stride;
|
||||
_weights += stride;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class StencilTableFactoryReal<REAL>;
|
||||
friend class LimitStencilTableFactoryReal<REAL>;
|
||||
|
||||
int * _size;
|
||||
Index * _indices;
|
||||
REAL * _weights;
|
||||
};
|
||||
|
||||
/// \brief Vertex stencil class wrapping the template for compatibility.
|
||||
///
|
||||
class Stencil : public StencilReal<float> {
|
||||
protected:
|
||||
typedef StencilReal<float> BaseStencil;
|
||||
|
||||
public:
|
||||
Stencil() : BaseStencil() { }
|
||||
Stencil(BaseStencil const & other) : BaseStencil(other) { }
|
||||
Stencil(int * size, Index * indices, float * weights)
|
||||
: BaseStencil(size, indices, weights) { }
|
||||
};
|
||||
|
||||
|
||||
/// \brief Table of subdivision stencils.
|
||||
///
|
||||
/// Stencils are the most direct method of evaluation of locations on the limit
|
||||
/// of a surface. Every point of a limit surface can be computed by linearly
|
||||
/// blending a collection of coarse control vertices.
|
||||
///
|
||||
/// A stencil assigns a series of control vertex indices with a blending weight
|
||||
/// that corresponds to a unique parametric location of the limit surface. When
|
||||
/// the control vertices move in space, the limit location can be very efficiently
|
||||
/// recomputed simply by applying the blending weights to the series of coarse
|
||||
/// control vertices.
|
||||
///
|
||||
template <typename REAL>
|
||||
class StencilTableReal {
|
||||
protected:
|
||||
StencilTableReal(int numControlVerts,
|
||||
std::vector<int> const& offsets,
|
||||
std::vector<int> const& sizes,
|
||||
std::vector<int> const& sources,
|
||||
std::vector<REAL> const& weights,
|
||||
bool includeCoarseVerts,
|
||||
size_t firstOffset);
|
||||
|
||||
public:
|
||||
|
||||
virtual ~StencilTableReal() {};
|
||||
|
||||
/// \brief Returns the number of stencils in the table
|
||||
int GetNumStencils() const {
|
||||
return (int)_sizes.size();
|
||||
}
|
||||
|
||||
/// \brief Returns the number of control vertices indexed in the table
|
||||
int GetNumControlVertices() const {
|
||||
return _numControlVertices;
|
||||
}
|
||||
|
||||
/// \brief Returns a Stencil at index i in the table
|
||||
StencilReal<REAL> GetStencil(Index i) const;
|
||||
|
||||
/// \brief Returns the number of control vertices of each stencil in the table
|
||||
std::vector<int> const & GetSizes() const {
|
||||
return _sizes;
|
||||
}
|
||||
|
||||
/// \brief Returns the offset to a given stencil (factory may leave empty)
|
||||
std::vector<Index> const & GetOffsets() const {
|
||||
return _offsets;
|
||||
}
|
||||
|
||||
/// \brief Returns the indices of the control vertices
|
||||
std::vector<Index> const & GetControlIndices() const {
|
||||
return _indices;
|
||||
}
|
||||
|
||||
/// \brief Returns the stencil interpolation weights
|
||||
std::vector<REAL> const & GetWeights() const {
|
||||
return _weights;
|
||||
}
|
||||
|
||||
/// \brief Returns the stencil at index i in the table
|
||||
StencilReal<REAL> operator[] (Index index) const;
|
||||
|
||||
/// \brief Updates point values based on the control values
|
||||
///
|
||||
/// \note The destination buffers are assumed to have allocated at least
|
||||
/// \c GetNumStencils() elements.
|
||||
///
|
||||
/// @param srcValues Buffer with primvar data for the control vertices
|
||||
///
|
||||
/// @param dstValues Destination buffer for the interpolated primvar data
|
||||
///
|
||||
/// @param start Index of first destination value to update
|
||||
///
|
||||
/// @param end Index of last destination value to update
|
||||
///
|
||||
template <class T, class U>
|
||||
void UpdateValues(T const &srcValues, U &dstValues, Index start=-1, Index end=-1) const {
|
||||
this->update(srcValues, dstValues, _weights, start, end);
|
||||
}
|
||||
|
||||
template <class T1, class T2, class U>
|
||||
void UpdateValues(T1 const &srcBase, int numBase, T2 const &srcRef,
|
||||
U &dstValues, Index start=-1, Index end=-1) const {
|
||||
this->update(srcBase, numBase, srcRef, dstValues, _weights, start, end);
|
||||
}
|
||||
|
||||
// Pointer interface for backward compatibility
|
||||
template <class T, class U>
|
||||
void UpdateValues(T const *src, U *dst, Index start=-1, Index end=-1) const {
|
||||
this->update(src, dst, _weights, start, end);
|
||||
}
|
||||
template <class T1, class T2, class U>
|
||||
void UpdateValues(T1 const *srcBase, int numBase, T2 const *srcRef,
|
||||
U *dst, Index start=-1, Index end=-1) const {
|
||||
this->update(srcBase, numBase, srcRef, dst, _weights, start, end);
|
||||
}
|
||||
|
||||
/// \brief Clears the stencils from the table
|
||||
void Clear();
|
||||
|
||||
protected:
|
||||
|
||||
// Update values by applying cached stencil weights to new control values
|
||||
template <class T, class U>
|
||||
void update( T const &srcValues, U &dstValues,
|
||||
std::vector<REAL> const & valueWeights, Index start, Index end) const;
|
||||
template <class T1, class T2, class U>
|
||||
void update( T1 const &srcBase, int numBase, T2 const &srcRef, U &dstValues,
|
||||
std::vector<REAL> const & valueWeights, Index start, Index end) const;
|
||||
|
||||
// Populate the offsets table from the stencil sizes in _sizes (factory helper)
|
||||
void generateOffsets();
|
||||
|
||||
// Resize the table arrays (factory helper)
|
||||
void resize(int nstencils, int nelems);
|
||||
|
||||
// Reserves the table arrays (factory helper)
|
||||
void reserve(int nstencils, int nelems);
|
||||
|
||||
// Reallocates the table arrays to remove excess capacity (factory helper)
|
||||
void shrinkToFit();
|
||||
|
||||
// Performs any final operations on internal tables (factory helper)
|
||||
void finalize();
|
||||
|
||||
protected:
|
||||
StencilTableReal() : _numControlVertices(0) {}
|
||||
StencilTableReal(int numControlVerts)
|
||||
: _numControlVertices(numControlVerts)
|
||||
{ }
|
||||
|
||||
friend class StencilTableFactoryReal<REAL>;
|
||||
friend class Far::PatchTableBuilder;
|
||||
|
||||
int _numControlVertices; // number of control vertices
|
||||
|
||||
std::vector<int> _sizes; // number of coefficients for each stencil
|
||||
std::vector<Index> _offsets, // offset to the start of each stencil
|
||||
_indices; // indices of contributing coarse vertices
|
||||
std::vector<REAL> _weights; // stencil weight coefficients
|
||||
};
|
||||
|
||||
/// \brief Stencil table class wrapping the template for compatibility.
|
||||
///
|
||||
class StencilTable : public StencilTableReal<float> {
|
||||
protected:
|
||||
typedef StencilTableReal<float> BaseTable;
|
||||
|
||||
public:
|
||||
Stencil GetStencil(Index index) const {
|
||||
return Stencil(BaseTable::GetStencil(index));
|
||||
}
|
||||
Stencil operator[] (Index index) const {
|
||||
return Stencil(BaseTable::GetStencil(index));
|
||||
}
|
||||
|
||||
protected:
|
||||
StencilTable() : BaseTable() { }
|
||||
StencilTable(int numControlVerts) : BaseTable(numControlVerts) { }
|
||||
StencilTable(int numControlVerts,
|
||||
std::vector<int> const& offsets,
|
||||
std::vector<int> const& sizes,
|
||||
std::vector<int> const& sources,
|
||||
std::vector<float> const& weights,
|
||||
bool includeCoarseVerts,
|
||||
size_t firstOffset)
|
||||
: BaseTable(numControlVerts, offsets,
|
||||
sizes, sources, weights, includeCoarseVerts, firstOffset) { }
|
||||
};
|
||||
|
||||
|
||||
/// \brief Limit point stencil descriptor
|
||||
///
|
||||
template <typename REAL>
|
||||
class LimitStencilReal : public StencilReal<REAL> {
|
||||
public:
|
||||
|
||||
/// \brief Constructor
|
||||
///
|
||||
/// @param size Table pointer to the size of the stencil
|
||||
///
|
||||
/// @param indices Table pointer to the vertex indices of the stencil
|
||||
///
|
||||
/// @param weights Table pointer to the vertex weights of the stencil
|
||||
///
|
||||
/// @param duWeights Table pointer to the 'u' derivative weights
|
||||
///
|
||||
/// @param dvWeights Table pointer to the 'v' derivative weights
|
||||
///
|
||||
/// @param duuWeights Table pointer to the 'uu' derivative weights
|
||||
///
|
||||
/// @param duvWeights Table pointer to the 'uv' derivative weights
|
||||
///
|
||||
/// @param dvvWeights Table pointer to the 'vv' derivative weights
|
||||
///
|
||||
LimitStencilReal( int* size,
|
||||
Index * indices,
|
||||
REAL * weights,
|
||||
REAL * duWeights=0,
|
||||
REAL * dvWeights=0,
|
||||
REAL * duuWeights=0,
|
||||
REAL * duvWeights=0,
|
||||
REAL * dvvWeights=0)
|
||||
: StencilReal<REAL>(size, indices, weights),
|
||||
_duWeights(duWeights),
|
||||
_dvWeights(dvWeights),
|
||||
_duuWeights(duuWeights),
|
||||
_duvWeights(duvWeights),
|
||||
_dvvWeights(dvvWeights) {
|
||||
}
|
||||
|
||||
/// \brief Returns the u derivative weights
|
||||
REAL const * GetDuWeights() const {
|
||||
return _duWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the v derivative weights
|
||||
REAL const * GetDvWeights() const {
|
||||
return _dvWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the uu derivative weights
|
||||
REAL const * GetDuuWeights() const {
|
||||
return _duuWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the uv derivative weights
|
||||
REAL const * GetDuvWeights() const {
|
||||
return _duvWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the vv derivative weights
|
||||
REAL const * GetDvvWeights() const {
|
||||
return _dvvWeights;
|
||||
}
|
||||
|
||||
/// \brief Advance to the next stencil in the table
|
||||
void Next() {
|
||||
int stride = *this->_size;
|
||||
++this->_size;
|
||||
this->_indices += stride;
|
||||
this->_weights += stride;
|
||||
if (_duWeights) _duWeights += stride;
|
||||
if (_dvWeights) _dvWeights += stride;
|
||||
if (_duuWeights) _duuWeights += stride;
|
||||
if (_duvWeights) _duvWeights += stride;
|
||||
if (_dvvWeights) _dvvWeights += stride;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
friend class StencilTableFactoryReal<REAL>;
|
||||
friend class LimitStencilTableFactoryReal<REAL>;
|
||||
|
||||
REAL * _duWeights, // pointer to stencil u derivative limit weights
|
||||
* _dvWeights, // pointer to stencil v derivative limit weights
|
||||
* _duuWeights, // pointer to stencil uu derivative limit weights
|
||||
* _duvWeights, // pointer to stencil uv derivative limit weights
|
||||
* _dvvWeights; // pointer to stencil vv derivative limit weights
|
||||
};
|
||||
|
||||
/// \brief Limit point stencil class wrapping the template for compatibility.
|
||||
///
|
||||
class LimitStencil : public LimitStencilReal<float> {
|
||||
protected:
|
||||
typedef LimitStencilReal<float> BaseStencil;
|
||||
|
||||
public:
|
||||
LimitStencil(BaseStencil const & other) : BaseStencil(other) { }
|
||||
LimitStencil(int* size, Index * indices, float * weights,
|
||||
float * duWeights=0, float * dvWeights=0,
|
||||
float * duuWeights=0, float * duvWeights=0, float * dvvWeights=0)
|
||||
: BaseStencil(size, indices, weights,
|
||||
duWeights, dvWeights, duuWeights, duvWeights, dvvWeights) { }
|
||||
};
|
||||
|
||||
|
||||
/// \brief Table of limit subdivision stencils.
|
||||
///
|
||||
template <typename REAL>
|
||||
class LimitStencilTableReal : public StencilTableReal<REAL> {
|
||||
protected:
|
||||
LimitStencilTableReal(
|
||||
int numControlVerts,
|
||||
std::vector<int> const& offsets,
|
||||
std::vector<int> const& sizes,
|
||||
std::vector<int> const& sources,
|
||||
std::vector<REAL> const& weights,
|
||||
std::vector<REAL> const& duWeights,
|
||||
std::vector<REAL> const& dvWeights,
|
||||
std::vector<REAL> const& duuWeights,
|
||||
std::vector<REAL> const& duvWeights,
|
||||
std::vector<REAL> const& dvvWeights,
|
||||
bool includeCoarseVerts,
|
||||
size_t firstOffset);
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Returns a LimitStencil at index i in the table
|
||||
LimitStencilReal<REAL> GetLimitStencil(Index i) const;
|
||||
|
||||
/// \brief Returns the limit stencil at index i in the table
|
||||
LimitStencilReal<REAL> operator[] (Index index) const;
|
||||
|
||||
/// \brief Returns the 'u' derivative stencil interpolation weights
|
||||
std::vector<REAL> const & GetDuWeights() const {
|
||||
return _duWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the 'v' derivative stencil interpolation weights
|
||||
std::vector<REAL> const & GetDvWeights() const {
|
||||
return _dvWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the 'uu' derivative stencil interpolation weights
|
||||
std::vector<REAL> const & GetDuuWeights() const {
|
||||
return _duuWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the 'uv' derivative stencil interpolation weights
|
||||
std::vector<REAL> const & GetDuvWeights() const {
|
||||
return _duvWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the 'vv' derivative stencil interpolation weights
|
||||
std::vector<REAL> const & GetDvvWeights() const {
|
||||
return _dvvWeights;
|
||||
}
|
||||
|
||||
/// \brief Updates derivative values based on the control values
|
||||
///
|
||||
/// \note The destination buffers ('uderivs' & 'vderivs') are assumed to
|
||||
/// have allocated at least \c GetNumStencils() elements.
|
||||
///
|
||||
/// @param srcValues Buffer with primvar data for the control vertices
|
||||
///
|
||||
/// @param uderivs Destination buffer for the interpolated 'u'
|
||||
/// derivative primvar data
|
||||
///
|
||||
/// @param vderivs Destination buffer for the interpolated 'v'
|
||||
/// derivative primvar data
|
||||
///
|
||||
/// @param start Index of first destination derivative to update
|
||||
///
|
||||
/// @param end Index of last destination derivative to update
|
||||
///
|
||||
template <class T, class U>
|
||||
void UpdateDerivs(T const & srcValues, U & uderivs, U & vderivs,
|
||||
int start=-1, int end=-1) const {
|
||||
|
||||
this->update(srcValues, uderivs, _duWeights, start, end);
|
||||
this->update(srcValues, vderivs, _dvWeights, start, end);
|
||||
}
|
||||
|
||||
template <class T1, class T2, class U>
|
||||
void UpdateDerivs(T1 const & srcBase, int numBase, T2 const & srcRef,
|
||||
U & uderivs, U & vderivs, int start=-1, int end=-1) const {
|
||||
|
||||
this->update(srcBase, numBase, srcRef, uderivs, _duWeights, start, end);
|
||||
this->update(srcBase, numBase, srcRef, vderivs, _dvWeights, start, end);
|
||||
}
|
||||
|
||||
// Pointer interface for backward compatibility
|
||||
template <class T, class U>
|
||||
void UpdateDerivs(T const *src, U *uderivs, U *vderivs,
|
||||
int start=-1, int end=-1) const {
|
||||
|
||||
this->update(src, uderivs, _duWeights, start, end);
|
||||
this->update(src, vderivs, _dvWeights, start, end);
|
||||
}
|
||||
template <class T1, class T2, class U>
|
||||
void UpdateDerivs(T1 const *srcBase, int numBase, T2 const *srcRef,
|
||||
U *uderivs, U *vderivs, int start=-1, int end=-1) const {
|
||||
|
||||
this->update(srcBase, numBase, srcRef, uderivs, _duWeights, start, end);
|
||||
this->update(srcBase, numBase, srcRef, vderivs, _dvWeights, start, end);
|
||||
}
|
||||
|
||||
/// \brief Updates 2nd derivative values based on the control values
|
||||
///
|
||||
/// \note The destination buffers ('uuderivs', 'uvderivs', & 'vderivs') are
|
||||
/// assumed to have allocated at least \c GetNumStencils() elements.
|
||||
///
|
||||
/// @param srcValues Buffer with primvar data for the control vertices
|
||||
///
|
||||
/// @param uuderivs Destination buffer for the interpolated 'uu'
|
||||
/// derivative primvar data
|
||||
///
|
||||
/// @param uvderivs Destination buffer for the interpolated 'uv'
|
||||
/// derivative primvar data
|
||||
///
|
||||
/// @param vvderivs Destination buffer for the interpolated 'vv'
|
||||
/// derivative primvar data
|
||||
///
|
||||
/// @param start Index of first destination derivative to update
|
||||
///
|
||||
/// @param end Index of last destination derivative to update
|
||||
///
|
||||
template <class T, class U>
|
||||
void Update2ndDerivs(T const & srcValues,
|
||||
U & uuderivs, U & uvderivs, U & vvderivs,
|
||||
int start=-1, int end=-1) const {
|
||||
|
||||
this->update(srcValues, uuderivs, _duuWeights, start, end);
|
||||
this->update(srcValues, uvderivs, _duvWeights, start, end);
|
||||
this->update(srcValues, vvderivs, _dvvWeights, start, end);
|
||||
}
|
||||
|
||||
template <class T1, class T2, class U>
|
||||
void Update2ndDerivs(T1 const & srcBase, int numBase, T2 const & srcRef,
|
||||
U & uuderivs, U & uvderivs, U & vvderivs, int start=-1, int end=-1) const {
|
||||
|
||||
this->update(srcBase, numBase, srcRef, uuderivs, _duuWeights, start, end);
|
||||
this->update(srcBase, numBase, srcRef, uvderivs, _duvWeights, start, end);
|
||||
this->update(srcBase, numBase, srcRef, vvderivs, _dvvWeights, start, end);
|
||||
}
|
||||
|
||||
// Pointer interface for backward compatibility
|
||||
template <class T, class U>
|
||||
void Update2ndDerivs(T const *src, T *uuderivs, U *uvderivs, U *vvderivs,
|
||||
int start=-1, int end=-1) const {
|
||||
|
||||
this->update(src, uuderivs, _duuWeights, start, end);
|
||||
this->update(src, uvderivs, _duvWeights, start, end);
|
||||
this->update(src, vvderivs, _dvvWeights, start, end);
|
||||
}
|
||||
template <class T1, class T2, class U>
|
||||
void Update2ndDerivs(T1 const *srcBase, int numBase, T2 const *srcRef,
|
||||
U *uuderivs, U *uvderivs, U *vvderivs, int start=-1, int end=-1) const {
|
||||
|
||||
this->update(srcBase, numBase, srcRef, uuderivs, _duuWeights, start, end);
|
||||
this->update(srcBase, numBase, srcRef, uvderivs, _duvWeights, start, end);
|
||||
this->update(srcBase, numBase, srcRef, vvderivs, _dvvWeights, start, end);
|
||||
}
|
||||
|
||||
/// \brief Clears the stencils from the table
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
friend class LimitStencilTableFactoryReal<REAL>;
|
||||
|
||||
// Resize the table arrays (factory helper)
|
||||
void resize(int nstencils, int nelems);
|
||||
|
||||
private:
|
||||
std::vector<REAL> _duWeights, // u derivative limit stencil weights
|
||||
_dvWeights, // v derivative limit stencil weights
|
||||
_duuWeights, // uu derivative limit stencil weights
|
||||
_duvWeights, // uv derivative limit stencil weights
|
||||
_dvvWeights; // vv derivative limit stencil weights
|
||||
};
|
||||
|
||||
/// \brief Limit stencil table class wrapping the template for compatibility.
|
||||
///
|
||||
class LimitStencilTable : public LimitStencilTableReal<float> {
|
||||
protected:
|
||||
typedef LimitStencilTableReal<float> BaseTable;
|
||||
|
||||
public:
|
||||
LimitStencil GetLimitStencil(Index index) const {
|
||||
return LimitStencil(BaseTable::GetLimitStencil(index));
|
||||
}
|
||||
LimitStencil operator[] (Index index) const {
|
||||
return LimitStencil(BaseTable::GetLimitStencil(index));
|
||||
}
|
||||
|
||||
protected:
|
||||
LimitStencilTable(int numControlVerts,
|
||||
std::vector<int> const& offsets,
|
||||
std::vector<int> const& sizes,
|
||||
std::vector<int> const& sources,
|
||||
std::vector<float> const& weights,
|
||||
std::vector<float> const& duWeights,
|
||||
std::vector<float> const& dvWeights,
|
||||
std::vector<float> const& duuWeights,
|
||||
std::vector<float> const& duvWeights,
|
||||
std::vector<float> const& dvvWeights,
|
||||
bool includeCoarseVerts,
|
||||
size_t firstOffset)
|
||||
: BaseTable(numControlVerts,
|
||||
offsets, sizes, sources, weights,
|
||||
duWeights, dvWeights, duuWeights, duvWeights, dvvWeights,
|
||||
includeCoarseVerts, firstOffset) { }
|
||||
};
|
||||
|
||||
|
||||
// Update values by applying cached stencil weights to new control values
|
||||
template <typename REAL>
|
||||
template <class T1, class T2, class U> void
|
||||
StencilTableReal<REAL>::update(T1 const &srcBase, int numBase,
|
||||
T2 const &srcRef, U &dstValues,
|
||||
std::vector<REAL> const &valueWeights, Index start, Index end) const {
|
||||
|
||||
int const * sizes = &_sizes.at(0);
|
||||
Index const * indices = &_indices.at(0);
|
||||
REAL const * weights = &valueWeights.at(0);
|
||||
|
||||
if (start > 0) {
|
||||
assert(start < (Index)_offsets.size());
|
||||
sizes += start;
|
||||
indices += _offsets[start];
|
||||
weights += _offsets[start];
|
||||
} else {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
int nstencils = ((end < start) ? GetNumStencils() : end) - start;
|
||||
|
||||
for (int i = 0; i < nstencils; ++i, ++sizes) {
|
||||
dstValues[start + i].Clear();
|
||||
for (int j = 0; j < *sizes; ++j, ++indices, ++weights) {
|
||||
if (*indices < numBase) {
|
||||
dstValues[start + i].AddWithWeight(srcBase[*indices], *weights);
|
||||
} else {
|
||||
dstValues[start + i].AddWithWeight(srcRef[*indices - numBase], *weights);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
template <typename REAL>
|
||||
template <class T, class U> void
|
||||
StencilTableReal<REAL>::update(T const &srcValues, U &dstValues,
|
||||
std::vector<REAL> const &valueWeights, Index start, Index end) const {
|
||||
|
||||
int const * sizes = &_sizes.at(0);
|
||||
Index const * indices = &_indices.at(0);
|
||||
REAL const * weights = &valueWeights.at(0);
|
||||
|
||||
if (start > 0) {
|
||||
assert(start < (Index)_offsets.size());
|
||||
sizes += start;
|
||||
indices += _offsets[start];
|
||||
weights += _offsets[start];
|
||||
} else {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
int nstencils = ((end < start) ? GetNumStencils() : end) - start;
|
||||
|
||||
for (int i = 0; i < nstencils; ++i, ++sizes) {
|
||||
dstValues[start + i].Clear();
|
||||
for (int j = 0; j < *sizes; ++j, ++indices, ++weights) {
|
||||
dstValues[start + i].AddWithWeight(srcValues[*indices], *weights);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
StencilTableReal<REAL>::generateOffsets() {
|
||||
Index offset=0;
|
||||
int noffsets = (int)_sizes.size();
|
||||
_offsets.resize(noffsets);
|
||||
for (int i=0; i<(int)_sizes.size(); ++i ) {
|
||||
_offsets[i]=offset;
|
||||
offset+=_sizes[i];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
StencilTableReal<REAL>::resize(int nstencils, int nelems) {
|
||||
_sizes.resize(nstencils);
|
||||
_indices.resize(nelems);
|
||||
_weights.resize(nelems);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
StencilTableReal<REAL>::reserve(int nstencils, int nelems) {
|
||||
_sizes.reserve(nstencils);
|
||||
_indices.reserve(nelems);
|
||||
_weights.reserve(nelems);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
StencilTableReal<REAL>::shrinkToFit() {
|
||||
std::vector<int>(_sizes).swap(_sizes);
|
||||
std::vector<Index>(_indices).swap(_indices);
|
||||
std::vector<REAL>(_weights).swap(_weights);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
StencilTableReal<REAL>::finalize() {
|
||||
shrinkToFit();
|
||||
generateOffsets();
|
||||
}
|
||||
|
||||
// Returns a Stencil at index i in the table
|
||||
template <typename REAL>
|
||||
inline StencilReal<REAL>
|
||||
StencilTableReal<REAL>::GetStencil(Index i) const {
|
||||
assert((! _offsets.empty()) && i<(int)_offsets.size());
|
||||
|
||||
Index ofs = _offsets[i];
|
||||
|
||||
return StencilReal<REAL>(const_cast<int*>(&_sizes[i]),
|
||||
const_cast<Index*>(&_indices[ofs]),
|
||||
const_cast<REAL*>(&_weights[ofs]));
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline StencilReal<REAL>
|
||||
StencilTableReal<REAL>::operator[] (Index index) const {
|
||||
return GetStencil(index);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
LimitStencilTableReal<REAL>::resize(int nstencils, int nelems) {
|
||||
StencilTableReal<REAL>::resize(nstencils, nelems);
|
||||
_duWeights.resize(nelems);
|
||||
_dvWeights.resize(nelems);
|
||||
}
|
||||
|
||||
// Returns a LimitStencil at index i in the table
|
||||
template <typename REAL>
|
||||
inline LimitStencilReal<REAL>
|
||||
LimitStencilTableReal<REAL>::GetLimitStencil(Index i) const {
|
||||
assert((! this->GetOffsets().empty()) && i<(int)this->GetOffsets().size());
|
||||
|
||||
Index ofs = this->GetOffsets()[i];
|
||||
|
||||
if (!_duWeights.empty() && !_dvWeights.empty() &&
|
||||
!_duuWeights.empty() && !_duvWeights.empty() && !_dvvWeights.empty()) {
|
||||
return LimitStencilReal<REAL>(
|
||||
const_cast<int *>(&this->GetSizes()[i]),
|
||||
const_cast<Index *>(&this->GetControlIndices()[ofs]),
|
||||
const_cast<REAL *>(&this->GetWeights()[ofs]),
|
||||
const_cast<REAL *>(&GetDuWeights()[ofs]),
|
||||
const_cast<REAL *>(&GetDvWeights()[ofs]),
|
||||
const_cast<REAL *>(&GetDuuWeights()[ofs]),
|
||||
const_cast<REAL *>(&GetDuvWeights()[ofs]),
|
||||
const_cast<REAL *>(&GetDvvWeights()[ofs]) );
|
||||
} else if (!_duWeights.empty() && !_dvWeights.empty()) {
|
||||
return LimitStencilReal<REAL>(
|
||||
const_cast<int *>(&this->GetSizes()[i]),
|
||||
const_cast<Index *>(&this->GetControlIndices()[ofs]),
|
||||
const_cast<REAL *>(&this->GetWeights()[ofs]),
|
||||
const_cast<REAL *>(&GetDuWeights()[ofs]),
|
||||
const_cast<REAL *>(&GetDvWeights()[ofs]) );
|
||||
} else {
|
||||
return LimitStencilReal<REAL>(
|
||||
const_cast<int *>(&this->GetSizes()[i]),
|
||||
const_cast<Index *>(&this->GetControlIndices()[ofs]),
|
||||
const_cast<REAL *>(&this->GetWeights()[ofs]) );
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline LimitStencilReal<REAL>
|
||||
LimitStencilTableReal<REAL>::operator[] (Index index) const {
|
||||
return GetLimitStencil(index);
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_FAR_STENCILTABLE_H
|
||||
678
src/osd/opensubdiv/far/stencilTableFactory.cpp
Normal file
678
src/osd/opensubdiv/far/stencilTableFactory.cpp
Normal file
@@ -0,0 +1,678 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../far/stencilTableFactory.h"
|
||||
#include "../far/stencilBuilder.h"
|
||||
#include "../far/patchTable.h"
|
||||
#include "../far/patchTableFactory.h"
|
||||
#include "../far/patchMap.h"
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../far/primvarRefiner.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
using internal::StencilBuilder;
|
||||
|
||||
namespace {
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning (push)
|
||||
#pragma warning disable 1572
|
||||
#endif
|
||||
|
||||
template <typename REAL>
|
||||
inline bool isWeightZero(REAL w) { return (w == (REAL) 0.0); }
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
StencilTableFactoryReal<REAL>::generateControlVertStencils(
|
||||
int numControlVerts,
|
||||
StencilReal<REAL> & dst) {
|
||||
|
||||
// Control vertices contribute a single index with a weight of 1.0
|
||||
for (int i=0; i<numControlVerts; ++i) {
|
||||
*dst._size = 1;
|
||||
*dst._indices = i;
|
||||
*dst._weights = (REAL) 1.0;
|
||||
dst.Next();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// StencilTable factory
|
||||
//
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const *
|
||||
StencilTableFactoryReal<REAL>::Create(TopologyRefiner const & refiner,
|
||||
Options options) {
|
||||
|
||||
bool interpolateVertex = options.interpolationMode==INTERPOLATE_VERTEX;
|
||||
bool interpolateVarying = options.interpolationMode==INTERPOLATE_VARYING;
|
||||
bool interpolateFaceVarying = options.interpolationMode==INTERPOLATE_FACE_VARYING;
|
||||
|
||||
int numControlVertices = !interpolateFaceVarying
|
||||
? refiner.GetLevel(0).GetNumVertices()
|
||||
: refiner.GetLevel(0).GetNumFVarValues(options.fvarChannel);
|
||||
|
||||
int maxlevel = std::min(int(options.maxLevel), refiner.GetMaxLevel());
|
||||
if (maxlevel==0 && (! options.generateControlVerts)) {
|
||||
StencilTableReal<REAL> * result = new StencilTableReal<REAL>;
|
||||
result->_numControlVertices = numControlVertices;
|
||||
return result;
|
||||
}
|
||||
|
||||
StencilBuilder<REAL> builder(numControlVertices,
|
||||
/*genControlVerts*/ true,
|
||||
/*compactWeights*/ true);
|
||||
|
||||
//
|
||||
// Interpolate stencils for each refinement level using
|
||||
// PrimvarRefiner::InterpolateLevel<>() for vertex or varying
|
||||
//
|
||||
PrimvarRefiner primvarRefiner(refiner);
|
||||
|
||||
typename StencilBuilder<REAL>::Index srcIndex(&builder, 0);
|
||||
typename StencilBuilder<REAL>::Index dstIndex(&builder, numControlVertices);
|
||||
|
||||
for (int level=1; level<=maxlevel; ++level) {
|
||||
if (interpolateVertex) {
|
||||
primvarRefiner.Interpolate(level, srcIndex, dstIndex);
|
||||
} else if (interpolateVarying) {
|
||||
primvarRefiner.InterpolateVarying(level, srcIndex, dstIndex);
|
||||
} else {
|
||||
primvarRefiner.InterpolateFaceVarying(level, srcIndex, dstIndex, options.fvarChannel);
|
||||
}
|
||||
|
||||
if (options.factorizeIntermediateLevels) {
|
||||
srcIndex = dstIndex;
|
||||
}
|
||||
|
||||
int dstVertex = !interpolateFaceVarying
|
||||
? refiner.GetLevel(level).GetNumVertices()
|
||||
: refiner.GetLevel(level).GetNumFVarValues(options.fvarChannel);
|
||||
dstIndex = dstIndex[dstVertex];
|
||||
|
||||
if (! options.factorizeIntermediateLevels) {
|
||||
// All previous verts are considered as coarse verts, as a
|
||||
// result, we don't update the srcIndex and update the coarse
|
||||
// vertex count.
|
||||
builder.SetCoarseVertCount(dstIndex.GetOffset());
|
||||
}
|
||||
}
|
||||
|
||||
size_t firstOffset = numControlVertices;
|
||||
if (! options.generateIntermediateLevels)
|
||||
firstOffset = srcIndex.GetOffset();
|
||||
|
||||
// Copy stencils from the StencilBuilder into the StencilTable.
|
||||
// Always initialize numControlVertices (useful for torus case)
|
||||
StencilTableReal<REAL> * result =
|
||||
new StencilTableReal<REAL>(numControlVertices,
|
||||
builder.GetStencilOffsets(),
|
||||
builder.GetStencilSizes(),
|
||||
builder.GetStencilSources(),
|
||||
builder.GetStencilWeights(),
|
||||
options.generateControlVerts,
|
||||
firstOffset);
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const *
|
||||
StencilTableFactoryReal<REAL>::Create(int numTables,
|
||||
StencilTableReal<REAL> const ** tables) {
|
||||
|
||||
// XXXtakahito:
|
||||
// This function returns NULL for empty inputs or erroneous condition.
|
||||
// It's convenient for skipping varying stencils etc, however,
|
||||
// other Create() API returns an empty stencil instead of NULL.
|
||||
// They need to be consistent.
|
||||
|
||||
if ( (numTables<=0) || (! tables)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ncvs = -1,
|
||||
nstencils = 0,
|
||||
nelems = 0;
|
||||
|
||||
for (int i=0; i<numTables; ++i) {
|
||||
|
||||
StencilTableReal<REAL> const * st = tables[i];
|
||||
// allow the tables could have a null entry.
|
||||
if (!st) continue;
|
||||
|
||||
if (ncvs >= 0 && st->GetNumControlVertices() != ncvs) {
|
||||
return NULL;
|
||||
}
|
||||
ncvs = st->GetNumControlVertices();
|
||||
nstencils += st->GetNumStencils();
|
||||
nelems += (int)st->GetControlIndices().size();
|
||||
}
|
||||
|
||||
if (ncvs == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
StencilTableReal<REAL> * result = new StencilTableReal<REAL>;
|
||||
result->resize(nstencils, nelems);
|
||||
|
||||
int * sizes = &result->_sizes[0];
|
||||
Index * indices = &result->_indices[0];
|
||||
REAL * weights = &result->_weights[0];
|
||||
for (int i=0; i<numTables; ++i) {
|
||||
StencilTableReal<REAL> const * st = tables[i];
|
||||
if (!st) continue;
|
||||
|
||||
int st_nstencils = st->GetNumStencils(),
|
||||
st_nelems = (int)st->_indices.size();
|
||||
memcpy(sizes, &st->_sizes[0], st_nstencils*sizeof(int));
|
||||
memcpy(indices, &st->_indices[0], st_nelems*sizeof(Index));
|
||||
memcpy(weights, &st->_weights[0], st_nelems*sizeof(REAL));
|
||||
|
||||
sizes += st_nstencils;
|
||||
indices += st_nelems;
|
||||
weights += st_nelems;
|
||||
}
|
||||
|
||||
result->_numControlVertices = ncvs;
|
||||
|
||||
// have to re-generate offsets from scratch
|
||||
result->generateOffsets();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const *
|
||||
StencilTableFactoryReal<REAL>::AppendLocalPointStencilTable(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTableReal<REAL> const * baseStencilTable,
|
||||
StencilTableReal<REAL> const * localPointStencilTable,
|
||||
bool factorize) {
|
||||
|
||||
return appendLocalPointStencilTable(
|
||||
refiner,
|
||||
baseStencilTable,
|
||||
localPointStencilTable,
|
||||
/*channel*/-1,
|
||||
factorize);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const *
|
||||
StencilTableFactoryReal<REAL>::AppendLocalPointStencilTableFaceVarying(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTableReal<REAL> const * baseStencilTable,
|
||||
StencilTableReal<REAL> const * localPointStencilTable,
|
||||
int channel,
|
||||
bool factorize) {
|
||||
|
||||
return appendLocalPointStencilTable(
|
||||
refiner,
|
||||
baseStencilTable,
|
||||
localPointStencilTable,
|
||||
channel,
|
||||
factorize);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const *
|
||||
StencilTableFactoryReal<REAL>::appendLocalPointStencilTable(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTableReal<REAL> const * baseStencilTable,
|
||||
StencilTableReal<REAL> const * localPointStencilTable,
|
||||
int channel,
|
||||
bool factorize) {
|
||||
|
||||
// require the local point stencils exist and be non-empty
|
||||
if ((localPointStencilTable == NULL) ||
|
||||
(localPointStencilTable->GetNumStencils() == 0)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int nControlVerts = channel < 0
|
||||
? refiner.GetLevel(0).GetNumVertices()
|
||||
: refiner.GetLevel(0).GetNumFVarValues(channel);
|
||||
|
||||
// if no base stencils or empty, return copy of local point stencils
|
||||
if ((baseStencilTable == NULL) ||
|
||||
(baseStencilTable->GetNumStencils() == 0)) {
|
||||
StencilTableReal<REAL> * result =
|
||||
new StencilTableReal<REAL>(*localPointStencilTable);
|
||||
result->_numControlVertices = nControlVerts;
|
||||
return result;
|
||||
}
|
||||
|
||||
// baseStencilTable can be built with or without singular stencils
|
||||
// (single weight of 1.0f) as place-holders for coarse mesh vertices.
|
||||
|
||||
int controlVertsIndexOffset = 0;
|
||||
int nBaseStencils = baseStencilTable->GetNumStencils();
|
||||
int nBaseStencilsElements = (int)baseStencilTable->_indices.size();
|
||||
{
|
||||
int nverts = channel < 0
|
||||
? refiner.GetNumVerticesTotal()
|
||||
: refiner.GetNumFVarValuesTotal(channel);
|
||||
if (nBaseStencils == nverts) {
|
||||
|
||||
// the table contains stencils for the control vertices
|
||||
//
|
||||
// <----------------- nverts ------------------>
|
||||
//
|
||||
// +---------------+----------------------------+-----------------+
|
||||
// | control verts | refined verts : (max lv) | local points |
|
||||
// +---------------+----------------------------+-----------------+
|
||||
// | base stencil table | LP stencils |
|
||||
// +--------------------------------------------+-----------------+
|
||||
// ^ /
|
||||
// \_________________________/
|
||||
//
|
||||
//
|
||||
controlVertsIndexOffset = 0;
|
||||
|
||||
} else if (nBaseStencils == (nverts - nControlVerts)) {
|
||||
|
||||
// the table does not contain stencils for the control vertices
|
||||
//
|
||||
// <----------------- nverts ------------------>
|
||||
// <------ nBaseStencils ------->
|
||||
// +---------------+----------------------------+-----------------+
|
||||
// | control verts | refined verts : (max lv) | local points |
|
||||
// +---------------+----------------------------+-----------------+
|
||||
// | base stencil table | LP stencils |
|
||||
// +----------------------------+-----------------+
|
||||
// ^ /
|
||||
// \_________________/
|
||||
// <-------------->
|
||||
// controlVertsIndexOffset
|
||||
//
|
||||
controlVertsIndexOffset = nControlVerts;
|
||||
|
||||
} else {
|
||||
// these are not the stencils you are looking for.
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// copy all local point stencils to proto stencils, and factorize if needed.
|
||||
int nLocalPointStencils = localPointStencilTable->GetNumStencils();
|
||||
int nLocalPointStencilsElements = 0;
|
||||
|
||||
StencilBuilder<REAL> builder(nControlVerts,
|
||||
/*genControlVerts*/ false,
|
||||
/*compactWeights*/ factorize);
|
||||
typename StencilBuilder<REAL>::Index origin(&builder, 0);
|
||||
typename StencilBuilder<REAL>::Index dst = origin;
|
||||
typename StencilBuilder<REAL>::Index srcIdx = origin;
|
||||
|
||||
for (int i = 0 ; i < nLocalPointStencils; ++i) {
|
||||
StencilReal<REAL> src = localPointStencilTable->GetStencil(i);
|
||||
dst = origin[i];
|
||||
for (int j = 0; j < src.GetSize(); ++j) {
|
||||
Index index = src.GetVertexIndices()[j];
|
||||
REAL weight = src.GetWeights()[j];
|
||||
if (isWeightZero<REAL>(weight)) continue;
|
||||
|
||||
if (factorize) {
|
||||
dst.AddWithWeight(
|
||||
// subtracting controlVertsIndex if the baseStencil doesn't
|
||||
// include control vertices (see above diagram)
|
||||
// since currently local point stencils are created with
|
||||
// absolute indices including control (level=0) vertices.
|
||||
baseStencilTable->GetStencil(index - controlVertsIndexOffset),
|
||||
weight);
|
||||
} else {
|
||||
srcIdx = origin[index + controlVertsIndexOffset];
|
||||
dst.AddWithWeight(srcIdx, weight);
|
||||
}
|
||||
}
|
||||
nLocalPointStencilsElements += builder.GetNumVertsInStencil(i);
|
||||
}
|
||||
|
||||
// create new stencil table
|
||||
StencilTableReal<REAL> * result = new StencilTableReal<REAL>;
|
||||
result->_numControlVertices = nControlVerts;
|
||||
result->resize(nBaseStencils + nLocalPointStencils,
|
||||
nBaseStencilsElements + nLocalPointStencilsElements);
|
||||
|
||||
int* sizes = &result->_sizes[0];
|
||||
Index * indices = &result->_indices[0];
|
||||
REAL * weights = &result->_weights[0];
|
||||
|
||||
// put base stencils first
|
||||
memcpy(sizes, &baseStencilTable->_sizes[0],
|
||||
nBaseStencils*sizeof(int));
|
||||
memcpy(indices, &baseStencilTable->_indices[0],
|
||||
nBaseStencilsElements*sizeof(Index));
|
||||
memcpy(weights, &baseStencilTable->_weights[0],
|
||||
nBaseStencilsElements*sizeof(REAL));
|
||||
|
||||
sizes += nBaseStencils;
|
||||
indices += nBaseStencilsElements;
|
||||
weights += nBaseStencilsElements;
|
||||
|
||||
// endcap stencils second
|
||||
for (int i = 0 ; i < nLocalPointStencils; ++i) {
|
||||
int size = builder.GetNumVertsInStencil(i);
|
||||
int idx = builder.GetStencilOffsets()[i];
|
||||
for (int j = 0; j < size; ++j) {
|
||||
*indices++ = builder.GetStencilSources()[idx+j];
|
||||
*weights++ = builder.GetStencilWeights()[idx+j];
|
||||
}
|
||||
*sizes++ = size;
|
||||
}
|
||||
|
||||
// have to re-generate offsets from scratch
|
||||
result->generateOffsets();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <typename REAL>
|
||||
LimitStencilTableReal<REAL> const *
|
||||
LimitStencilTableFactoryReal<REAL>::Create(TopologyRefiner const & refiner,
|
||||
LocationArrayVec const & locationArrays,
|
||||
StencilTableReal<REAL> const * cvStencilsIn,
|
||||
PatchTable const * patchTableIn,
|
||||
Options options) {
|
||||
|
||||
// Compute the total number of stencils to generate
|
||||
int numStencils=0, numLimitStencils=0;
|
||||
for (int i=0; i<(int)locationArrays.size(); ++i) {
|
||||
assert(locationArrays[i].numLocations>=0);
|
||||
numStencils += locationArrays[i].numLocations;
|
||||
}
|
||||
if (numStencils<=0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool uniform = refiner.IsUniform();
|
||||
int maxlevel = refiner.GetMaxLevel();
|
||||
|
||||
bool interpolateVertex = (options.interpolationMode == INTERPOLATE_VERTEX);
|
||||
bool interpolateVarying = (options.interpolationMode == INTERPOLATE_VARYING);
|
||||
bool interpolateFaceVarying = (options.interpolationMode == INTERPOLATE_FACE_VARYING);
|
||||
int fvarChannel = options.fvarChannel;
|
||||
|
||||
//
|
||||
// Quick sanity checks for given PatchTable and/or StencilTables:
|
||||
//
|
||||
int nRefinedStencils = 0;
|
||||
if (uniform) {
|
||||
// Uniform stencils must include at least the last level points:
|
||||
nRefinedStencils = interpolateFaceVarying
|
||||
? refiner.GetLevel(maxlevel).GetNumFVarValues(fvarChannel)
|
||||
: refiner.GetLevel(maxlevel).GetNumVertices();
|
||||
} else {
|
||||
// Adaptive stencils must include at least all refined points:
|
||||
nRefinedStencils = interpolateFaceVarying
|
||||
? refiner.GetNumFVarValuesTotal(fvarChannel)
|
||||
: refiner.GetNumVerticesTotal();
|
||||
}
|
||||
if (cvStencilsIn && (cvStencilsIn->GetNumStencils() < nRefinedStencils)) {
|
||||
// Too few stencils in given StencilTable
|
||||
return 0;
|
||||
}
|
||||
if (patchTableIn && (patchTableIn->IsFeatureAdaptive() == uniform)) {
|
||||
// Adaptive/uniform mismatch with given PatchTable and refiner
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If an appropriate StencilTable was given, use it, otherwise, create a new one
|
||||
StencilTableReal<REAL> const * cvstencils = cvStencilsIn;
|
||||
if (! cvstencils) {
|
||||
//
|
||||
// Generate stencils for the control vertices - this is necessary to
|
||||
// properly factorize patches with control vertices at level 0 (natural
|
||||
// regular patches, such as in a torus)
|
||||
// note: the control vertices of the mesh are added as single-index
|
||||
// stencils of weight 1.0f
|
||||
//
|
||||
typename StencilTableFactoryReal<REAL>::Options stencilTableOptions;
|
||||
stencilTableOptions.generateIntermediateLevels = uniform ? false :true;
|
||||
stencilTableOptions.generateControlVerts = true;
|
||||
stencilTableOptions.generateOffsets = true;
|
||||
stencilTableOptions.interpolationMode = options.interpolationMode;
|
||||
stencilTableOptions.fvarChannel = options.fvarChannel;
|
||||
|
||||
cvstencils = StencilTableFactoryReal<REAL>::Create(refiner, stencilTableOptions);
|
||||
}
|
||||
|
||||
// If an appropriate PatchTable was given, use it, otherwise, create a new one
|
||||
PatchTable const * patchtable = patchTableIn;
|
||||
if (! patchtable) {
|
||||
//
|
||||
// Ideally we could create a sparse PatchTable here for the given
|
||||
// Locations, but that requires inverting the ptex/base-face relation.
|
||||
// so the caller must deal with that and provide such a PatchTable
|
||||
//
|
||||
PatchTableFactory::Options patchTableOptions;
|
||||
patchTableOptions.SetPatchPrecision<REAL>();
|
||||
patchTableOptions.includeBaseLevelIndices = true;
|
||||
patchTableOptions.generateVaryingTables = interpolateVarying;
|
||||
patchTableOptions.generateFVarTables = interpolateFaceVarying;
|
||||
if (interpolateFaceVarying) {
|
||||
patchTableOptions.includeFVarBaseLevelIndices = true;
|
||||
patchTableOptions.numFVarChannels = 1;
|
||||
patchTableOptions.fvarChannelIndices = &fvarChannel;
|
||||
patchTableOptions.generateFVarLegacyLinearPatches = uniform ||
|
||||
!refiner.GetAdaptiveOptions().considerFVarChannels;
|
||||
}
|
||||
patchTableOptions.SetEndCapType(
|
||||
Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS);
|
||||
patchTableOptions.useInfSharpPatch = !uniform &&
|
||||
refiner.GetAdaptiveOptions().useInfSharpPatch;
|
||||
|
||||
patchtable = PatchTableFactory::Create(refiner, patchTableOptions);
|
||||
}
|
||||
|
||||
// Append local point stencils and further verfiy size of given StencilTable:
|
||||
StencilTableReal<REAL> const * localstencils = 0;
|
||||
if (interpolateVertex) {
|
||||
localstencils = patchtable->GetLocalPointStencilTable<REAL>();
|
||||
} else if (interpolateFaceVarying) {
|
||||
localstencils = patchtable->GetLocalPointFaceVaryingStencilTable<REAL>(fvarChannel);
|
||||
} else {
|
||||
localstencils = patchtable->GetLocalPointVaryingStencilTable<REAL>();
|
||||
}
|
||||
|
||||
if (localstencils && (cvstencils->GetNumStencils() == nRefinedStencils)) {
|
||||
StencilTableReal<REAL> const *refinedstencils = cvstencils;
|
||||
if (interpolateFaceVarying) {
|
||||
cvstencils = StencilTableFactoryReal<REAL>::AppendLocalPointStencilTableFaceVarying(
|
||||
refiner, refinedstencils, localstencils, fvarChannel);
|
||||
} else {
|
||||
cvstencils = StencilTableFactoryReal<REAL>::AppendLocalPointStencilTable(
|
||||
refiner, refinedstencils, localstencils);
|
||||
}
|
||||
if (!cvStencilsIn) delete refinedstencils;
|
||||
}
|
||||
|
||||
assert(patchtable && cvstencils);
|
||||
|
||||
// Create a patch-map to locate sub-patches faster
|
||||
PatchMap patchmap( *patchtable );
|
||||
|
||||
//
|
||||
// Generate limit stencils for locations
|
||||
//
|
||||
int nControlVertices = interpolateFaceVarying
|
||||
? refiner.GetLevel(0).GetNumFVarValues(fvarChannel)
|
||||
: refiner.GetLevel(0).GetNumVertices();
|
||||
|
||||
StencilBuilder<REAL> builder(nControlVertices,
|
||||
/*genControlVerts*/ false,
|
||||
/*compactWeights*/ true);
|
||||
typename StencilBuilder<REAL>::Index origin(&builder, 0);
|
||||
typename StencilBuilder<REAL>::Index dst = origin;
|
||||
|
||||
//
|
||||
// Generally use the patches corresponding to the interpolation mode, but Uniform
|
||||
// PatchTables do not have varying patches -- use the equivalent linear vertex
|
||||
// patches in this case:
|
||||
//
|
||||
bool useVertexPatches = interpolateVertex || (interpolateVarying && uniform);
|
||||
bool useFVarPatches = interpolateFaceVarying;
|
||||
|
||||
REAL wP[20], wDs[20], wDt[20], wDss[20], wDst[20], wDtt[20];
|
||||
|
||||
for (size_t i=0; i<locationArrays.size(); ++i) {
|
||||
LocationArray const & array = locationArrays[i];
|
||||
assert(array.ptexIdx>=0);
|
||||
|
||||
for (int j=0; j<array.numLocations; ++j) { // for each face we're working on
|
||||
REAL s = array.s[j],
|
||||
t = array.t[j]; // for each target (s,t) point on that face
|
||||
|
||||
PatchMap::Handle const * handle =
|
||||
patchmap.FindPatch(array.ptexIdx, s, t);
|
||||
if (handle) {
|
||||
ConstIndexArray cvs;
|
||||
if (useVertexPatches) {
|
||||
cvs = patchtable->GetPatchVertices(*handle);
|
||||
} else if (useFVarPatches) {
|
||||
cvs = patchtable->GetPatchFVarValues(*handle, fvarChannel);
|
||||
} else {
|
||||
cvs = patchtable->GetPatchVaryingVertices(*handle);
|
||||
}
|
||||
|
||||
StencilTableReal<REAL> const & src = *cvstencils;
|
||||
dst = origin[numLimitStencils];
|
||||
|
||||
if (options.generate2ndDerivatives) {
|
||||
if (useVertexPatches) {
|
||||
patchtable->EvaluateBasis<REAL>(
|
||||
*handle, s, t, wP, wDs, wDt, wDss, wDst, wDtt);
|
||||
} else if (useFVarPatches) {
|
||||
patchtable->EvaluateBasisFaceVarying<REAL>(
|
||||
*handle, s, t, wP, wDs, wDt, wDss, wDst, wDtt, fvarChannel);
|
||||
} else {
|
||||
patchtable->EvaluateBasisVarying<REAL>(
|
||||
*handle, s, t, wP, wDs, wDt, wDss, wDst, wDtt);
|
||||
}
|
||||
|
||||
dst.Clear();
|
||||
for (int k = 0; k < cvs.size(); ++k) {
|
||||
dst.AddWithWeight(src[cvs[k]], wP[k], wDs[k], wDt[k], wDss[k], wDst[k], wDtt[k]);
|
||||
}
|
||||
} else if (options.generate1stDerivatives) {
|
||||
if (useVertexPatches) {
|
||||
patchtable->EvaluateBasis<REAL>(
|
||||
*handle, s, t, wP, wDs, wDt);
|
||||
} else if (useFVarPatches) {
|
||||
patchtable->EvaluateBasisFaceVarying<REAL>(
|
||||
*handle, s, t, wP, wDs, wDt, 0, 0, 0, fvarChannel);
|
||||
} else {
|
||||
patchtable->EvaluateBasisVarying<REAL>(
|
||||
*handle, s, t, wP, wDs, wDt);
|
||||
}
|
||||
|
||||
dst.Clear();
|
||||
for (int k = 0; k < cvs.size(); ++k) {
|
||||
dst.AddWithWeight(src[cvs[k]], wP[k], wDs[k], wDt[k]);
|
||||
}
|
||||
} else {
|
||||
if (useVertexPatches) {
|
||||
patchtable->EvaluateBasis<REAL>(
|
||||
*handle, s, t, wP);
|
||||
} else if (useFVarPatches) {
|
||||
patchtable->EvaluateBasisFaceVarying<REAL>(
|
||||
*handle, s, t, wP, 0, 0, 0, 0, 0, fvarChannel);
|
||||
} else {
|
||||
patchtable->EvaluateBasisVarying<REAL>(
|
||||
*handle, s, t, wP);
|
||||
}
|
||||
|
||||
dst.Clear();
|
||||
for (int k = 0; k < cvs.size(); ++k) {
|
||||
dst.AddWithWeight(src[cvs[k]], wP[k]);
|
||||
}
|
||||
}
|
||||
|
||||
++numLimitStencils;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! cvStencilsIn) {
|
||||
delete cvstencils;
|
||||
}
|
||||
|
||||
if (! patchTableIn) {
|
||||
delete patchtable;
|
||||
}
|
||||
|
||||
//
|
||||
// Copy the proto-stencils into the limit stencil table
|
||||
//
|
||||
LimitStencilTableReal<REAL> * result = new LimitStencilTableReal<REAL>(
|
||||
nControlVertices,
|
||||
builder.GetStencilOffsets(),
|
||||
builder.GetStencilSizes(),
|
||||
builder.GetStencilSources(),
|
||||
builder.GetStencilWeights(),
|
||||
builder.GetStencilDuWeights(),
|
||||
builder.GetStencilDvWeights(),
|
||||
builder.GetStencilDuuWeights(),
|
||||
builder.GetStencilDuvWeights(),
|
||||
builder.GetStencilDvvWeights(),
|
||||
/*ctrlVerts*/false,
|
||||
/*fristOffset*/0);
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Explicit instantiation for float and double:
|
||||
//
|
||||
template class StencilTableFactoryReal<float>;
|
||||
template class StencilTableFactoryReal<double>;
|
||||
|
||||
template class LimitStencilTableFactoryReal<float>;
|
||||
template class LimitStencilTableFactoryReal<double>;
|
||||
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
384
src/osd/opensubdiv/far/stencilTableFactory.h
Normal file
384
src/osd/opensubdiv/far/stencilTableFactory.h
Normal file
@@ -0,0 +1,384 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_STENCILTABLE_FACTORY_H
|
||||
#define OPENSUBDIV3_FAR_STENCILTABLE_FACTORY_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/patchTable.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
class TopologyRefiner;
|
||||
|
||||
template <typename REAL> class StencilReal;
|
||||
template <typename REAL> class StencilTableReal;
|
||||
|
||||
template <typename REAL> class LimitStencilReal;
|
||||
template <typename REAL> class LimitStencilTableReal;
|
||||
|
||||
|
||||
/// \brief A specialized factory for StencilTable
|
||||
///
|
||||
template <typename REAL>
|
||||
class StencilTableFactoryReal {
|
||||
|
||||
public:
|
||||
|
||||
enum Mode {
|
||||
INTERPOLATE_VERTEX=0, ///< vertex primvar stencils
|
||||
INTERPOLATE_VARYING, ///< varying primvar stencils
|
||||
INTERPOLATE_FACE_VARYING ///< face-varying primvar stencils
|
||||
};
|
||||
|
||||
struct Options {
|
||||
|
||||
Options() : interpolationMode(INTERPOLATE_VERTEX),
|
||||
generateOffsets(false),
|
||||
generateControlVerts(false),
|
||||
generateIntermediateLevels(true),
|
||||
factorizeIntermediateLevels(true),
|
||||
maxLevel(10),
|
||||
fvarChannel(0) { }
|
||||
|
||||
unsigned int interpolationMode : 2, ///< interpolation mode
|
||||
generateOffsets : 1, ///< populate optional "_offsets" field
|
||||
generateControlVerts : 1, ///< generate stencils for control-vertices
|
||||
generateIntermediateLevels : 1, ///< vertices at all levels or highest only
|
||||
factorizeIntermediateLevels : 1, ///< accumulate stencil weights from control
|
||||
/// vertices or from the stencils of the
|
||||
/// previous level
|
||||
maxLevel : 4; ///< generate stencils up to 'maxLevel'
|
||||
unsigned int fvarChannel; ///< face-varying channel to use
|
||||
/// when generating face-varying stencils
|
||||
};
|
||||
|
||||
/// \brief Instantiates StencilTable from TopologyRefiner that have been
|
||||
/// refined uniformly or adaptively.
|
||||
///
|
||||
/// \note The factory only creates stencils for vertices that have already
|
||||
/// been refined in the TopologyRefiner. Use RefineUniform() or
|
||||
/// RefineAdaptive() before constructing the stencils.
|
||||
///
|
||||
/// @param refiner The TopologyRefiner containing the topology
|
||||
///
|
||||
/// @param options Options controlling the creation of the table
|
||||
///
|
||||
static StencilTableReal<REAL> const * Create(
|
||||
TopologyRefiner const & refiner, Options options = Options());
|
||||
|
||||
|
||||
/// \brief Instantiates StencilTable by concatenating an array of existing
|
||||
/// stencil tables.
|
||||
///
|
||||
/// \note This factory checks that the stencil tables point to the same set
|
||||
/// of supporting control vertices - no re-indexing is done.
|
||||
/// GetNumControlVertices() *must* return the same value for all input
|
||||
/// tables.
|
||||
///
|
||||
/// @param numTables Number of input StencilTables
|
||||
///
|
||||
/// @param tables Array of input StencilTables
|
||||
///
|
||||
static StencilTableReal<REAL> const * Create(
|
||||
int numTables, StencilTableReal<REAL> const ** tables);
|
||||
|
||||
|
||||
/// \brief Utility function for stencil splicing for local point stencils.
|
||||
///
|
||||
/// @param refiner The TopologyRefiner containing the topology
|
||||
///
|
||||
/// @param baseStencilTable Input StencilTable for refined vertices
|
||||
///
|
||||
/// @param localPointStencilTable
|
||||
/// StencilTable for the change of basis patch points.
|
||||
///
|
||||
/// @param factorize If factorize is set to true, endcap stencils will be
|
||||
/// factorized with supporting vertices from baseStencil
|
||||
/// table so that the endcap points can be computed
|
||||
/// directly from control vertices.
|
||||
///
|
||||
static StencilTableReal<REAL> const * AppendLocalPointStencilTable(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTableReal<REAL> const *baseStencilTable,
|
||||
StencilTableReal<REAL> const *localPointStencilTable,
|
||||
bool factorize = true);
|
||||
|
||||
/// \brief Utility function for stencil splicing for local point varying stencils.
|
||||
///
|
||||
/// @param refiner The TopologyRefiner containing the topology
|
||||
///
|
||||
/// @param baseStencilTable Input StencilTable for refined vertices
|
||||
///
|
||||
/// @param localPointStencilTable
|
||||
/// StencilTable for the change of basis patch points.
|
||||
///
|
||||
/// @param factorize If factorize is set to true, endcap stencils will be
|
||||
/// factorized with supporting vertices from baseStencil
|
||||
/// table so that the endcap points can be computed
|
||||
/// directly from control vertices.
|
||||
///
|
||||
static StencilTableReal<REAL> const * AppendLocalPointStencilTableVarying(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTableReal<REAL> const *baseStencilTable,
|
||||
StencilTableReal<REAL> const *localPointStencilTable,
|
||||
bool factorize = true) {
|
||||
return AppendLocalPointStencilTable(
|
||||
refiner, baseStencilTable, localPointStencilTable, factorize);
|
||||
}
|
||||
|
||||
/// \brief Utility function for stencil splicing for local point
|
||||
/// face-varying stencils.
|
||||
///
|
||||
/// @param refiner The TopologyRefiner containing the topology
|
||||
///
|
||||
/// @param baseStencilTable Input StencilTable for refined vertices
|
||||
///
|
||||
/// @param localPointStencilTable
|
||||
/// StencilTable for the change of basis patch points.
|
||||
///
|
||||
/// @param channel face-varying channel
|
||||
///
|
||||
/// @param factorize If factorize is set to true, endcap stencils will be
|
||||
/// factorized with supporting vertices from baseStencil
|
||||
/// table so that the endcap points can be computed
|
||||
/// directly from control vertices.
|
||||
///
|
||||
static StencilTableReal<REAL> const * AppendLocalPointStencilTableFaceVarying(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTableReal<REAL> const *baseStencilTable,
|
||||
StencilTableReal<REAL> const *localPointStencilTable,
|
||||
int channel = 0,
|
||||
bool factorize = true);
|
||||
|
||||
private:
|
||||
|
||||
// Generate stencils for the coarse control-vertices (single weight = 1.0f)
|
||||
static void generateControlVertStencils(
|
||||
int numControlVerts,
|
||||
StencilReal<REAL> & dst);
|
||||
|
||||
// Internal method to splice local point stencils
|
||||
static StencilTableReal<REAL> const * appendLocalPointStencilTable(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTableReal<REAL> const * baseStencilTable,
|
||||
StencilTableReal<REAL> const * localPointStencilTable,
|
||||
int channel,
|
||||
bool factorize);
|
||||
};
|
||||
|
||||
/// \brief A specialized factory for LimitStencilTable
|
||||
///
|
||||
/// The LimitStencilTableFactory creates a table of limit stencils. Limit
|
||||
/// stencils can interpolate any arbitrary location on the limit surface.
|
||||
/// The stencils will be bilinear if the surface is refined uniformly, and
|
||||
/// bicubic if feature adaptive isolation is used instead.
|
||||
///
|
||||
/// Surface locations are expressed as a combination of ptex face index and
|
||||
/// normalized (s,t) patch coordinates. The factory exposes the LocationArray
|
||||
/// struct as a container for these location descriptors.
|
||||
///
|
||||
template <typename REAL>
|
||||
class LimitStencilTableFactoryReal {
|
||||
|
||||
public:
|
||||
|
||||
enum Mode {
|
||||
INTERPOLATE_VERTEX=0, ///< vertex primvar stencils
|
||||
INTERPOLATE_VARYING, ///< varying primvar stencils
|
||||
INTERPOLATE_FACE_VARYING ///< face-varying primvar stencils
|
||||
};
|
||||
|
||||
struct Options {
|
||||
|
||||
Options() : interpolationMode(INTERPOLATE_VERTEX),
|
||||
generate1stDerivatives(true),
|
||||
generate2ndDerivatives(false),
|
||||
fvarChannel(0) { }
|
||||
|
||||
unsigned int interpolationMode : 2, ///< interpolation mode
|
||||
generate1stDerivatives : 1, ///< Generate weights for 1st derivatives
|
||||
generate2ndDerivatives : 1; ///< Generate weights for 2nd derivatives
|
||||
unsigned int fvarChannel; ///< face-varying channel to use
|
||||
};
|
||||
|
||||
/// \brief Descriptor for limit surface locations
|
||||
struct LocationArray {
|
||||
|
||||
LocationArray() : ptexIdx(-1), numLocations(0), s(0), t(0) { }
|
||||
|
||||
int ptexIdx, ///< ptex face index
|
||||
numLocations; ///< number of (u,v) coordinates in the array
|
||||
|
||||
REAL const * s, ///< array of u coordinates
|
||||
* t; ///< array of v coordinates
|
||||
};
|
||||
|
||||
typedef std::vector<LocationArray> LocationArrayVec;
|
||||
|
||||
/// \brief Instantiates LimitStencilTable from a TopologyRefiner that has
|
||||
/// been refined either uniformly or adaptively.
|
||||
///
|
||||
/// @param refiner The TopologyRefiner containing the topology
|
||||
///
|
||||
/// @param locationArrays An array of surface location descriptors
|
||||
/// (see LocationArray)
|
||||
///
|
||||
/// @param cvStencils A StencilTable generated from the TopologyRefiner
|
||||
/// (Optional: prevents redundant instantiation of the
|
||||
/// table if available. The given table must at least
|
||||
/// contain stencils for all control points and all
|
||||
/// refined points -- any stencils for local points of
|
||||
/// a PatchTable must match the PatchTable provided or
|
||||
/// internally generated)
|
||||
///
|
||||
/// @param patchTable A PatchTable generated from the TopologyRefiner
|
||||
/// (Optional: prevents redundant instantiation of the
|
||||
/// table if available. The given table must match
|
||||
/// the optional StencilTable if also provided)
|
||||
///
|
||||
/// @param options Options controlling the creation of the table
|
||||
///
|
||||
static LimitStencilTableReal<REAL> const * Create(
|
||||
TopologyRefiner const & refiner,
|
||||
LocationArrayVec const & locationArrays,
|
||||
StencilTableReal<REAL> const * cvStencils = 0,
|
||||
PatchTable const * patchTable = 0,
|
||||
Options options = Options());
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Public wrapper classes for the templates
|
||||
//
|
||||
class Stencil;
|
||||
class StencilTable;
|
||||
|
||||
/// \brief Stencil table factory class wrapping the template for compatibility.
|
||||
///
|
||||
class StencilTableFactory : public StencilTableFactoryReal<float> {
|
||||
private:
|
||||
typedef StencilTableFactoryReal<float> BaseFactory;
|
||||
typedef StencilTableReal<float> BaseTable;
|
||||
|
||||
public:
|
||||
static StencilTable const * Create(
|
||||
TopologyRefiner const & refiner, Options options = Options()) {
|
||||
|
||||
return static_cast<StencilTable const *>(
|
||||
BaseFactory::Create(refiner, options));
|
||||
}
|
||||
|
||||
static StencilTable const * Create(
|
||||
int numTables, StencilTable const ** tables) {
|
||||
|
||||
return static_cast<StencilTable const *>(
|
||||
BaseFactory::Create(numTables,
|
||||
reinterpret_cast<BaseTable const **>(tables)));
|
||||
}
|
||||
|
||||
static StencilTable const * AppendLocalPointStencilTable(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTable const *baseStencilTable,
|
||||
StencilTable const *localPointStencilTable,
|
||||
bool factorize = true) {
|
||||
|
||||
return static_cast<StencilTable const *>(
|
||||
BaseFactory::AppendLocalPointStencilTable(refiner,
|
||||
static_cast<BaseTable const *>(baseStencilTable),
|
||||
static_cast<BaseTable const *>(localPointStencilTable),
|
||||
factorize));
|
||||
}
|
||||
|
||||
static StencilTable const * AppendLocalPointStencilTableVarying(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTable const *baseStencilTable,
|
||||
StencilTable const *localPointStencilTable,
|
||||
bool factorize = true) {
|
||||
|
||||
return static_cast<StencilTable const *>(
|
||||
BaseFactory::AppendLocalPointStencilTableVarying(refiner,
|
||||
static_cast<BaseTable const *>(baseStencilTable),
|
||||
static_cast<BaseTable const *>(localPointStencilTable),
|
||||
factorize));
|
||||
}
|
||||
|
||||
static StencilTable const * AppendLocalPointStencilTableFaceVarying(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTable const *baseStencilTable,
|
||||
StencilTable const *localPointStencilTable,
|
||||
int channel = 0,
|
||||
bool factorize = true) {
|
||||
|
||||
return static_cast<StencilTable const *>(
|
||||
BaseFactory::AppendLocalPointStencilTableFaceVarying(refiner,
|
||||
static_cast<BaseTable const *>(baseStencilTable),
|
||||
static_cast<BaseTable const *>(localPointStencilTable),
|
||||
channel, factorize));
|
||||
}
|
||||
};
|
||||
|
||||
class LimitStencil;
|
||||
class LimitStencilTable;
|
||||
|
||||
/// \brief Stencil table factory class wrapping the template for compatibility.
|
||||
///
|
||||
class LimitStencilTableFactory : public LimitStencilTableFactoryReal<float> {
|
||||
private:
|
||||
typedef LimitStencilTableFactoryReal<float> BaseFactory;
|
||||
typedef StencilTableReal<float> BaseTable;
|
||||
|
||||
public:
|
||||
static LimitStencilTable const * Create(
|
||||
TopologyRefiner const & refiner,
|
||||
LocationArrayVec const & locationArrays,
|
||||
StencilTable const * cvStencils = 0,
|
||||
PatchTable const * patchTable = 0,
|
||||
Options options = Options()) {
|
||||
|
||||
return static_cast<LimitStencilTable const *>(
|
||||
BaseFactory::Create(
|
||||
refiner,
|
||||
locationArrays,
|
||||
static_cast<BaseTable const *>(cvStencils),
|
||||
patchTable,
|
||||
options));
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_FAR_STENCILTABLE_FACTORY_H
|
||||
185
src/osd/opensubdiv/far/topologyDescriptor.cpp
Normal file
185
src/osd/opensubdiv/far/topologyDescriptor.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
#include "../far/topologyDescriptor.h"
|
||||
#include "../far/topologyRefinerFactory.h"
|
||||
#include "../far/topologyRefiner.h"
|
||||
|
||||
// Unfortunately necessary for error codes that should be more accessible...
|
||||
#include "../vtr/level.h"
|
||||
|
||||
#include <cstdio>
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// Definitions for TopologyDescriptor:
|
||||
//
|
||||
TopologyDescriptor::TopologyDescriptor() {
|
||||
memset(this, 0, sizeof(TopologyDescriptor));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Definitions/specializations for its RefinerFactory<TopologyDescriptor>:
|
||||
//
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::resizeComponentTopology(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc) {
|
||||
|
||||
setNumBaseVertices(refiner, desc.numVertices);
|
||||
setNumBaseFaces(refiner, desc.numFaces);
|
||||
|
||||
for (int face=0; face<desc.numFaces; ++face) {
|
||||
|
||||
setNumBaseFaceVertices(refiner, face, desc.numVertsPerFace[face]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::assignComponentTopology(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc) {
|
||||
|
||||
for (int face=0, idx=0; face<desc.numFaces; ++face) {
|
||||
|
||||
IndexArray dstFaceVerts = getBaseFaceVertices(refiner, face);
|
||||
|
||||
if (desc.isLeftHanded) {
|
||||
dstFaceVerts[0] = desc.vertIndicesPerFace[idx++];
|
||||
for (int vert=dstFaceVerts.size()-1; vert > 0; --vert) {
|
||||
|
||||
dstFaceVerts[vert] = desc.vertIndicesPerFace[idx++];
|
||||
}
|
||||
} else {
|
||||
for (int vert=0; vert<dstFaceVerts.size(); ++vert) {
|
||||
|
||||
dstFaceVerts[vert] = desc.vertIndicesPerFace[idx++];
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::assignComponentTags(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc) {
|
||||
|
||||
if ((desc.numCreases>0) && desc.creaseVertexIndexPairs && desc.creaseWeights) {
|
||||
|
||||
int const * vertIndexPairs = desc.creaseVertexIndexPairs;
|
||||
for (int edge=0; edge<desc.numCreases; ++edge, vertIndexPairs+=2) {
|
||||
|
||||
Index idx = findBaseEdge(refiner, vertIndexPairs[0], vertIndexPairs[1]);
|
||||
|
||||
if (idx!=INDEX_INVALID) {
|
||||
setBaseEdgeSharpness(refiner, idx, desc.creaseWeights[edge]);
|
||||
} else {
|
||||
char msg[1024];
|
||||
snprintf(msg, 1024, "Edge %d specified to be sharp does not exist (%d, %d)",
|
||||
edge, vertIndexPairs[0], vertIndexPairs[1]);
|
||||
reportInvalidTopology(Vtr::internal::Level::TOPOLOGY_INVALID_CREASE_EDGE, msg, desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((desc.numCorners>0) && desc.cornerVertexIndices && desc.cornerWeights) {
|
||||
|
||||
for (int vert=0; vert<desc.numCorners; ++vert) {
|
||||
|
||||
int idx = desc.cornerVertexIndices[vert];
|
||||
|
||||
if (idx >= 0 && idx < getNumBaseVertices(refiner)) {
|
||||
setBaseVertexSharpness(refiner, idx, desc.cornerWeights[vert]);
|
||||
} else {
|
||||
char msg[1024];
|
||||
snprintf(msg, 1024, "Vertex %d specified to be sharp does not exist", idx);
|
||||
reportInvalidTopology(Vtr::internal::Level::TOPOLOGY_INVALID_CREASE_VERT, msg, desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (desc.numHoles>0) {
|
||||
for (int i=0; i<desc.numHoles; ++i) {
|
||||
setBaseFaceHole(refiner, desc.holeIndices[i], true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::assignFaceVaryingTopology(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc) {
|
||||
|
||||
if (desc.numFVarChannels>0) {
|
||||
|
||||
for (int channel=0; channel<desc.numFVarChannels; ++channel) {
|
||||
|
||||
int numFVarValues = desc.fvarChannels[channel].numValues;
|
||||
int const* srcFVarValues = desc.fvarChannels[channel].valueIndices;
|
||||
|
||||
createBaseFVarChannel(refiner, numFVarValues);
|
||||
|
||||
for (int face = 0, srcNext = 0; face < desc.numFaces; ++face) {
|
||||
|
||||
IndexArray dstFaceFVarValues = getBaseFaceFVarValues(refiner, face, channel);
|
||||
|
||||
if (desc.isLeftHanded) {
|
||||
dstFaceFVarValues[0] = srcFVarValues[srcNext++];
|
||||
for (int vert = dstFaceFVarValues.size() - 1; vert > 0; --vert) {
|
||||
|
||||
dstFaceFVarValues[vert] = srcFVarValues[srcNext++];
|
||||
}
|
||||
} else {
|
||||
for (int vert = 0; vert < dstFaceFVarValues.size(); ++vert) {
|
||||
|
||||
dstFaceFVarValues[vert] = srcFVarValues[srcNext++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
void
|
||||
TopologyRefinerFactory<TopologyDescriptor>::reportInvalidTopology(
|
||||
TopologyError /* errCode */, char const * msg, TopologyDescriptor const& /* mesh */) {
|
||||
Warning(msg);
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
127
src/osd/opensubdiv/far/topologyDescriptor.h
Normal file
127
src/osd/opensubdiv/far/topologyDescriptor.h
Normal file
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_FAR_TOPOLOGY_DESCRIPTOR_H
|
||||
#define OPENSUBDIV3_FAR_TOPOLOGY_DESCRIPTOR_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../far/topologyRefinerFactory.h"
|
||||
#include "../far/error.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
///
|
||||
/// \brief A simple reference to raw topology data for use with TopologyRefinerFactory
|
||||
///
|
||||
/// TopologyDescriptor is a simple struct containing references to raw topology data used
|
||||
/// to construct a TopologyRefiner. It is not a requirement but a convenience for use
|
||||
/// with TopologyRefinerFactory when mesh topology is not available in an existing mesh
|
||||
/// data structure. It should be functionally complete and simple to use, but for more
|
||||
/// demanding situations, writing a custom Factory is usually warranted.
|
||||
///
|
||||
struct TopologyDescriptor {
|
||||
|
||||
int numVertices,
|
||||
numFaces;
|
||||
|
||||
int const * numVertsPerFace;
|
||||
Index const * vertIndicesPerFace;
|
||||
|
||||
int numCreases;
|
||||
Index const * creaseVertexIndexPairs;
|
||||
float const * creaseWeights;
|
||||
|
||||
int numCorners;
|
||||
Index const * cornerVertexIndices;
|
||||
float const * cornerWeights;
|
||||
|
||||
int numHoles;
|
||||
Index const * holeIndices;
|
||||
|
||||
bool isLeftHanded;
|
||||
|
||||
// Face-varying data channel -- value indices correspond to vertex indices,
|
||||
// i.e. one for every vertex of every face:
|
||||
//
|
||||
struct FVarChannel {
|
||||
|
||||
int numValues;
|
||||
Index const * valueIndices;
|
||||
|
||||
FVarChannel() : numValues(0), valueIndices(0) { }
|
||||
};
|
||||
|
||||
int numFVarChannels;
|
||||
FVarChannel const * fvarChannels;
|
||||
|
||||
TopologyDescriptor();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Forward declarations of required TopologyRefinerFactory<TopologyDescriptor>
|
||||
// specializations (defined internally):
|
||||
//
|
||||
// @cond EXCLUDE_DOXYGEN
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::resizeComponentTopology(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc);
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::assignComponentTopology(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc);
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::assignComponentTags(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc);
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::assignFaceVaryingTopology(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc);
|
||||
|
||||
template <>
|
||||
void
|
||||
TopologyRefinerFactory<TopologyDescriptor>::reportInvalidTopology(
|
||||
TopologyError errCode, char const * msg, TopologyDescriptor const & desc);
|
||||
|
||||
// @endcond
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_TOPOLOGY_DESCRIPTOR_H */
|
||||
273
src/osd/opensubdiv/far/topologyLevel.h
Normal file
273
src/osd/opensubdiv/far/topologyLevel.h
Normal file
@@ -0,0 +1,273 @@
|
||||
//
|
||||
// Copyright 2015 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_FAR_TOPOLOGY_LEVEL_H
|
||||
#define OPENSUBDIV3_FAR_TOPOLOGY_LEVEL_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../vtr/level.h"
|
||||
#include "../vtr/refinement.h"
|
||||
#include "../far/types.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
///
|
||||
/// \brief An interface for accessing data in a specific level of a refined topology hierarchy.
|
||||
///
|
||||
/// TopologyLevel provides an interface to data in a specific level of a topology hierarchy.
|
||||
/// Instances of TopologyLevel are created and owned by a TopologyRefiner,
|
||||
/// which will return const-references to them. Such references are only valid during the
|
||||
/// lifetime of the TopologyRefiner that created and returned them, and only for a given refinement,
|
||||
/// i.e. if the TopologyRefiner is re-refined, any references to TopoologyLevels are invalidated.
|
||||
///
|
||||
class TopologyLevel {
|
||||
|
||||
public:
|
||||
//@{
|
||||
/// @name Methods to inspect the overall inventory of components:
|
||||
///
|
||||
/// All three main component types are indexed locally within each level. For
|
||||
/// some topological relationships -- notably face-vertices, which is often
|
||||
/// the only relationship of interest -- the total number of entries is also
|
||||
/// made available.
|
||||
///
|
||||
|
||||
/// \brief Return the number of vertices in this level
|
||||
int GetNumVertices() const { return _level->getNumVertices(); }
|
||||
|
||||
/// \brief Return the number of faces in this level
|
||||
int GetNumFaces() const { return _level->getNumFaces(); }
|
||||
|
||||
/// \brief Return the number of edges in this level
|
||||
int GetNumEdges() const { return _level->getNumEdges(); }
|
||||
|
||||
/// \brief Return the total number of face-vertices, i.e. the sum of all vertices for all faces
|
||||
int GetNumFaceVertices() const { return _level->getNumFaceVerticesTotal(); }
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Methods to inspect topological relationships for individual components:
|
||||
///
|
||||
/// With three main component types (vertices, faces and edges), for each of the
|
||||
/// three components the TopologyLevel stores the incident/adjacent components of
|
||||
/// the other two types. So there are six relationships available for immediate
|
||||
/// inspection. All are accessed by methods that return an array of fixed size
|
||||
/// containing the indices of the incident components.
|
||||
///
|
||||
/// For some of the relations, i.e. those for which the incident components are
|
||||
/// of higher order or 'contain' the component itself (e.g. a vertex has incident
|
||||
/// faces that contain it), an additional 'local index' is available that identifies
|
||||
/// the component within each of its neighbors. For example, if vertex V is the k'th
|
||||
/// vertex in some face F, then when F occurs in the set of incident vertices of V,
|
||||
/// the local index corresponding to F will be k. The ordering of local indices
|
||||
/// matches the ordering of the incident component to which it corresponds.
|
||||
//
|
||||
|
||||
/// \brief Access the vertices incident a given face
|
||||
ConstIndexArray GetFaceVertices(Index f) const { return _level->getFaceVertices(f); }
|
||||
|
||||
/// \brief Access the edges incident a given face
|
||||
ConstIndexArray GetFaceEdges(Index f) const { return _level->getFaceEdges(f); }
|
||||
|
||||
/// \brief Access the vertices incident a given edge
|
||||
ConstIndexArray GetEdgeVertices(Index e) const { return _level->getEdgeVertices(e); }
|
||||
|
||||
/// \brief Access the faces incident a given edge
|
||||
ConstIndexArray GetEdgeFaces(Index e) const { return _level->getEdgeFaces(e); }
|
||||
|
||||
/// \brief Access the faces incident a given vertex
|
||||
ConstIndexArray GetVertexFaces(Index v) const { return _level->getVertexFaces(v); }
|
||||
|
||||
/// \brief Access the edges incident a given vertex
|
||||
ConstIndexArray GetVertexEdges(Index v) const { return _level->getVertexEdges(v); }
|
||||
|
||||
/// \brief Access the local indices of a vertex with respect to its incident faces
|
||||
ConstLocalIndexArray GetVertexFaceLocalIndices(Index v) const { return _level->getVertexFaceLocalIndices(v); }
|
||||
|
||||
/// \brief Access the local indices of a vertex with respect to its incident edges
|
||||
ConstLocalIndexArray GetVertexEdgeLocalIndices(Index v) const { return _level->getVertexEdgeLocalIndices(v); }
|
||||
|
||||
/// \brief Access the local indices of an edge with respect to its incident faces
|
||||
ConstLocalIndexArray GetEdgeFaceLocalIndices(Index e) const { return _level->getEdgeFaceLocalIndices(e); }
|
||||
|
||||
/// \brief Identify the edge matching the given vertex pair
|
||||
Index FindEdge(Index v0, Index v1) const { return _level->findEdge(v0, v1); }
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Methods to inspect other topological properties of individual components:
|
||||
///
|
||||
|
||||
/// \brief Return if the edge is non-manifold
|
||||
bool IsEdgeNonManifold(Index e) const { return _level->isEdgeNonManifold(e); }
|
||||
|
||||
/// \brief Return if the vertex is non-manifold
|
||||
bool IsVertexNonManifold(Index v) const { return _level->isVertexNonManifold(v); }
|
||||
|
||||
/// \brief Return if the edge is a boundary
|
||||
bool IsEdgeBoundary(Index e) const { return _level->getEdgeTag(e)._boundary; }
|
||||
|
||||
/// \brief Return if the vertex is a boundary
|
||||
bool IsVertexBoundary(Index v) const { return _level->getVertexTag(v)._boundary; }
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Methods to inspect feature tags for individual components:
|
||||
///
|
||||
/// While only a subset of components may have been tagged with features such
|
||||
/// as sharpness, all such features have a default value and so all components
|
||||
/// can be inspected.
|
||||
|
||||
/// \brief Return the sharpness assigned a given edge
|
||||
float GetEdgeSharpness(Index e) const { return _level->getEdgeSharpness(e); }
|
||||
|
||||
/// \brief Return the sharpness assigned a given vertex
|
||||
float GetVertexSharpness(Index v) const { return _level->getVertexSharpness(v); }
|
||||
|
||||
/// \brief Return if a given face has been tagged as a hole
|
||||
bool IsFaceHole(Index f) const { return _level->isFaceHole(f); }
|
||||
|
||||
/// \brief Return the subdivision rule assigned a given vertex specific to this level
|
||||
Sdc::Crease::Rule GetVertexRule(Index v) const { return _level->getVertexRule(v); }
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Methods to inspect face-varying data:
|
||||
///
|
||||
/// Face-varying data is organized into topologically independent channels,
|
||||
/// each with an integer identifier. Access to face-varying data generally
|
||||
/// requires the specification of a channel, though with a single channel
|
||||
/// being a common situation the first/only channel will be assumed if
|
||||
/// unspecified.
|
||||
///
|
||||
/// A face-varying channel is composed of a set of values that may be shared
|
||||
/// by faces meeting at a common vertex. Just as there are sets of vertices
|
||||
/// that are associated with faces by index (ranging from 0 to
|
||||
/// num-vertices - 1), face-varying values are also referenced by index
|
||||
/// (ranging from 0 to num-values -1).
|
||||
///
|
||||
/// The face-varying values associated with a face are accessed similarly to
|
||||
/// the way in which vertices associated with the face are accessed -- an
|
||||
/// array of fixed size containing the indices for each corner is provided
|
||||
/// for inspection, iteration, etc.
|
||||
///
|
||||
/// When the face-varying topology around a vertex "matches", it has the
|
||||
/// same limit properties and so results in the same limit surface when
|
||||
/// collections of adjacent vertices match. Like other references to
|
||||
/// "topology", this includes consideration of sharpness. So it may be
|
||||
/// that face-varying values are assigned around a vertex on a boundary in
|
||||
/// a way that appears to match, but the face-varying interpolation option
|
||||
/// requires sharpening of that vertex in face-varying space -- the
|
||||
/// difference in the topology of the resulting limit surfaces leading to
|
||||
/// the query returning false for the match. The edge case is simpler in
|
||||
/// that it only considers continuity across the edge, not the entire
|
||||
/// neighborhood around each end vertex.
|
||||
|
||||
/// \brief Return the number of face-varying channels (should be same for all levels)
|
||||
int GetNumFVarChannels() const { return _level->getNumFVarChannels(); }
|
||||
|
||||
/// \brief Return the total number of face-varying values in a particular channel
|
||||
/// (the upper bound of a face-varying value index)
|
||||
int GetNumFVarValues(int channel = 0) const { return _level->getNumFVarValues(channel); }
|
||||
|
||||
/// \brief Access the face-varying values associated with a particular face
|
||||
ConstIndexArray GetFaceFVarValues(Index f, int channel = 0) const {
|
||||
return _level->getFaceFVarValues(f, channel);
|
||||
}
|
||||
|
||||
/// \brief Return if face-varying topology around a vertex matches
|
||||
bool DoesVertexFVarTopologyMatch(Index v, int channel = 0) const {
|
||||
return _level->doesVertexFVarTopologyMatch(v, channel);
|
||||
}
|
||||
|
||||
/// \brief Return if face-varying topology across the edge only matches
|
||||
bool DoesEdgeFVarTopologyMatch(Index e, int channel = 0) const {
|
||||
return _level->doesEdgeFVarTopologyMatch(e, channel);
|
||||
}
|
||||
|
||||
/// \brief Return if face-varying topology around a face matches
|
||||
bool DoesFaceFVarTopologyMatch(Index f, int channel = 0) const {
|
||||
return _level->doesFaceFVarTopologyMatch(f, channel);
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Methods to identify parent or child components in adjoining levels of refinement:
|
||||
|
||||
/// \brief Access the child faces (in the next level) of a given face
|
||||
ConstIndexArray GetFaceChildFaces(Index f) const { return _refToChild->getFaceChildFaces(f); }
|
||||
|
||||
/// \brief Access the child edges (in the next level) of a given face
|
||||
ConstIndexArray GetFaceChildEdges(Index f) const { return _refToChild->getFaceChildEdges(f); }
|
||||
|
||||
/// \brief Access the child edges (in the next level) of a given edge
|
||||
ConstIndexArray GetEdgeChildEdges(Index e) const { return _refToChild->getEdgeChildEdges(e); }
|
||||
|
||||
/// \brief Return the child vertex (in the next level) of a given face
|
||||
Index GetFaceChildVertex( Index f) const { return _refToChild->getFaceChildVertex(f); }
|
||||
|
||||
/// \brief Return the child vertex (in the next level) of a given edge
|
||||
Index GetEdgeChildVertex( Index e) const { return _refToChild->getEdgeChildVertex(e); }
|
||||
|
||||
/// \brief Return the child vertex (in the next level) of a given vertex
|
||||
Index GetVertexChildVertex(Index v) const { return _refToChild->getVertexChildVertex(v); }
|
||||
|
||||
/// \brief Return the parent face (in the previous level) of a given face
|
||||
Index GetFaceParentFace(Index f) const { return _refToParent->getChildFaceParentFace(f); }
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Debugging aides:
|
||||
|
||||
bool ValidateTopology() const { return _level->validateTopology(); }
|
||||
void PrintTopology(bool children = true) const { _level->print((children && _refToChild) ? _refToChild : 0); }
|
||||
//@}
|
||||
|
||||
|
||||
private:
|
||||
friend class TopologyRefiner;
|
||||
|
||||
Vtr::internal::Level const * _level;
|
||||
Vtr::internal::Refinement const * _refToParent;
|
||||
Vtr::internal::Refinement const * _refToChild;
|
||||
|
||||
public:
|
||||
// Not intended for public use, but required by std::vector, etc...
|
||||
TopologyLevel() { }
|
||||
~TopologyLevel() { }
|
||||
};
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_TOPOLOGY_LEVEL_H */
|
||||
826
src/osd/opensubdiv/far/topologyRefiner.cpp
Normal file
826
src/osd/opensubdiv/far/topologyRefiner.cpp
Normal file
@@ -0,0 +1,826 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../far/error.h"
|
||||
#include "../vtr/fvarLevel.h"
|
||||
#include "../vtr/sparseSelector.h"
|
||||
#include "../vtr/quadRefinement.h"
|
||||
#include "../vtr/triRefinement.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// Relatively trivial construction/destruction -- the base level (level[0]) needs
|
||||
// to be explicitly initialized after construction and refinement then applied
|
||||
//
|
||||
TopologyRefiner::TopologyRefiner(Sdc::SchemeType schemeType, Sdc::Options schemeOptions) :
|
||||
_subdivType(schemeType),
|
||||
_subdivOptions(schemeOptions),
|
||||
_isUniform(true),
|
||||
_hasHoles(false),
|
||||
_hasIrregFaces(false),
|
||||
_regFaceSize(Sdc::SchemeTypeTraits::GetRegularFaceSize(schemeType)),
|
||||
_maxLevel(0),
|
||||
_uniformOptions(0),
|
||||
_adaptiveOptions(0),
|
||||
_totalVertices(0),
|
||||
_totalEdges(0),
|
||||
_totalFaces(0),
|
||||
_totalFaceVertices(0),
|
||||
_maxValence(0),
|
||||
_baseLevelOwned(true) {
|
||||
|
||||
// Need to revisit allocation scheme here -- want to use smart-ptrs for these
|
||||
// but will probably have to settle for explicit new/delete...
|
||||
_levels.reserve(10);
|
||||
_levels.push_back(new Vtr::internal::Level);
|
||||
_farLevels.reserve(10);
|
||||
assembleFarLevels();
|
||||
}
|
||||
|
||||
//
|
||||
// The copy constructor is protected and used by the factory to create a new instance
|
||||
// from only the base level of the given instance -- it does not create a full copy.
|
||||
// So members reflecting any refinement are default-initialized while those dependent
|
||||
// on the base level are copied or explicitly initialized after its assignment.
|
||||
//
|
||||
TopologyRefiner::TopologyRefiner(TopologyRefiner const & source) :
|
||||
_subdivType(source._subdivType),
|
||||
_subdivOptions(source._subdivOptions),
|
||||
_isUniform(true),
|
||||
_hasHoles(source._hasHoles),
|
||||
_hasIrregFaces(source._hasIrregFaces),
|
||||
_regFaceSize(source._regFaceSize),
|
||||
_maxLevel(0),
|
||||
_uniformOptions(0),
|
||||
_adaptiveOptions(0),
|
||||
_baseLevelOwned(false) {
|
||||
|
||||
_levels.reserve(10);
|
||||
_levels.push_back(source._levels[0]);
|
||||
initializeInventory();
|
||||
|
||||
_farLevels.reserve(10);
|
||||
assembleFarLevels();
|
||||
}
|
||||
|
||||
|
||||
TopologyRefiner::~TopologyRefiner() {
|
||||
|
||||
for (int i=0; i<(int)_levels.size(); ++i) {
|
||||
if ((i > 0) || _baseLevelOwned) delete _levels[i];
|
||||
}
|
||||
|
||||
for (int i=0; i<(int)_refinements.size(); ++i) {
|
||||
delete _refinements[i];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TopologyRefiner::Unrefine() {
|
||||
|
||||
if (_levels.size()) {
|
||||
for (int i=1; i<(int)_levels.size(); ++i) {
|
||||
delete _levels[i];
|
||||
}
|
||||
_levels.resize(1);
|
||||
initializeInventory();
|
||||
}
|
||||
for (int i=0; i<(int)_refinements.size(); ++i) {
|
||||
delete _refinements[i];
|
||||
}
|
||||
_refinements.clear();
|
||||
|
||||
assembleFarLevels();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Initializing and updating the component inventory:
|
||||
//
|
||||
void
|
||||
TopologyRefiner::initializeInventory() {
|
||||
|
||||
if (_levels.size()) {
|
||||
assert(_levels.size() == 1);
|
||||
|
||||
Vtr::internal::Level const & baseLevel = *_levels[0];
|
||||
|
||||
_totalVertices = baseLevel.getNumVertices();
|
||||
_totalEdges = baseLevel.getNumEdges();
|
||||
_totalFaces = baseLevel.getNumFaces();
|
||||
_totalFaceVertices = baseLevel.getNumFaceVerticesTotal();
|
||||
|
||||
_maxValence = baseLevel.getMaxValence();
|
||||
} else {
|
||||
_totalVertices = 0;
|
||||
_totalEdges = 0;
|
||||
_totalFaces = 0;
|
||||
_totalFaceVertices = 0;
|
||||
|
||||
_maxValence = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TopologyRefiner::updateInventory(Vtr::internal::Level const & newLevel) {
|
||||
|
||||
_totalVertices += newLevel.getNumVertices();
|
||||
_totalEdges += newLevel.getNumEdges();
|
||||
_totalFaces += newLevel.getNumFaces();
|
||||
_totalFaceVertices += newLevel.getNumFaceVerticesTotal();
|
||||
|
||||
_maxValence = std::max(_maxValence, newLevel.getMaxValence());
|
||||
}
|
||||
|
||||
void
|
||||
TopologyRefiner::appendLevel(Vtr::internal::Level & newLevel) {
|
||||
|
||||
_levels.push_back(&newLevel);
|
||||
|
||||
updateInventory(newLevel);
|
||||
}
|
||||
|
||||
void
|
||||
TopologyRefiner::appendRefinement(Vtr::internal::Refinement & newRefinement) {
|
||||
|
||||
_refinements.push_back(&newRefinement);
|
||||
}
|
||||
|
||||
void
|
||||
TopologyRefiner::assembleFarLevels() {
|
||||
|
||||
_farLevels.resize(_levels.size());
|
||||
|
||||
_farLevels[0]._refToParent = 0;
|
||||
_farLevels[0]._level = _levels[0];
|
||||
_farLevels[0]._refToChild = 0;
|
||||
|
||||
int nRefinements = (int)_refinements.size();
|
||||
if (nRefinements) {
|
||||
_farLevels[0]._refToChild = _refinements[0];
|
||||
|
||||
for (int i = 1; i < nRefinements; ++i) {
|
||||
_farLevels[i]._refToParent = _refinements[i - 1];
|
||||
_farLevels[i]._level = _levels[i];
|
||||
_farLevels[i]._refToChild = _refinements[i];;
|
||||
}
|
||||
|
||||
_farLevels[nRefinements]._refToParent = _refinements[nRefinements - 1];
|
||||
_farLevels[nRefinements]._level = _levels[nRefinements];
|
||||
_farLevels[nRefinements]._refToChild = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Accessors to the topology information:
|
||||
//
|
||||
int
|
||||
TopologyRefiner::GetNumFVarValuesTotal(int channel) const {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < (int)_levels.size(); ++i) {
|
||||
sum += _levels[i]->getNumFVarValues(channel);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Main refinement method -- allocating and initializing levels and refinements:
|
||||
//
|
||||
void
|
||||
TopologyRefiner::RefineUniform(UniformOptions options) {
|
||||
|
||||
if (_levels[0]->getNumVertices() == 0) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefiner::RefineUniform() -- base level is uninitialized.");
|
||||
return;
|
||||
}
|
||||
if (_refinements.size()) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefiner::RefineUniform() -- previous refinements already applied.");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate the stack of levels and the refinements between them:
|
||||
//
|
||||
_uniformOptions = options;
|
||||
|
||||
_isUniform = true;
|
||||
_maxLevel = options.refinementLevel;
|
||||
|
||||
Sdc::Split splitType = Sdc::SchemeTypeTraits::GetTopologicalSplitType(_subdivType);
|
||||
|
||||
//
|
||||
// Initialize refinement options for Vtr -- adjusting full-topology for the last level:
|
||||
//
|
||||
Vtr::internal::Refinement::Options refineOptions;
|
||||
refineOptions._sparse = false;
|
||||
refineOptions._faceVertsFirst = options.orderVerticesFromFacesFirst;
|
||||
|
||||
for (int i = 1; i <= (int)options.refinementLevel; ++i) {
|
||||
refineOptions._minimalTopology =
|
||||
options.fullTopologyInLastLevel ? false : (i == (int)options.refinementLevel);
|
||||
|
||||
Vtr::internal::Level& parentLevel = getLevel(i-1);
|
||||
Vtr::internal::Level& childLevel = *(new Vtr::internal::Level);
|
||||
|
||||
Vtr::internal::Refinement* refinement = 0;
|
||||
if (splitType == Sdc::SPLIT_TO_QUADS) {
|
||||
refinement = new Vtr::internal::QuadRefinement(parentLevel, childLevel, _subdivOptions);
|
||||
} else {
|
||||
refinement = new Vtr::internal::TriRefinement(parentLevel, childLevel, _subdivOptions);
|
||||
}
|
||||
refinement->refine(refineOptions);
|
||||
|
||||
appendLevel(childLevel);
|
||||
appendRefinement(*refinement);
|
||||
}
|
||||
assembleFarLevels();
|
||||
}
|
||||
|
||||
//
|
||||
// Internal utility class and function supporting feature adaptive selection of faces...
|
||||
//
|
||||
namespace internal {
|
||||
//
|
||||
// FeatureMask is a simple set of bits identifying features to be selected during a level of
|
||||
// adaptive refinement. Adaptive refinement options passed the Refiner are interpreted as a
|
||||
// specific set of features defined here. Given options to reduce faces generated at deeper
|
||||
// levels, a method to "reduce" the set of features is also provided here.
|
||||
//
|
||||
// This class was specifically not nested in TopologyRefiner to allow simple non-class methods
|
||||
// to make use of it in the core selection methods. Those selection methods were similarly
|
||||
// made non-class methods to ensure they conform to the feature set defined by the FeatureMask
|
||||
// and not some internal class state.
|
||||
//
|
||||
class FeatureMask {
|
||||
public:
|
||||
typedef TopologyRefiner::AdaptiveOptions Options;
|
||||
typedef unsigned int int_type;
|
||||
|
||||
void Clear() { *((int_type*)this) = 0; }
|
||||
bool IsEmpty() const { return *((int_type*)this) == 0; }
|
||||
|
||||
FeatureMask() { Clear(); }
|
||||
FeatureMask(Options const & options, int regFaceSize) {
|
||||
Clear();
|
||||
InitializeFeatures(options, regFaceSize);
|
||||
}
|
||||
|
||||
// These are the two primary methods intended for use -- intialization via a set of Options
|
||||
// and reduction of the subsequent feature set (which presumes prior initialization with the
|
||||
// same set as give)
|
||||
//
|
||||
void InitializeFeatures(Options const & options, int regFaceSize);
|
||||
void ReduceFeatures( Options const & options);
|
||||
|
||||
public:
|
||||
int_type selectXOrdinaryInterior : 1;
|
||||
int_type selectXOrdinaryBoundary : 1;
|
||||
|
||||
int_type selectSemiSharpSingle : 1;
|
||||
int_type selectSemiSharpNonSingle : 1;
|
||||
|
||||
int_type selectInfSharpRegularCrease : 1;
|
||||
int_type selectInfSharpRegularCorner : 1;
|
||||
int_type selectInfSharpIrregularDart : 1;
|
||||
int_type selectInfSharpIrregularCrease : 1;
|
||||
int_type selectInfSharpIrregularCorner : 1;
|
||||
|
||||
int_type selectUnisolatedInteriorEdge : 1;
|
||||
|
||||
int_type selectNonManifold : 1;
|
||||
int_type selectFVarFeatures : 1;
|
||||
};
|
||||
|
||||
void
|
||||
FeatureMask::InitializeFeatures(Options const & options, int regFaceSize) {
|
||||
|
||||
//
|
||||
// Support for the "single-crease patch" case is limited to the subdivision scheme
|
||||
// (currently only Catmull-Clark). It has historically been applied to both semi-
|
||||
// sharp and inf-sharp creases -- the semi-sharp application is still relevant,
|
||||
// but the inf-sharp has been superceded.
|
||||
//
|
||||
// The inf-sharp single-crease case now corresponds to an inf-sharp regular crease
|
||||
// in the interior -- and since such regular creases on the boundary are never
|
||||
// considered for selection (just as interior smoot regular faces are not), this
|
||||
// feature is only relevant for the interior case. So aside from it being used
|
||||
// when regular inf-sharp features are all selected, it can also be used for the
|
||||
// single-crease case.
|
||||
//
|
||||
bool useSingleCreasePatch = options.useSingleCreasePatch && (regFaceSize == 4);
|
||||
|
||||
// Extra-ordinary features (independent of the inf-sharp options):
|
||||
selectXOrdinaryInterior = true;
|
||||
selectXOrdinaryBoundary = true;
|
||||
|
||||
// Semi-sharp features -- the regular single crease case and all others:
|
||||
selectSemiSharpSingle = !useSingleCreasePatch;
|
||||
selectSemiSharpNonSingle = true;
|
||||
|
||||
// Inf-sharp features -- boundary extra-ordinary vertices are irreg creases:
|
||||
selectInfSharpRegularCrease = !(options.useInfSharpPatch || useSingleCreasePatch);
|
||||
selectInfSharpRegularCorner = !options.useInfSharpPatch;
|
||||
selectInfSharpIrregularDart = true;
|
||||
selectInfSharpIrregularCrease = true;
|
||||
selectInfSharpIrregularCorner = true;
|
||||
|
||||
selectUnisolatedInteriorEdge = useSingleCreasePatch && !options.useInfSharpPatch;
|
||||
|
||||
selectNonManifold = true;
|
||||
selectFVarFeatures = options.considerFVarChannels;
|
||||
}
|
||||
|
||||
void
|
||||
FeatureMask::ReduceFeatures(Options const & options) {
|
||||
|
||||
// Disable typical xordinary vertices:
|
||||
selectXOrdinaryInterior = false;
|
||||
selectXOrdinaryBoundary = false;
|
||||
|
||||
// If minimizing inf-sharp patches, disable all but sharp/corner irregularities
|
||||
if (options.useInfSharpPatch) {
|
||||
selectInfSharpRegularCrease = false;
|
||||
selectInfSharpRegularCorner = false;
|
||||
selectInfSharpIrregularDart = false;
|
||||
selectInfSharpIrregularCrease = false;
|
||||
}
|
||||
}
|
||||
} // end namespace internal
|
||||
|
||||
void
|
||||
TopologyRefiner::RefineAdaptive(AdaptiveOptions options,
|
||||
ConstIndexArray baseFacesToRefine) {
|
||||
|
||||
if (_levels[0]->getNumVertices() == 0) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefiner::RefineAdaptive() -- base level is uninitialized.");
|
||||
return;
|
||||
}
|
||||
if (_refinements.size()) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefiner::RefineAdaptive() -- previous refinements already applied.");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize member and local variables from the adaptive options:
|
||||
//
|
||||
_isUniform = false;
|
||||
_adaptiveOptions = options;
|
||||
|
||||
//
|
||||
// Initialize the feature-selection options based on given options -- with two sets
|
||||
// of levels isolating different sets of features, initialize the two feature sets
|
||||
// up front and use the appropriate one for each level:
|
||||
//
|
||||
int nonLinearScheme = Sdc::SchemeTypeTraits::GetLocalNeighborhoodSize(_subdivType);
|
||||
|
||||
int shallowLevel = std::min<int>(options.secondaryLevel, options.isolationLevel);
|
||||
int deeperLevel = options.isolationLevel;
|
||||
|
||||
int potentialMaxLevel = nonLinearScheme ? deeperLevel : _hasIrregFaces;
|
||||
|
||||
internal::FeatureMask moreFeaturesMask(options, _regFaceSize);
|
||||
internal::FeatureMask lessFeaturesMask = moreFeaturesMask;
|
||||
|
||||
if (shallowLevel < potentialMaxLevel) {
|
||||
lessFeaturesMask.ReduceFeatures(options);
|
||||
}
|
||||
|
||||
//
|
||||
// If face-varying channels are considered, make sure non-linear channels are present
|
||||
// and turn off consideration if none present:
|
||||
//
|
||||
if (moreFeaturesMask.selectFVarFeatures && nonLinearScheme) {
|
||||
bool nonLinearChannelsPresent = false;
|
||||
for (int channel = 0; channel < _levels[0]->getNumFVarChannels(); ++channel) {
|
||||
nonLinearChannelsPresent |= !_levels[0]->getFVarLevel(channel).isLinear();
|
||||
}
|
||||
if (!nonLinearChannelsPresent) {
|
||||
moreFeaturesMask.selectFVarFeatures = false;
|
||||
lessFeaturesMask.selectFVarFeatures = false;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize refinement options for Vtr -- full topology is always generated in
|
||||
// the last level as expected usage is for patch retrieval:
|
||||
//
|
||||
Vtr::internal::Refinement::Options refineOptions;
|
||||
|
||||
refineOptions._sparse = true;
|
||||
refineOptions._minimalTopology = false;
|
||||
refineOptions._faceVertsFirst = options.orderVerticesFromFacesFirst;
|
||||
|
||||
Sdc::Split splitType = Sdc::SchemeTypeTraits::GetTopologicalSplitType(_subdivType);
|
||||
|
||||
for (int i = 1; i <= potentialMaxLevel; ++i) {
|
||||
|
||||
Vtr::internal::Level& parentLevel = getLevel(i-1);
|
||||
Vtr::internal::Level& childLevel = *(new Vtr::internal::Level);
|
||||
|
||||
Vtr::internal::Refinement* refinement = 0;
|
||||
if (splitType == Sdc::SPLIT_TO_QUADS) {
|
||||
refinement = new Vtr::internal::QuadRefinement(parentLevel, childLevel, _subdivOptions);
|
||||
} else {
|
||||
refinement = new Vtr::internal::TriRefinement(parentLevel, childLevel, _subdivOptions);
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize a Selector to mark a sparse set of components for refinement -- choose
|
||||
// the feature selection mask appropriate to the level:
|
||||
//
|
||||
Vtr::internal::SparseSelector selector(*refinement);
|
||||
|
||||
internal::FeatureMask const & levelFeatures = (i <= shallowLevel) ? moreFeaturesMask
|
||||
: lessFeaturesMask;
|
||||
|
||||
if (i > 1) {
|
||||
selectFeatureAdaptiveComponents(selector, levelFeatures, ConstIndexArray());
|
||||
} else if (nonLinearScheme) {
|
||||
selectFeatureAdaptiveComponents(selector, levelFeatures, baseFacesToRefine);
|
||||
} else {
|
||||
selectLinearIrregularFaces(selector, baseFacesToRefine);
|
||||
}
|
||||
|
||||
if (selector.isSelectionEmpty()) {
|
||||
delete refinement;
|
||||
delete &childLevel;
|
||||
break;
|
||||
} else {
|
||||
refinement->refine(refineOptions);
|
||||
|
||||
appendLevel(childLevel);
|
||||
appendRefinement(*refinement);
|
||||
}
|
||||
}
|
||||
_maxLevel = (unsigned int) _refinements.size();
|
||||
|
||||
assembleFarLevels();
|
||||
}
|
||||
|
||||
//
|
||||
// Local utility functions for selecting features in faces for adaptive refinement:
|
||||
//
|
||||
namespace {
|
||||
//
|
||||
// First are a couple of low-level utility methods to perform the same analysis
|
||||
// at a corner or the entire face for specific detection of inf-sharp or boundary
|
||||
// features. These are shared between the analysis of the main face and those in
|
||||
// face-varying channels (which only differ from the main face in the presence of
|
||||
// face-varying boundaries).
|
||||
//
|
||||
// The first can be applied equally to an individual corner or to the entire face
|
||||
// (using its composite tag). The second applies to the entire face, making use
|
||||
// of the first, and is the main entry point for dealng with inf-sharp features.
|
||||
//
|
||||
// Note we can use the composite tag here even though it arises from all corners
|
||||
// of the face and so does not represent a specific corner. When at least one
|
||||
// smooth interior vertex exists, it limits the combinations that can exist on the
|
||||
// remaining corners (though quads and tris cannot be treated equally here).
|
||||
//
|
||||
// If any inf-sharp features are to be selected, identify them first as irregular
|
||||
// or not, then qualify them more specifically. (Remember that a regular vertex
|
||||
// may have its neighboring faces partitioned into irregular regions in the
|
||||
// presence of inf-sharp edges. Similarly an irregular vertex may have its
|
||||
// neighborhood partitioned into regular regions.)
|
||||
//
|
||||
inline bool
|
||||
doesInfSharpVTagHaveFeatures(Vtr::internal::Level::VTag compVTag,
|
||||
internal::FeatureMask const & featureMask) {
|
||||
|
||||
// Note that even though the given VTag may represent an individual corner, we
|
||||
// use more general bitwise tests here (particularly the Rule) so that we can
|
||||
// pass in a composite tag for the entire face and have the same tests applied:
|
||||
//
|
||||
if (compVTag._infIrregular) {
|
||||
if (compVTag._rule & Sdc::Crease::RULE_CORNER) {
|
||||
return featureMask.selectInfSharpIrregularCorner;
|
||||
} else if (compVTag._rule & Sdc::Crease::RULE_CREASE) {
|
||||
return compVTag._boundary ? featureMask.selectXOrdinaryBoundary :
|
||||
featureMask.selectInfSharpIrregularCrease;
|
||||
} else if (compVTag._rule & Sdc::Crease::RULE_DART) {
|
||||
return featureMask.selectInfSharpIrregularDart;
|
||||
}
|
||||
} else if (compVTag._boundary) {
|
||||
// Remember that regular boundary features should never be selected, except
|
||||
// for a boundary crease sharpened (and so a Corner) by an interior edge:
|
||||
|
||||
if (compVTag._rule & Sdc::Crease::RULE_CORNER) {
|
||||
return compVTag._corner ? false : featureMask.selectInfSharpRegularCorner;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (compVTag._rule & Sdc::Crease::RULE_CORNER) {
|
||||
return featureMask.selectInfSharpRegularCorner;
|
||||
} else {
|
||||
return featureMask.selectInfSharpRegularCrease;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool
|
||||
doesInfSharpFaceHaveFeatures(Vtr::internal::Level::VTag compVTag,
|
||||
Vtr::internal::Level::VTag vTags[], int numVerts,
|
||||
internal::FeatureMask const & featureMask) {
|
||||
//
|
||||
// For quads, if at least one smooth corner of a regular face, features
|
||||
// are isolated enough to make use of the composite tag alone (unless
|
||||
// boundary isolation is enabled, in which case trivially return).
|
||||
//
|
||||
// For tris, the presence of boundaries creates more ambiguity, so we
|
||||
// need to exclude that case and inspect corner features individually.
|
||||
//
|
||||
bool isolateQuadBoundaries = false;
|
||||
|
||||
bool atLeastOneSmoothCorner = (compVTag._rule & Sdc::Crease::RULE_SMOOTH);
|
||||
if (numVerts == 4) {
|
||||
if (atLeastOneSmoothCorner) {
|
||||
return doesInfSharpVTagHaveFeatures(compVTag, featureMask);
|
||||
} else if (isolateQuadBoundaries) {
|
||||
return true;
|
||||
} else if (featureMask.selectUnisolatedInteriorEdge) {
|
||||
// Needed for single-crease approximation to inf-sharp interior edge:
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (vTags[i]._infSharpEdges && !vTags[i]._boundary) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (atLeastOneSmoothCorner && !compVTag._boundary) {
|
||||
return doesInfSharpVTagHaveFeatures(compVTag, featureMask);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numVerts; ++i) {
|
||||
if (!(vTags[i]._rule & Sdc::Crease::RULE_SMOOTH)) {
|
||||
if (doesInfSharpVTagHaveFeatures(vTags[i], featureMask)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// This is the core method/function for analyzing a face and deciding whether or not
|
||||
// to included it during feature-adaptive refinement.
|
||||
//
|
||||
// Topological analysis of the face exploits tags that are applied to corner vertices
|
||||
// and carried through the refinement hierarchy. The tags were designed with this
|
||||
// in mind and also to be combined via bitwise-OR to make collective decisions about
|
||||
// the neighborhood of the entire face.
|
||||
//
|
||||
// After a few trivial acceptances/rejections, feature detection is divided up into
|
||||
// semi-sharp and inf-sharp cases -- note that both may be present, but semi-sharp
|
||||
// features have an implicit precedence until they decay and so are handled first.
|
||||
// They are also fairly trivial to deal with (most often requiring selection) while
|
||||
// the presence of boundaries and additional options complicates the inf-sharp case.
|
||||
// Since the inf-sharp logic needs to be applied in face-varying cases, it exists in
|
||||
// a separate method.
|
||||
//
|
||||
// This was originally written specific to the quad-centric Catmark scheme and was
|
||||
// since generalized to support Loop given the enhanced tagging of components based
|
||||
// on the scheme. Any enhancements here should be aware of the intended generality.
|
||||
// Ultimately it may not be worth trying to keep this general and we will be better
|
||||
// off specializing it for each scheme. The fact that this method is intimately tied
|
||||
// to patch generation also begs for it to become part of a class that encompasses
|
||||
// both the feature adaptive tagging and the identification of the intended patches
|
||||
// that result from it.
|
||||
//
|
||||
bool
|
||||
doesFaceHaveFeatures(Vtr::internal::Level const& level, Index face,
|
||||
internal::FeatureMask const & featureMask, int regFaceSize) {
|
||||
|
||||
using Vtr::internal::Level;
|
||||
|
||||
ConstIndexArray fVerts = level.getFaceVertices(face);
|
||||
|
||||
// Irregular faces (base level) are unconditionally included:
|
||||
if (fVerts.size() != regFaceSize) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Gather and combine the VTags:
|
||||
Level::VTag vTags[4];
|
||||
level.getFaceVTags(face, vTags);
|
||||
|
||||
Level::VTag compFaceVTag = Level::VTag::BitwiseOr(vTags, fVerts.size());
|
||||
|
||||
// Faces incident irregular faces (base level) are unconditionally included:
|
||||
if (compFaceVTag._incidIrregFace) {
|
||||
return true;
|
||||
}
|
||||
// Incomplete faces (incomplete neighborhood) are unconditionally excluded:
|
||||
if (compFaceVTag._incomplete) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Select non-manifold features if specified, otherwise treat as inf-sharp:
|
||||
if (compFaceVTag._nonManifold && featureMask.selectNonManifold) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Select (smooth) xord vertices if specified, boundaries handled with inf-sharp:
|
||||
if (compFaceVTag._xordinary && featureMask.selectXOrdinaryInterior) {
|
||||
if (compFaceVTag._rule == Sdc::Crease::RULE_SMOOTH) {
|
||||
return true;
|
||||
} else if (level.getDepth() < 2) {
|
||||
for (int i = 0; i < fVerts.size(); ++i) {
|
||||
if (vTags[i]._xordinary && (vTags[i]._rule == Sdc::Crease::RULE_SMOOTH)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If all smooth corners, no remaining features to select (x-ordinary dealt with):
|
||||
if (compFaceVTag._rule == Sdc::Crease::RULE_SMOOTH) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Semi-sharp features -- select all immediately or test the single-crease case:
|
||||
if (compFaceVTag._semiSharp || compFaceVTag._semiSharpEdges) {
|
||||
if (featureMask.selectSemiSharpSingle && featureMask.selectSemiSharpNonSingle) {
|
||||
return true;
|
||||
} else if (level.isSingleCreasePatch(face)) {
|
||||
return featureMask.selectSemiSharpSingle;
|
||||
} else {
|
||||
return featureMask.selectSemiSharpNonSingle;
|
||||
}
|
||||
}
|
||||
|
||||
// Inf-sharp features (including boundaries) -- delegate to shared method:
|
||||
if (compFaceVTag._infSharp || compFaceVTag._infSharpEdges) {
|
||||
return doesInfSharpFaceHaveFeatures(compFaceVTag, vTags, fVerts.size(), featureMask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Analyzing the face-varying topology for selection is considerably simpler that
|
||||
// for the face and its vertices -- in part due to the fact that these faces lie on
|
||||
// face-varying boundaries, and also due to assumptions about prior inspection:
|
||||
//
|
||||
// - it is assumed the face topologgy does not match, so the face must lie on
|
||||
// a FVar boundary, i.e. inf-sharp
|
||||
//
|
||||
// - it is assumed the face vertices were already inspected, so cases such as
|
||||
// semi-sharp or smooth interior x-ordinary features have already triggered
|
||||
// selection
|
||||
//
|
||||
// That leaves the inspection of inf-sharp features, for the tags from the face
|
||||
// varying channel -- code that is shared with the main face.
|
||||
//
|
||||
bool
|
||||
doesFaceHaveDistinctFaceVaryingFeatures(Vtr::internal::Level const& level, Index face,
|
||||
internal::FeatureMask const & featureMask, int fvarChannel) {
|
||||
|
||||
using Vtr::internal::Level;
|
||||
|
||||
ConstIndexArray fVerts = level.getFaceVertices(face);
|
||||
|
||||
assert(!level.doesFaceFVarTopologyMatch(face, fvarChannel));
|
||||
|
||||
// We can't use the composite VTag for the face here as it only includes the FVar
|
||||
// values specific to this face. We need to account for all FVar values around
|
||||
// each corner of the face -- including those in potentially completely disjoint
|
||||
// sets -- to ensure that adjacent faces remain compatibly refined (i.e. differ
|
||||
// by only one level), so we use the composite tags for the corner vertices:
|
||||
//
|
||||
Level::VTag vTags[4];
|
||||
|
||||
for (int i = 0; i < fVerts.size(); ++i) {
|
||||
vTags[i] = level.getVertexCompositeFVarVTag(fVerts[i], fvarChannel);
|
||||
}
|
||||
Level::VTag compVTag = Level::VTag::BitwiseOr(vTags, fVerts.size());
|
||||
|
||||
// Select non-manifold features if specified, otherwise treat as inf-sharp:
|
||||
if (compVTag._nonManifold && featureMask.selectNonManifold) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Any remaining locally extra-ordinary face-varying boundaries warrant selection:
|
||||
if (compVTag._xordinary && featureMask.selectXOrdinaryInterior) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Given faces with differing FVar topology are on boundaries, defer to inf-sharp:
|
||||
return doesInfSharpFaceHaveFeatures(compVTag, vTags, fVerts.size(), featureMask);
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
//
|
||||
// Method for selecting components for sparse refinement based on the feature-adaptive needs
|
||||
// of patch generation.
|
||||
//
|
||||
// It assumes we have a freshly initialized SparseSelector (i.e. nothing already selected)
|
||||
// and will select all relevant topological features for inclusion in the subsequent sparse
|
||||
// refinement.
|
||||
//
|
||||
void
|
||||
TopologyRefiner::selectFeatureAdaptiveComponents(Vtr::internal::SparseSelector& selector,
|
||||
internal::FeatureMask const & featureMask,
|
||||
ConstIndexArray facesToRefine) {
|
||||
|
||||
//
|
||||
// Inspect each face and the properties tagged at all of its corners:
|
||||
//
|
||||
Vtr::internal::Level const& level = selector.getRefinement().parent();
|
||||
|
||||
int numFacesToRefine = facesToRefine.size() ? facesToRefine.size() : level.getNumFaces();
|
||||
|
||||
int numFVarChannels = featureMask.selectFVarFeatures ? level.getNumFVarChannels() : 0;
|
||||
|
||||
for (int fIndex = 0; fIndex < numFacesToRefine; ++fIndex) {
|
||||
|
||||
Vtr::Index face = facesToRefine.size() ? facesToRefine[fIndex] : (Index) fIndex;
|
||||
|
||||
if (HasHoles() && level.isFaceHole(face)) continue;
|
||||
|
||||
//
|
||||
// Test if the face has any of the specified features present. If not, and FVar
|
||||
// channels are to be considered, look for features in the FVar channels:
|
||||
//
|
||||
bool selectFace = doesFaceHaveFeatures(level, face, featureMask, _regFaceSize);
|
||||
|
||||
if (!selectFace && featureMask.selectFVarFeatures) {
|
||||
for (int channel = 0; !selectFace && (channel < numFVarChannels); ++channel) {
|
||||
|
||||
// Only test the face for this channel if the topology does not match:
|
||||
if (!level.doesFaceFVarTopologyMatch(face, channel)) {
|
||||
selectFace = doesFaceHaveDistinctFaceVaryingFeatures(
|
||||
level, face, featureMask, channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selectFace) {
|
||||
selector.selectFace(face);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TopologyRefiner::selectLinearIrregularFaces(Vtr::internal::SparseSelector& selector,
|
||||
ConstIndexArray facesToRefine) {
|
||||
|
||||
//
|
||||
// Inspect each face and select only irregular faces:
|
||||
//
|
||||
Vtr::internal::Level const& level = selector.getRefinement().parent();
|
||||
|
||||
int numFacesToRefine = facesToRefine.size() ? facesToRefine.size() : level.getNumFaces();
|
||||
|
||||
for (int fIndex = 0; fIndex < numFacesToRefine; ++fIndex) {
|
||||
|
||||
Vtr::Index face = facesToRefine.size() ? facesToRefine[fIndex] : (Index) fIndex;
|
||||
|
||||
if (HasHoles() && level.isFaceHole(face)) continue;
|
||||
|
||||
if (level.getFaceVertices(face).size() != _regFaceSize) {
|
||||
selector.selectFace(face);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
298
src/osd/opensubdiv/far/topologyRefiner.h
Normal file
298
src/osd/opensubdiv/far/topologyRefiner.h
Normal file
@@ -0,0 +1,298 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_FAR_TOPOLOGY_REFINER_H
|
||||
#define OPENSUBDIV3_FAR_TOPOLOGY_REFINER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../sdc/types.h"
|
||||
#include "../sdc/options.h"
|
||||
#include "../far/types.h"
|
||||
#include "../far/topologyLevel.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr { namespace internal { class SparseSelector; } }
|
||||
namespace Far { namespace internal { class FeatureMask; } }
|
||||
|
||||
namespace Far {
|
||||
|
||||
template <typename REAL> class PrimvarRefinerReal;
|
||||
template <class MESH> class TopologyRefinerFactory;
|
||||
|
||||
///
|
||||
/// \brief Stores topology data for a specified set of refinement options.
|
||||
///
|
||||
class TopologyRefiner {
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Constructor
|
||||
TopologyRefiner(Sdc::SchemeType type, Sdc::Options options = Sdc::Options());
|
||||
|
||||
/// \brief Destructor
|
||||
~TopologyRefiner();
|
||||
|
||||
/// \brief Returns the subdivision scheme
|
||||
Sdc::SchemeType GetSchemeType() const { return _subdivType; }
|
||||
|
||||
/// \brief Returns the subdivision options
|
||||
Sdc::Options GetSchemeOptions() const { return _subdivOptions; }
|
||||
|
||||
/// \brief Returns true if uniform refinement has been applied
|
||||
bool IsUniform() const { return _isUniform; }
|
||||
|
||||
/// \brief Returns the number of refinement levels
|
||||
int GetNumLevels() const { return (int)_farLevels.size(); }
|
||||
|
||||
/// \brief Returns the highest level of refinement
|
||||
int GetMaxLevel() const { return _maxLevel; }
|
||||
|
||||
/// \brief Returns the maximum vertex valence in all levels
|
||||
int GetMaxValence() const { return _maxValence; }
|
||||
|
||||
/// \brief Returns true if faces have been tagged as holes
|
||||
bool HasHoles() const { return _hasHoles; }
|
||||
|
||||
/// \brief Returns the total number of vertices in all levels
|
||||
int GetNumVerticesTotal() const { return _totalVertices; }
|
||||
|
||||
/// \brief Returns the total number of edges in all levels
|
||||
int GetNumEdgesTotal() const { return _totalEdges; }
|
||||
|
||||
/// \brief Returns the total number of edges in all levels
|
||||
int GetNumFacesTotal() const { return _totalFaces; }
|
||||
|
||||
/// \brief Returns the total number of face vertices in all levels
|
||||
int GetNumFaceVerticesTotal() const { return _totalFaceVertices; }
|
||||
|
||||
/// \brief Returns a handle to access data specific to a particular level
|
||||
TopologyLevel const & GetLevel(int level) const { return _farLevels[level]; }
|
||||
|
||||
//@{
|
||||
/// @name High-level refinement and related methods
|
||||
///
|
||||
|
||||
//
|
||||
// Uniform refinement
|
||||
//
|
||||
|
||||
/// \brief Uniform refinement options
|
||||
///
|
||||
/// Options for uniform refinement, including the number of levels, vertex
|
||||
/// ordering and generation of topology information.
|
||||
///
|
||||
/// Note the impact of the option to generate fullTopologyInLastLevel. Given
|
||||
/// subsequent levels of uniform refinement typically reguire 4x the data
|
||||
/// of the previous level, only the minimum amount of data is generated in the
|
||||
/// last level by default, i.e. a vertex and face-vertex list. If requiring
|
||||
/// topology traversal of the last level, e.g. inspecting edges or incident
|
||||
/// faces of vertices, the option to generate full topology in the last
|
||||
/// level should be enabled.
|
||||
///
|
||||
struct UniformOptions {
|
||||
|
||||
UniformOptions(int level) :
|
||||
refinementLevel(level),
|
||||
orderVerticesFromFacesFirst(false),
|
||||
fullTopologyInLastLevel(false) { }
|
||||
|
||||
unsigned int refinementLevel:4, ///< Number of refinement iterations
|
||||
orderVerticesFromFacesFirst:1, ///< Order child vertices from faces first
|
||||
///< instead of child vertices of vertices
|
||||
fullTopologyInLastLevel:1; ///< Skip topological relationships in the last
|
||||
///< level of refinement that are not needed for
|
||||
///< interpolation (keep false if using limit).
|
||||
};
|
||||
|
||||
/// \brief Refine the topology uniformly
|
||||
///
|
||||
/// This method applies uniform refinement to the level specified in the
|
||||
/// given UniformOptions.
|
||||
///
|
||||
/// Note the impact of the UniformOption to generate fullTopologyInLastLevel
|
||||
/// and be sure it is assigned to satisfy the needs of the resulting refinement.
|
||||
///
|
||||
/// @param options Options controlling uniform refinement
|
||||
///
|
||||
void RefineUniform(UniformOptions options);
|
||||
|
||||
/// \brief Returns the options specified on refinement
|
||||
UniformOptions GetUniformOptions() const { return _uniformOptions; }
|
||||
|
||||
//
|
||||
// Adaptive refinement
|
||||
//
|
||||
|
||||
/// \brief Adaptive refinement options
|
||||
struct AdaptiveOptions {
|
||||
|
||||
AdaptiveOptions(int level) :
|
||||
isolationLevel(level),
|
||||
secondaryLevel(15),
|
||||
useSingleCreasePatch(false),
|
||||
useInfSharpPatch(false),
|
||||
considerFVarChannels(false),
|
||||
orderVerticesFromFacesFirst(false) { }
|
||||
|
||||
unsigned int isolationLevel:4; ///< Number of iterations applied to isolate
|
||||
///< extraordinary vertices and creases
|
||||
unsigned int secondaryLevel:4; ///< Shallower level to stop isolation of
|
||||
///< smooth irregular features
|
||||
unsigned int useSingleCreasePatch:1; ///< Use 'single-crease' patch and stop
|
||||
///< isolation where applicable
|
||||
unsigned int useInfSharpPatch:1; ///< Use infinitely sharp patches and stop
|
||||
///< isolation where applicable
|
||||
unsigned int considerFVarChannels:1; ///< Inspect face-varying channels and
|
||||
///< isolate when irregular features present
|
||||
unsigned int orderVerticesFromFacesFirst:1; ///< Order child vertices from faces first
|
||||
///< instead of child vertices of vertices
|
||||
};
|
||||
|
||||
/// \brief Feature Adaptive topology refinement
|
||||
///
|
||||
/// @param options Options controlling adaptive refinement
|
||||
///
|
||||
/// @param selectedFaces Limit adaptive refinement to the specified faces
|
||||
///
|
||||
void RefineAdaptive(AdaptiveOptions options,
|
||||
ConstIndexArray selectedFaces = ConstIndexArray());
|
||||
|
||||
/// \brief Returns the options specified on refinement
|
||||
AdaptiveOptions GetAdaptiveOptions() const { return _adaptiveOptions; }
|
||||
|
||||
/// \brief Unrefine the topology, keeping only the base level.
|
||||
void Unrefine();
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Number and properties of face-varying channels:
|
||||
///
|
||||
|
||||
/// \brief Returns the number of face-varying channels in the tables
|
||||
int GetNumFVarChannels() const;
|
||||
|
||||
/// \brief Returns the face-varying interpolation rule set for a given channel
|
||||
Sdc::Options::FVarLinearInterpolation GetFVarLinearInterpolation(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the total number of face-varying values in all levels
|
||||
int GetNumFVarValuesTotal(int channel = 0) const;
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
|
||||
//
|
||||
// Lower level protected methods intended strictly for internal use:
|
||||
//
|
||||
template <class MESH>
|
||||
friend class TopologyRefinerFactory;
|
||||
friend class TopologyRefinerFactoryBase;
|
||||
friend class PatchTableBuilder;
|
||||
friend class PatchBuilder;
|
||||
friend class PtexIndices;
|
||||
template <typename REAL>
|
||||
friend class PrimvarRefinerReal;
|
||||
|
||||
// Copy constructor exposed via the factory class:
|
||||
TopologyRefiner(TopologyRefiner const & source);
|
||||
|
||||
Vtr::internal::Level & getLevel(int l) { return *_levels[l]; }
|
||||
Vtr::internal::Level const & getLevel(int l) const { return *_levels[l]; }
|
||||
|
||||
Vtr::internal::Refinement & getRefinement(int l) { return *_refinements[l]; }
|
||||
Vtr::internal::Refinement const & getRefinement(int l) const { return *_refinements[l]; }
|
||||
|
||||
private:
|
||||
// Not default constructible or copyable:
|
||||
TopologyRefiner() : _uniformOptions(0), _adaptiveOptions(0) { }
|
||||
TopologyRefiner & operator=(TopologyRefiner const &) { return *this; }
|
||||
|
||||
void selectFeatureAdaptiveComponents(Vtr::internal::SparseSelector& selector,
|
||||
internal::FeatureMask const & mask,
|
||||
ConstIndexArray selectedFaces);
|
||||
void selectLinearIrregularFaces(Vtr::internal::SparseSelector& selector,
|
||||
ConstIndexArray selectedFaces);
|
||||
|
||||
void initializeInventory();
|
||||
void updateInventory(Vtr::internal::Level const & newLevel);
|
||||
|
||||
void appendLevel(Vtr::internal::Level & newLevel);
|
||||
void appendRefinement(Vtr::internal::Refinement & newRefinement);
|
||||
void assembleFarLevels();
|
||||
|
||||
private:
|
||||
|
||||
Sdc::SchemeType _subdivType;
|
||||
Sdc::Options _subdivOptions;
|
||||
|
||||
unsigned int _isUniform : 1;
|
||||
unsigned int _hasHoles : 1;
|
||||
unsigned int _hasIrregFaces : 1;
|
||||
unsigned int _regFaceSize : 3;
|
||||
unsigned int _maxLevel : 4;
|
||||
|
||||
// Options assigned on refinement:
|
||||
UniformOptions _uniformOptions;
|
||||
AdaptiveOptions _adaptiveOptions;
|
||||
|
||||
// Cumulative properties of all levels:
|
||||
int _totalVertices;
|
||||
int _totalEdges;
|
||||
int _totalFaces;
|
||||
int _totalFaceVertices;
|
||||
int _maxValence;
|
||||
|
||||
// Note the base level may be shared with another instance
|
||||
bool _baseLevelOwned;
|
||||
|
||||
std::vector<Vtr::internal::Level *> _levels;
|
||||
std::vector<Vtr::internal::Refinement *> _refinements;
|
||||
|
||||
std::vector<TopologyLevel> _farLevels;
|
||||
};
|
||||
|
||||
|
||||
inline int
|
||||
TopologyRefiner::GetNumFVarChannels() const {
|
||||
|
||||
return _levels[0]->getNumFVarChannels();
|
||||
}
|
||||
inline Sdc::Options::FVarLinearInterpolation
|
||||
TopologyRefiner::GetFVarLinearInterpolation(int channel) const {
|
||||
|
||||
return _levels[0]->getFVarOptions(channel).GetFVarLinearInterpolation();
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_TOPOLOGY_REFINER_H */
|
||||
444
src/osd/opensubdiv/far/topologyRefinerFactory.cpp
Normal file
444
src/osd/opensubdiv/far/topologyRefinerFactory.cpp
Normal file
@@ -0,0 +1,444 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
#include "../far/topologyRefinerFactory.h"
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../sdc/types.h"
|
||||
#include "../vtr/level.h"
|
||||
|
||||
#include <cstdio>
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// Methods for the Factory base class -- general enough to warrant including
|
||||
// in the base class rather than the subclass template (and so replicated for
|
||||
// each usage)
|
||||
//
|
||||
//
|
||||
bool
|
||||
TopologyRefinerFactoryBase::prepareComponentTopologySizing(
|
||||
TopologyRefiner& refiner) {
|
||||
|
||||
Vtr::internal::Level& baseLevel = refiner.getLevel(0);
|
||||
|
||||
//
|
||||
// At minimum we require face-vertices (the total count of which can be
|
||||
// determined from the offsets accumulated during sizing pass) and we
|
||||
// need to resize members related to them to be populated during
|
||||
// assignment:
|
||||
//
|
||||
int vCount = baseLevel.getNumVertices();
|
||||
int fCount = baseLevel.getNumFaces();
|
||||
|
||||
if (vCount == 0) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"mesh contains no vertices.");
|
||||
return false;
|
||||
}
|
||||
if (fCount == 0) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"meshes without faces not yet supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure no face was defined that would lead to a valence overflow --
|
||||
// the max valence has been initialized with the maximum number of
|
||||
// face-vertices:
|
||||
if (baseLevel.getMaxValence() > Vtr::VALENCE_LIMIT) {
|
||||
char msg[1024];
|
||||
snprintf(msg, 1024,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"face with %d vertices > %d max.",
|
||||
baseLevel.getMaxValence(), Vtr::VALENCE_LIMIT);
|
||||
Error(FAR_RUNTIME_ERROR, msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
int fVertCount = baseLevel.getNumFaceVertices(fCount - 1) +
|
||||
baseLevel.getOffsetOfFaceVertices(fCount - 1);
|
||||
|
||||
if (fVertCount == 0) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"mesh contains no face-vertices.");
|
||||
return false;
|
||||
}
|
||||
if ((refiner.GetSchemeType() == Sdc::SCHEME_LOOP) &&
|
||||
(fVertCount != (3 * fCount))) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"non-triangular faces not supported by Loop scheme.");
|
||||
return false;
|
||||
}
|
||||
baseLevel.resizeFaceVertices(fVertCount);
|
||||
|
||||
//
|
||||
// If edges were sized, all other topological relations must be sized
|
||||
// with it, in which case we allocate those members to be populated.
|
||||
// Otherwise, sizing of the other topology members is deferred until
|
||||
// the face-vertices are assigned and the resulting relationships
|
||||
// determined:
|
||||
//
|
||||
int eCount = baseLevel.getNumEdges();
|
||||
|
||||
if (eCount > 0) {
|
||||
baseLevel.resizeFaceEdges(baseLevel.getNumFaceVerticesTotal());
|
||||
baseLevel.resizeEdgeVertices();
|
||||
baseLevel.resizeEdgeFaces( baseLevel.getNumEdgeFaces(eCount-1) +
|
||||
baseLevel.getOffsetOfEdgeFaces(eCount-1));
|
||||
baseLevel.resizeVertexFaces(baseLevel.getNumVertexFaces(vCount-1) +
|
||||
baseLevel.getOffsetOfVertexFaces(vCount-1));
|
||||
baseLevel.resizeVertexEdges(baseLevel.getNumVertexEdges(vCount-1) +
|
||||
baseLevel.getOffsetOfVertexEdges(vCount-1));
|
||||
|
||||
assert(baseLevel.getNumFaceEdgesTotal() > 0);
|
||||
assert(baseLevel.getNumEdgeVerticesTotal() > 0);
|
||||
assert(baseLevel.getNumEdgeFacesTotal() > 0);
|
||||
assert(baseLevel.getNumVertexFacesTotal() > 0);
|
||||
assert(baseLevel.getNumVertexEdgesTotal() > 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TopologyRefinerFactoryBase::prepareComponentTopologyAssignment(
|
||||
TopologyRefiner& refiner, bool fullValidation,
|
||||
TopologyCallback callback, void const * callbackData) {
|
||||
|
||||
Vtr::internal::Level& baseLevel = refiner.getLevel(0);
|
||||
|
||||
bool completeMissingTopology = (baseLevel.getNumEdges() == 0);
|
||||
if (completeMissingTopology) {
|
||||
if (! baseLevel.completeTopologyFromFaceVertices()) {
|
||||
char msg[1024];
|
||||
snprintf(msg, 1024,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"vertex with valence %d > %d max.",
|
||||
baseLevel.getMaxValence(), Vtr::VALENCE_LIMIT);
|
||||
Error(FAR_RUNTIME_ERROR, msg);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (baseLevel.getMaxValence() == 0) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"maximum valence not assigned.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fullValidation) {
|
||||
if (! baseLevel.validateTopology(callback, callbackData)) {
|
||||
if (completeMissingTopology) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"invalid topology detected from partial specification.");
|
||||
} else {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"invalid topology detected as fully specified.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have a valid base level, initialize the Refiner's
|
||||
// component inventory:
|
||||
refiner.initializeInventory();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TopologyRefinerFactoryBase::prepareComponentTagsAndSharpness(
|
||||
TopologyRefiner& refiner) {
|
||||
|
||||
//
|
||||
// This method combines the initialization of internal component tags
|
||||
// with the sharpening of edges and vertices according to the given
|
||||
// boundary interpolation rule in the Options.
|
||||
// Since both involve traversing the edge and vertex lists and noting
|
||||
// the presence of boundaries -- best to do both at once...
|
||||
//
|
||||
Vtr::internal::Level& baseLevel = refiner.getLevel(0);
|
||||
|
||||
Sdc::Options options = refiner.GetSchemeOptions();
|
||||
Sdc::Crease creasing(options);
|
||||
|
||||
bool makeBoundaryFacesHoles =
|
||||
(options.GetVtxBoundaryInterpolation() ==
|
||||
Sdc::Options::VTX_BOUNDARY_NONE) &&
|
||||
(Sdc::SchemeTypeTraits::GetLocalNeighborhoodSize(
|
||||
refiner.GetSchemeType()) > 0);
|
||||
|
||||
bool sharpenCornerVerts =
|
||||
(options.GetVtxBoundaryInterpolation() ==
|
||||
Sdc::Options::VTX_BOUNDARY_EDGE_AND_CORNER);
|
||||
|
||||
bool sharpenNonManFeatures = true;
|
||||
|
||||
//
|
||||
// Before initializing edge and vertex tags, tag any qualifying boundary
|
||||
// faces as holes before the sharpness of incident vertices and edges is
|
||||
// affected by boundary interpolation rules.
|
||||
//
|
||||
// Faces will be excluded (tagged as holes) if they contain a vertex on a
|
||||
// boundary that did not have all of its incident boundary edges sharpened
|
||||
// (not just the boundary edges within the face), so inspect the vertices
|
||||
// and tag their incident faces when necessary:
|
||||
//
|
||||
if (makeBoundaryFacesHoles) {
|
||||
for (Vtr::Index vIndex = 0; vIndex < baseLevel.getNumVertices();
|
||||
++vIndex) {
|
||||
Vtr::ConstIndexArray vEdges = baseLevel.getVertexEdges(vIndex);
|
||||
Vtr::ConstIndexArray vFaces = baseLevel.getVertexFaces(vIndex);
|
||||
|
||||
// Ignore manifold interior vertices:
|
||||
if ((vEdges.size() == vFaces.size()) &&
|
||||
!baseLevel.getVertexTag(vIndex)._nonManifold) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool excludeFaces = false;
|
||||
for (int i = 0; !excludeFaces && (i < vEdges.size()); ++i) {
|
||||
excludeFaces = (baseLevel.getNumEdgeFaces(vEdges[i]) == 1) &&
|
||||
!Sdc::Crease::IsInfinite(
|
||||
baseLevel.getEdgeSharpness(vEdges[i]));
|
||||
}
|
||||
if (excludeFaces) {
|
||||
for (int i = 0; i < vFaces.size(); ++i) {
|
||||
baseLevel.getFaceTag(vFaces[i])._hole = true;
|
||||
}
|
||||
// Need to tag Refiner (the Level does not keep track of this)
|
||||
refiner._hasHoles = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Process the Edge tags first, as Vertex tags (notably the Rule) are
|
||||
// dependent on properties of their incident edges.
|
||||
//
|
||||
for (Vtr::Index eIndex = 0; eIndex < baseLevel.getNumEdges(); ++eIndex) {
|
||||
Vtr::internal::Level::ETag& eTag = baseLevel.getEdgeTag(eIndex);
|
||||
|
||||
float& eSharpness = baseLevel.getEdgeSharpness(eIndex);
|
||||
|
||||
eTag._boundary = (baseLevel.getNumEdgeFaces(eIndex) < 2);
|
||||
if (eTag._boundary || (eTag._nonManifold && sharpenNonManFeatures)) {
|
||||
eSharpness = Sdc::Crease::SHARPNESS_INFINITE;
|
||||
}
|
||||
eTag._infSharp = Sdc::Crease::IsInfinite(eSharpness);
|
||||
eTag._semiSharp = Sdc::Crease::IsSharp(eSharpness) && !eTag._infSharp;
|
||||
}
|
||||
|
||||
//
|
||||
// Process the Vertex tags now -- for some tags (semi-sharp and its rule)
|
||||
// we need to inspect all incident edges:
|
||||
//
|
||||
int schemeRegularInteriorValence =
|
||||
Sdc::SchemeTypeTraits::GetRegularVertexValence(refiner.GetSchemeType());
|
||||
int schemeRegularBoundaryValence = schemeRegularInteriorValence / 2;
|
||||
|
||||
for (Vtr::Index vIndex = 0; vIndex < baseLevel.getNumVertices(); ++vIndex) {
|
||||
Vtr::internal::Level::VTag& vTag = baseLevel.getVertexTag(vIndex);
|
||||
|
||||
float& vSharpness = baseLevel.getVertexSharpness(vIndex);
|
||||
|
||||
Vtr::ConstIndexArray vEdges = baseLevel.getVertexEdges(vIndex);
|
||||
Vtr::ConstIndexArray vFaces = baseLevel.getVertexFaces(vIndex);
|
||||
|
||||
//
|
||||
// Take inventory of properties of incident edges that affect this
|
||||
// vertex:
|
||||
//
|
||||
int boundaryEdgeCount = 0;
|
||||
int infSharpEdgeCount = 0;
|
||||
int semiSharpEdgeCount = 0;
|
||||
int nonManifoldEdgeCount = 0;
|
||||
for (int i = 0; i < vEdges.size(); ++i) {
|
||||
Vtr::internal::Level::ETag const& eTag =
|
||||
baseLevel.getEdgeTag(vEdges[i]);
|
||||
|
||||
boundaryEdgeCount += eTag._boundary;
|
||||
infSharpEdgeCount += eTag._infSharp;
|
||||
semiSharpEdgeCount += eTag._semiSharp;
|
||||
nonManifoldEdgeCount += eTag._nonManifold;
|
||||
}
|
||||
int sharpEdgeCount = infSharpEdgeCount + semiSharpEdgeCount;
|
||||
|
||||
//
|
||||
// Sharpen the vertex before using it in conjunction with incident edge
|
||||
// properties to determine the semi-sharp tag and rule:
|
||||
//
|
||||
bool isTopologicalCorner = (vFaces.size() == 1) && (vEdges.size() == 2);
|
||||
bool isSharpenedCorner = isTopologicalCorner && sharpenCornerVerts;
|
||||
if (isSharpenedCorner) {
|
||||
vSharpness = Sdc::Crease::SHARPNESS_INFINITE;
|
||||
} else if (vTag._nonManifold && sharpenNonManFeatures) {
|
||||
//
|
||||
// We avoid sharpening non-manifold vertices when they occur on
|
||||
// interior non-manifold creases, i.e. a pair of opposing non-
|
||||
// manifold edges with more than two incident faces. In these
|
||||
// cases there are more incident faces than edges (1 more for
|
||||
// each additional "fin") and no boundaries.
|
||||
//
|
||||
if (! ((nonManifoldEdgeCount == 2) && (boundaryEdgeCount == 0) &&
|
||||
(vFaces.size() > vEdges.size()))) {
|
||||
vSharpness = Sdc::Crease::SHARPNESS_INFINITE;
|
||||
}
|
||||
}
|
||||
|
||||
vTag._infSharp = Sdc::Crease::IsInfinite(vSharpness);
|
||||
vTag._semiSharp = Sdc::Crease::IsSemiSharp(vSharpness);
|
||||
vTag._semiSharpEdges = (semiSharpEdgeCount > 0);
|
||||
|
||||
vTag._rule = (Vtr::internal::Level::VTag::VTagSize)
|
||||
creasing.DetermineVertexVertexRule(vSharpness, sharpEdgeCount);
|
||||
|
||||
//
|
||||
// Assign topological tags -- note that the "xordinary" tag is not
|
||||
// assigned if non-manifold:
|
||||
//
|
||||
vTag._boundary = (boundaryEdgeCount > 0);
|
||||
vTag._corner = isTopologicalCorner && vTag._infSharp;
|
||||
if (vTag._nonManifold) {
|
||||
vTag._xordinary = false;
|
||||
} else if (vTag._corner) {
|
||||
vTag._xordinary = false;
|
||||
} else if (vTag._boundary) {
|
||||
vTag._xordinary = (vFaces.size() != schemeRegularBoundaryValence);
|
||||
} else {
|
||||
vTag._xordinary = (vFaces.size() != schemeRegularInteriorValence);
|
||||
}
|
||||
vTag._incomplete = 0;
|
||||
|
||||
//
|
||||
// Assign tags specific to inf-sharp features to identify regular
|
||||
// topologies partitioned by inf-sharp creases -- must be no semi-
|
||||
// harp features here (and manifold for now):
|
||||
//
|
||||
vTag._infSharpEdges = (infSharpEdgeCount > 0);
|
||||
vTag._infSharpCrease = false;
|
||||
vTag._infIrregular = vTag._infSharp || vTag._infSharpEdges;
|
||||
|
||||
if (vTag._infSharpEdges) {
|
||||
// Ignore semi-sharp vertex sharpness when computing the
|
||||
// inf-sharp Rule:
|
||||
Sdc::Crease::Rule infRule = creasing.DetermineVertexVertexRule(
|
||||
(vTag._infSharp ? vSharpness : 0.0f), infSharpEdgeCount);
|
||||
|
||||
if (infRule == Sdc::Crease::RULE_CREASE) {
|
||||
vTag._infSharpCrease = true;
|
||||
|
||||
// A "regular" inf-crease can only occur along a manifold
|
||||
// regular boundary or by bisecting a manifold interior
|
||||
// region (it is also possible along non-manifold vertices
|
||||
// in some cases, but that requires much more effort to
|
||||
// detect -- perhaps later...)
|
||||
//
|
||||
if (!vTag._xordinary && !vTag._nonManifold) {
|
||||
if (vTag._boundary) {
|
||||
vTag._infIrregular = false;
|
||||
} else {
|
||||
assert((schemeRegularInteriorValence == 4) ||
|
||||
(schemeRegularInteriorValence == 6));
|
||||
|
||||
if (schemeRegularInteriorValence == 4) {
|
||||
vTag._infIrregular =
|
||||
(baseLevel.getEdgeTag(vEdges[0])._infSharp !=
|
||||
baseLevel.getEdgeTag(vEdges[2])._infSharp);
|
||||
} else if (schemeRegularInteriorValence == 6) {
|
||||
vTag._infIrregular =
|
||||
(baseLevel.getEdgeTag(vEdges[0])._infSharp !=
|
||||
baseLevel.getEdgeTag(vEdges[3])._infSharp) ||
|
||||
(baseLevel.getEdgeTag(vEdges[1])._infSharp !=
|
||||
baseLevel.getEdgeTag(vEdges[4])._infSharp);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (infRule == Sdc::Crease::RULE_CORNER) {
|
||||
// A regular set of inf-corners occurs when all edges are
|
||||
// sharp and not a smooth corner:
|
||||
//
|
||||
if ((infSharpEdgeCount == vEdges.size() &&
|
||||
((vEdges.size() > 2) || vTag._infSharp))) {
|
||||
vTag._infIrregular = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// If any irregular faces are present, mark whether or not a vertex
|
||||
// is incident any irregular face:
|
||||
//
|
||||
if (refiner._hasIrregFaces) {
|
||||
int regSize = refiner._regFaceSize;
|
||||
for (int i = 0; i < vFaces.size(); ++i) {
|
||||
if (baseLevel.getFaceVertices(vFaces[i]).size() != regSize) {
|
||||
vTag._incidIrregFace = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TopologyRefinerFactoryBase::prepareFaceVaryingChannels(
|
||||
TopologyRefiner& refiner) {
|
||||
|
||||
Vtr::internal::Level& baseLevel = refiner.getLevel(0);
|
||||
|
||||
int regVertexValence =
|
||||
Sdc::SchemeTypeTraits::GetRegularVertexValence(refiner.GetSchemeType());
|
||||
int regBoundaryValence = regVertexValence / 2;
|
||||
|
||||
for (int channel=0; channel<refiner.GetNumFVarChannels(); ++channel) {
|
||||
if (baseLevel.getNumFVarValues(channel) == 0) {
|
||||
char msg[1024];
|
||||
snprintf(msg, 1024,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"face-varying channel %d has no values.", channel);
|
||||
Error(FAR_RUNTIME_ERROR, msg);
|
||||
return false;
|
||||
}
|
||||
baseLevel.completeFVarChannelTopology(channel, regBoundaryValence);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
710
src/osd/opensubdiv/far/topologyRefinerFactory.h
Normal file
710
src/osd/opensubdiv/far/topologyRefinerFactory.h
Normal file
@@ -0,0 +1,710 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_FAR_TOPOLOGY_REFINER_FACTORY_H
|
||||
#define OPENSUBDIV3_FAR_TOPOLOGY_REFINER_FACTORY_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../far/error.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
///\brief Private base class of Factories for constructing TopologyRefiners
|
||||
///
|
||||
/// TopologyRefinerFactoryBase is the base class for subclasses that are intended to
|
||||
/// construct TopologyRefiners directly from meshes in their native representations.
|
||||
/// The subclasses are parameterized by the mesh type \<class MESH\> and are expected
|
||||
/// to inherit the details related to assembly and validation provided here that are
|
||||
/// independent of the subclass' mesh type.
|
||||
//
|
||||
class TopologyRefinerFactoryBase {
|
||||
protected:
|
||||
|
||||
//
|
||||
// Protected methods invoked by the subclass template to verify and process each
|
||||
// stage of construction implemented by the subclass:
|
||||
//
|
||||
typedef Vtr::internal::Level::ValidationCallback TopologyCallback;
|
||||
|
||||
static bool prepareComponentTopologySizing(TopologyRefiner& refiner);
|
||||
static bool prepareComponentTopologyAssignment(TopologyRefiner& refiner, bool fullValidation,
|
||||
TopologyCallback callback, void const * callbackData);
|
||||
static bool prepareComponentTagsAndSharpness(TopologyRefiner& refiner);
|
||||
static bool prepareFaceVaryingChannels(TopologyRefiner& refiner);
|
||||
};
|
||||
|
||||
|
||||
///\brief Factory for constructing TopologyRefiners from specific mesh classes.
|
||||
///
|
||||
/// TopologyRefinerFactory<MESH> is the factory class template to convert an instance of
|
||||
/// TopologyRefiner from an arbitrary mesh class. While a class template, the implementation
|
||||
/// is not (cannot) be complete, so specialization of a few methods is required (it is a
|
||||
/// stateless factory, so no instance and only static methods).
|
||||
///
|
||||
/// This template provides both the interface and high level assembly for the construction
|
||||
/// of the TopologyRefiner instance. The high level construction executes a specific set
|
||||
/// of operations to convert the client's MESH into TopologyRefiner. This set of operations
|
||||
/// combines methods independent of MESH from the base class with those specialized here for
|
||||
/// class MESH.
|
||||
///
|
||||
template <class MESH>
|
||||
class TopologyRefinerFactory : public TopologyRefinerFactoryBase {
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Options related to the construction of each TopologyRefiner.
|
||||
///
|
||||
struct Options {
|
||||
|
||||
Options(Sdc::SchemeType sdcType = Sdc::SCHEME_CATMARK, Sdc::Options sdcOptions = Sdc::Options()) :
|
||||
schemeType(sdcType),
|
||||
schemeOptions(sdcOptions),
|
||||
validateFullTopology(false) { }
|
||||
|
||||
Sdc::SchemeType schemeType; ///< The subdivision scheme type identifier
|
||||
Sdc::Options schemeOptions; ///< The full set of options for the scheme,
|
||||
///< e.g. boundary interpolation rules...
|
||||
unsigned int validateFullTopology : 1; ///< Apply more extensive validation of
|
||||
///< the constructed topology -- intended
|
||||
///< for debugging.
|
||||
};
|
||||
|
||||
/// \brief Instantiates a TopologyRefiner from client-provided topological
|
||||
/// representation.
|
||||
///
|
||||
/// If only the face-vertices topological relationships are specified
|
||||
/// with this factory, edge relationships have to be inferred, which
|
||||
/// requires additional processing. If the client topological rep can
|
||||
/// provide this information, it is highly recommended to do so.
|
||||
///
|
||||
/// @param mesh Client's topological representation (or a converter)
|
||||
//
|
||||
/// @param options Options controlling the creation of the TopologyRefiner
|
||||
///
|
||||
/// @return A new instance of TopologyRefiner or 0 for failure
|
||||
///
|
||||
static TopologyRefiner* Create(MESH const& mesh, Options options = Options());
|
||||
|
||||
/// \brief Instantiates a TopologyRefiner from the base level of an
|
||||
/// existing instance.
|
||||
///
|
||||
/// This allows lightweight copies of the same topology to be refined
|
||||
/// differently for each new instance. As with other classes that refer
|
||||
/// to an existing TopologyRefiner, it must generally exist for the entire
|
||||
/// lifetime of the new instance. In this case, the base level of the
|
||||
/// original instance must be preserved.
|
||||
///
|
||||
/// @param baseLevel An existing TopologyRefiner to share base level.
|
||||
///
|
||||
/// @return A new instance of TopologyRefiner or 0 for failure
|
||||
///
|
||||
static TopologyRefiner* Create(TopologyRefiner const & baseLevel);
|
||||
|
||||
protected:
|
||||
typedef Vtr::internal::Level::TopologyError TopologyError;
|
||||
|
||||
//@{
|
||||
/// @name Methods to be provided to complete assembly of the TopologyRefiner
|
||||
///
|
||||
///
|
||||
/// These methods are to be specialized to implement all details specific to
|
||||
/// class MESH required to convert MESH data to TopologyRefiner. Note that
|
||||
/// some of these *must* be specialized in order to complete construction while
|
||||
/// some are optional.
|
||||
///
|
||||
/// There are two minimal construction requirements (to specify the size and
|
||||
/// content of all topology relations) and three optional (to specify feature
|
||||
/// tags, face-varying data, and runtime validation and error reporting).
|
||||
///
|
||||
/// See comments in the generic stubs, the factory for Far::TopologyDescriptor
|
||||
/// or the tutorials for more details on writing these.
|
||||
///
|
||||
|
||||
/// \brief Specify the number of vertices, faces, face-vertices, etc.
|
||||
static bool resizeComponentTopology(TopologyRefiner& newRefiner, MESH const& mesh);
|
||||
|
||||
/// \brief Specify the relationships between vertices, faces, etc. ie the
|
||||
/// face-vertices, vertex-faces, edge-vertices, etc.
|
||||
static bool assignComponentTopology(TopologyRefiner& newRefiner, MESH const& mesh);
|
||||
|
||||
/// \brief (Optional) Specify edge or vertex sharpness or face holes
|
||||
static bool assignComponentTags(TopologyRefiner& newRefiner, MESH const& mesh);
|
||||
|
||||
/// \brief (Optional) Specify face-varying data per face
|
||||
static bool assignFaceVaryingTopology(TopologyRefiner& newRefiner, MESH const& mesh);
|
||||
|
||||
/// \brief (Optional) Control run-time topology validation and error reporting
|
||||
static void reportInvalidTopology(TopologyError errCode, char const * msg, MESH const& mesh);
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
//@{
|
||||
/// @name Base level assembly methods to be used within resizeComponentTopology()
|
||||
///
|
||||
/// \brief These methods specify sizes of various quantities, e.g. the number of
|
||||
/// vertices, faces, face-vertices, etc. The number of the primary components
|
||||
/// (vertices, faces and edges) should be specified prior to anything else that
|
||||
/// references them (e.g. we need to know the number of faces before specifying
|
||||
/// the vertices for that face.
|
||||
///
|
||||
/// If a full boundary representation with all neighborhood information is not
|
||||
/// available, e.g. faces and vertices are available but not edges, only the
|
||||
/// face-vertices should be specified. The remaining topological relationships
|
||||
/// will be constructed later in the assembly (though at greater cost than if
|
||||
/// specified directly).
|
||||
///
|
||||
/// The sizes for topological relationships between individual components should be
|
||||
/// specified in order, i.e. the number of face-vertices for each successive face.
|
||||
///
|
||||
|
||||
/// \brief Specify the number of vertices to be accommodated
|
||||
static void setNumBaseVertices(TopologyRefiner & newRefiner, int count);
|
||||
|
||||
/// \brief Specify the number of faces to be accommodated
|
||||
static void setNumBaseFaces(TopologyRefiner & newRefiner, int count);
|
||||
|
||||
/// \brief Specify the number of edges to be accommodated
|
||||
static void setNumBaseEdges(TopologyRefiner & newRefiner, int count);
|
||||
|
||||
/// \brief Specify the number of vertices incident each face
|
||||
static void setNumBaseFaceVertices(TopologyRefiner & newRefiner, Index f, int count);
|
||||
|
||||
/// \brief Specify the number of faces incident each edge
|
||||
static void setNumBaseEdgeFaces(TopologyRefiner & newRefiner, Index e, int count);
|
||||
|
||||
/// \brief Specify the number of faces incident each vertex
|
||||
static void setNumBaseVertexFaces(TopologyRefiner & newRefiner, Index v, int count);
|
||||
|
||||
/// \brief Specify the number of edges incident each vertex
|
||||
static void setNumBaseVertexEdges(TopologyRefiner & newRefiner, Index v, int count);
|
||||
|
||||
static int getNumBaseVertices(TopologyRefiner const & newRefiner);
|
||||
static int getNumBaseFaces(TopologyRefiner const & newRefiner);
|
||||
static int getNumBaseEdges(TopologyRefiner const & newRefiner);
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Base level assembly methods to be used within assignComponentTopology()
|
||||
///
|
||||
/// \brief These methods populate relationships between components -- in much the
|
||||
/// same manner as they are inspected once the TopologyRefiner is completed.
|
||||
///
|
||||
/// An array of fixed size is returned from these methods and its entries are to be
|
||||
/// populated with the appropriate indices for its neighbors. At minimum, the
|
||||
/// vertices for each face must be specified. As noted previously, the remaining
|
||||
/// relationships will be constructed as needed.
|
||||
///
|
||||
/// The ordering of entries in these arrays is important -- they are expected to
|
||||
/// be ordered counter-clockwise for a right-hand orientation.
|
||||
///
|
||||
/// Non-manifold components must be explicitly tagged as such and they do not
|
||||
/// require the ordering expected of manifold components. Special consideration
|
||||
/// must also be given to certain non-manifold situations, e.g. the same edge
|
||||
/// cannot appear twice in a face, and a degenerate edge (same vertex at both
|
||||
/// ends) can only have one incident face. Such considerations are typically
|
||||
/// achievable by creating multiple instances of an edge. So while there will
|
||||
/// always be a one-to-one correspondence between vertices and faces, the same
|
||||
/// is not guaranteed of edges in certain non-manifold circumstances.
|
||||
///
|
||||
|
||||
/// \brief Assign the vertices incident each face
|
||||
static IndexArray getBaseFaceVertices(TopologyRefiner & newRefiner, Index f);
|
||||
|
||||
/// \brief Assign the edges incident each face
|
||||
static IndexArray getBaseFaceEdges(TopologyRefiner & newRefiner, Index f);
|
||||
|
||||
/// \brief Assign the vertices incident each edge
|
||||
static IndexArray getBaseEdgeVertices(TopologyRefiner & newRefiner, Index e);
|
||||
|
||||
/// \brief Assign the faces incident each edge
|
||||
static IndexArray getBaseEdgeFaces(TopologyRefiner & newRefiner, Index e);
|
||||
|
||||
/// \brief Assign the faces incident each vertex
|
||||
static IndexArray getBaseVertexFaces(TopologyRefiner & newRefiner, Index v);
|
||||
|
||||
/// \brief Assign the edges incident each vertex
|
||||
static IndexArray getBaseVertexEdges(TopologyRefiner & newRefiner, Index v);
|
||||
|
||||
/// \brief Assign the local indices of a vertex within each of its incident faces
|
||||
static LocalIndexArray getBaseVertexFaceLocalIndices(TopologyRefiner & newRefiner, Index v);
|
||||
/// \brief Assign the local indices of a vertex within each of its incident edges
|
||||
static LocalIndexArray getBaseVertexEdgeLocalIndices(TopologyRefiner & newRefiner, Index v);
|
||||
/// \brief Assign the local indices of an edge within each of its incident faces
|
||||
static LocalIndexArray getBaseEdgeFaceLocalIndices(TopologyRefiner & newRefiner, Index e);
|
||||
|
||||
/// \brief Determine all local indices by inspection (only for pure manifold meshes)
|
||||
static void populateBaseLocalIndices(TopologyRefiner & newRefiner);
|
||||
|
||||
/// \brief Tag an edge as non-manifold
|
||||
static void setBaseEdgeNonManifold(TopologyRefiner & newRefiner, Index e, bool b);
|
||||
|
||||
/// \brief Tag a vertex as non-manifold
|
||||
static void setBaseVertexNonManifold(TopologyRefiner & newRefiner, Index v, bool b);
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Base level assembly methods to be used within assignComponentTags()
|
||||
///
|
||||
/// These methods are used to assign edge or vertex sharpness, for tagging faces
|
||||
/// as holes, etc. Unlike topological assignment, only those components that
|
||||
/// possess a feature of interest need be explicitly assigned.
|
||||
///
|
||||
/// Since topological construction is largely complete by this point, a method is
|
||||
/// available to identify an edge for sharpness assignment given a pair of vertices.
|
||||
///
|
||||
|
||||
/// \brief Identify an edge to be assigned a sharpness value given a vertex pair
|
||||
static Index findBaseEdge(TopologyRefiner const & newRefiner, Index v0, Index v1);
|
||||
|
||||
/// \brief Assign a sharpness value to a given edge
|
||||
static void setBaseEdgeSharpness(TopologyRefiner & newRefiner, Index e, float sharpness);
|
||||
|
||||
/// \brief Assign a sharpness value to a given vertex
|
||||
static void setBaseVertexSharpness(TopologyRefiner & newRefiner, Index v, float sharpness);
|
||||
|
||||
/// \brief Tag a face as a hole
|
||||
static void setBaseFaceHole(TopologyRefiner & newRefiner, Index f, bool isHole);
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Base level assembly methods to be used within assignFaceVaryingTopology()
|
||||
///
|
||||
/// Face-varying data is assigned to faces in much the same way as face-vertex
|
||||
/// topology is assigned -- indices for face-varying values are assigned to the
|
||||
/// corners of each face just as indices for vertices were assigned.
|
||||
///
|
||||
/// Independent sets of face-varying data are stored in channels. The identifier
|
||||
/// of each channel (an integer) is expected whenever referring to face-varying
|
||||
/// data in any form.
|
||||
///
|
||||
|
||||
/// \brief Create a new face-varying channel with the given number of values
|
||||
static int createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues);
|
||||
|
||||
/// \brief Create a new face-varying channel with the given number of values and independent interpolation options
|
||||
static int createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues, Sdc::Options const& fvarOptions);
|
||||
|
||||
/// \brief Assign the face-varying values for the corners of each face
|
||||
static IndexArray getBaseFaceFVarValues(TopologyRefiner & newRefiner, Index face, int channel = 0);
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
//
|
||||
// Not to be specialized:
|
||||
//
|
||||
static bool populateBaseLevel(TopologyRefiner& refiner, MESH const& mesh, Options options);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Generic implementations:
|
||||
//
|
||||
template <class MESH>
|
||||
TopologyRefiner*
|
||||
TopologyRefinerFactory<MESH>::Create(MESH const& mesh, Options options) {
|
||||
|
||||
TopologyRefiner * refiner = new TopologyRefiner(options.schemeType, options.schemeOptions);
|
||||
|
||||
if (! populateBaseLevel(*refiner, mesh, options)) {
|
||||
delete refiner;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Eventually want to move the Refiner's inventory initialization here. Currently it
|
||||
// is handled after topology assignment, but if the inventory is to include additional
|
||||
// features (e.g. holes, etc.) it is better off deferred to here.
|
||||
|
||||
return refiner;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
TopologyRefiner*
|
||||
TopologyRefinerFactory<MESH>::Create(TopologyRefiner const & source) {
|
||||
|
||||
return new TopologyRefiner(source);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
bool
|
||||
TopologyRefinerFactory<MESH>::populateBaseLevel(TopologyRefiner& refiner, MESH const& mesh, Options options) {
|
||||
|
||||
//
|
||||
// Construction of a specialized topology refiner involves four steps, each of which
|
||||
// involves a method specialized for MESH followed by one that takes an action in
|
||||
// response to it or in preparation for the next step.
|
||||
//
|
||||
// Both the specialized methods and those that follow them may find fault in the
|
||||
// construction and trigger failure at any time:
|
||||
//
|
||||
|
||||
//
|
||||
// Sizing of the topology -- this is a required specialization for MESH. This defines
|
||||
// an inventory of all components and their relations that is used to allocate buffers
|
||||
// to be efficiently populated in the subsequent topology assignment step.
|
||||
//
|
||||
if (! resizeComponentTopology(refiner, mesh)) return false;
|
||||
if (! prepareComponentTopologySizing(refiner)) return false;
|
||||
|
||||
//
|
||||
// Assignment of the topology -- this is a required specialization for MESH. If edges
|
||||
// are specified, all other topological relations are expected to be defined for them.
|
||||
// Otherwise edges and remaining topology will be completed from the face-vertices:
|
||||
//
|
||||
bool validate = options.validateFullTopology;
|
||||
TopologyCallback callback = reinterpret_cast<TopologyCallback>(reportInvalidTopology);
|
||||
void const * userData = &mesh;
|
||||
|
||||
if (! assignComponentTopology(refiner, mesh)) return false;
|
||||
if (! prepareComponentTopologyAssignment(refiner, validate, callback, userData)) return false;
|
||||
|
||||
//
|
||||
// User assigned and internal tagging of components -- an optional specialization for
|
||||
// MESH. Allows the specification of sharpness values, holes, etc.
|
||||
//
|
||||
if (! assignComponentTags(refiner, mesh)) return false;
|
||||
if (! prepareComponentTagsAndSharpness(refiner)) return false;
|
||||
|
||||
//
|
||||
// Defining channels of face-varying primvar data -- an optional specialization for MESH.
|
||||
//
|
||||
if (! assignFaceVaryingTopology(refiner, mesh)) return false;
|
||||
if (! prepareFaceVaryingChannels(refiner)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setNumBaseFaces(TopologyRefiner & newRefiner, int count) {
|
||||
newRefiner._levels[0]->resizeFaces(count);
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setNumBaseEdges(TopologyRefiner & newRefiner, int count) {
|
||||
newRefiner._levels[0]->resizeEdges(count);
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setNumBaseVertices(TopologyRefiner & newRefiner, int count) {
|
||||
newRefiner._levels[0]->resizeVertices(count);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline int
|
||||
TopologyRefinerFactory<MESH>::getNumBaseFaces(TopologyRefiner const & newRefiner) {
|
||||
return newRefiner._levels[0]->getNumFaces();
|
||||
}
|
||||
template <class MESH>
|
||||
inline int
|
||||
TopologyRefinerFactory<MESH>::getNumBaseEdges(TopologyRefiner const & newRefiner) {
|
||||
return newRefiner._levels[0]->getNumEdges();
|
||||
}
|
||||
template <class MESH>
|
||||
inline int
|
||||
TopologyRefinerFactory<MESH>::getNumBaseVertices(TopologyRefiner const & newRefiner) {
|
||||
return newRefiner._levels[0]->getNumVertices();
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setNumBaseFaceVertices(TopologyRefiner & newRefiner, Index f, int count) {
|
||||
newRefiner._levels[0]->resizeFaceVertices(f, count);
|
||||
newRefiner._hasIrregFaces |= (count != newRefiner._regFaceSize);
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setNumBaseEdgeFaces(TopologyRefiner & newRefiner, Index e, int count) {
|
||||
newRefiner._levels[0]->resizeEdgeFaces(e, count);
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setNumBaseVertexFaces(TopologyRefiner & newRefiner, Index v, int count) {
|
||||
newRefiner._levels[0]->resizeVertexFaces(v, count);
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setNumBaseVertexEdges(TopologyRefiner & newRefiner, Index v, int count) {
|
||||
newRefiner._levels[0]->resizeVertexEdges(v, count);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline IndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseFaceVertices(TopologyRefiner & newRefiner, Index f) {
|
||||
return newRefiner._levels[0]->getFaceVertices(f);
|
||||
}
|
||||
template <class MESH>
|
||||
inline IndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseFaceEdges(TopologyRefiner & newRefiner, Index f) {
|
||||
return newRefiner._levels[0]->getFaceEdges(f);
|
||||
}
|
||||
template <class MESH>
|
||||
inline IndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseEdgeVertices(TopologyRefiner & newRefiner, Index e) {
|
||||
return newRefiner._levels[0]->getEdgeVertices(e);
|
||||
}
|
||||
template <class MESH>
|
||||
inline IndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseEdgeFaces(TopologyRefiner & newRefiner, Index e) {
|
||||
return newRefiner._levels[0]->getEdgeFaces(e);
|
||||
}
|
||||
template <class MESH>
|
||||
inline IndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseVertexFaces(TopologyRefiner & newRefiner, Index v) {
|
||||
return newRefiner._levels[0]->getVertexFaces(v);
|
||||
}
|
||||
template <class MESH>
|
||||
inline IndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseVertexEdges(TopologyRefiner & newRefiner, Index v) {
|
||||
return newRefiner._levels[0]->getVertexEdges(v);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline LocalIndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseEdgeFaceLocalIndices(TopologyRefiner & newRefiner, Index e) {
|
||||
return newRefiner._levels[0]->getEdgeFaceLocalIndices(e);
|
||||
}
|
||||
template <class MESH>
|
||||
inline LocalIndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseVertexFaceLocalIndices(TopologyRefiner & newRefiner, Index v) {
|
||||
return newRefiner._levels[0]->getVertexFaceLocalIndices(v);
|
||||
}
|
||||
template <class MESH>
|
||||
inline LocalIndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseVertexEdgeLocalIndices(TopologyRefiner & newRefiner, Index v) {
|
||||
return newRefiner._levels[0]->getVertexEdgeLocalIndices(v);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline Index
|
||||
TopologyRefinerFactory<MESH>::findBaseEdge(TopologyRefiner const & newRefiner, Index v0, Index v1) {
|
||||
return newRefiner._levels[0]->findEdge(v0, v1);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::populateBaseLocalIndices(TopologyRefiner & newRefiner) {
|
||||
newRefiner._levels[0]->populateLocalIndices();
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setBaseEdgeNonManifold(TopologyRefiner & newRefiner, Index e, bool b) {
|
||||
newRefiner._levels[0]->setEdgeNonManifold(e, b);
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setBaseVertexNonManifold(TopologyRefiner & newRefiner, Index v, bool b) {
|
||||
newRefiner._levels[0]->setVertexNonManifold(v, b);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setBaseEdgeSharpness(TopologyRefiner & newRefiner, Index e, float s) {
|
||||
newRefiner._levels[0]->getEdgeSharpness(e) = s;
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setBaseVertexSharpness(TopologyRefiner & newRefiner, Index v, float s) {
|
||||
newRefiner._levels[0]->getVertexSharpness(v) = s;
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setBaseFaceHole(TopologyRefiner & newRefiner, Index f, bool b) {
|
||||
newRefiner._levels[0]->setFaceHole(f, b);
|
||||
newRefiner._hasHoles |= b;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline int
|
||||
TopologyRefinerFactory<MESH>::createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues) {
|
||||
return newRefiner._levels[0]->createFVarChannel(numValues, newRefiner._subdivOptions);
|
||||
}
|
||||
template <class MESH>
|
||||
inline int
|
||||
TopologyRefinerFactory<MESH>::createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues, Sdc::Options const& fvarOptions) {
|
||||
Sdc::Options newOptions = newRefiner._subdivOptions;
|
||||
newOptions.SetFVarLinearInterpolation(fvarOptions.GetFVarLinearInterpolation());
|
||||
return newRefiner._levels[0]->createFVarChannel(numValues, newOptions);
|
||||
}
|
||||
template <class MESH>
|
||||
inline IndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseFaceFVarValues(TopologyRefiner & newRefiner, Index face, int channel) {
|
||||
return newRefiner._levels[0]->getFaceFVarValues(face, channel);
|
||||
}
|
||||
|
||||
|
||||
template <class MESH>
|
||||
bool
|
||||
TopologyRefinerFactory<MESH>::resizeComponentTopology(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
||||
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::resizeComponentTopology() -- no specialization provided.");
|
||||
|
||||
//
|
||||
// Sizing the topology tables:
|
||||
// This method is for determining the sizes of the various topology tables (and other
|
||||
// data) associated with the mesh. Once completed, appropriate memory will be allocated
|
||||
// and an additional method invoked to populate it accordingly.
|
||||
//
|
||||
// The following methods should be called -- first those to specify the number of faces,
|
||||
// edges and vertices in the mesh:
|
||||
//
|
||||
// void setBaseFaceCount( TopologyRefiner& newRefiner, int count)
|
||||
// void setBaseEdgeCount( TopologyRefiner& newRefiner, int count)
|
||||
// void setBaseVertexCount(TopologyRefiner& newRefiner, int count)
|
||||
//
|
||||
// and then for each face, edge and vertex, the number of its incident components:
|
||||
//
|
||||
// void setBaseFaceVertexCount(TopologyRefiner& newRefiner, Index face, int count)
|
||||
// void setBaseEdgeFaceCount( TopologyRefiner& newRefiner, Index edge, int count)
|
||||
// void setBaseVertexFaceCount(TopologyRefiner& newRefiner, Index vertex, int count)
|
||||
// void setBaseVertexEdgeCount(TopologyRefiner& newRefiner, Index vertex, int count)
|
||||
//
|
||||
// The count/size for a component type must be set before indices associated with that
|
||||
// component type can be used.
|
||||
//
|
||||
// Note that it is only necessary to size 4 of the 6 supported topological relations --
|
||||
// the number of edge-vertices is fixed at two per edge, and the number of face-edges is
|
||||
// the same as the number of face-vertices.
|
||||
//
|
||||
// So a single pass through your mesh to gather up all of this sizing information will
|
||||
// allow the Tables to be allocated appropriately once and avoid any dynamic resizing as
|
||||
// it grows.
|
||||
//
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
bool
|
||||
TopologyRefinerFactory<MESH>::assignComponentTopology(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
||||
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::assignComponentTopology() -- no specialization provided.");
|
||||
|
||||
//
|
||||
// Assigning the topology tables:
|
||||
// Once the topology tables have been allocated, the six required topological
|
||||
// relations can be directly populated using the following methods:
|
||||
//
|
||||
// IndexArray setBaseFaceVertices(TopologyRefiner& newRefiner, Index face)
|
||||
// IndexArray setBaseFaceEdges(TopologyRefiner& newRefiner, Index face)
|
||||
//
|
||||
// IndexArray setBaseEdgeVertices(TopologyRefiner& newRefiner, Index edge)
|
||||
// IndexArray setBaseEdgeFaces(TopologyRefiner& newRefiner, Index edge)
|
||||
//
|
||||
// IndexArray setBaseVertexEdges(TopologyRefiner& newRefiner, Index vertex)
|
||||
// IndexArray setBaseVertexFaces(TopologyRefiner& newRefiner, Index vertex)
|
||||
//
|
||||
// For the last two relations -- the faces and edges incident a vertex -- there are
|
||||
// also "local indices" that must be specified (considering doing this internally),
|
||||
// where the "local index" of each incident face or edge is the index of the vertex
|
||||
// within that face or edge, and so ranging from 0-3 for incident quads and 0-1 for
|
||||
// incident edges. These are assigned through similarly retrieved arrays:
|
||||
//
|
||||
// LocalIndexArray setBaseVertexFaceLocalIndices(TopologyRefiner& newRefiner, Index vertex)
|
||||
// LocalIndexArray setBaseVertexEdgeLocalIndices(TopologyRefiner& newRefiner, Index vertex)
|
||||
// LocalIndexArray setBaseEdgeFaceLocalIndices( TopologyRefiner& newRefiner, Index edge)
|
||||
//
|
||||
// or, if the mesh is manifold, explicit assignment of these can be deferred and
|
||||
// all can be determined by calling:
|
||||
//
|
||||
// void populateBaseLocalIndices(TopologyRefiner& newRefiner)
|
||||
//
|
||||
// All components are assumed to be locally manifold and ordering of components in
|
||||
// the above relations is expected to be counter-clockwise.
|
||||
//
|
||||
// For non-manifold components, no ordering/orientation of incident components is
|
||||
// assumed or required, but be sure to explicitly tag such components (vertices and
|
||||
// edges) as non-manifold:
|
||||
//
|
||||
// void setBaseEdgeNonManifold(TopologyRefiner& newRefiner, Index edge, bool b);
|
||||
//
|
||||
// void setBaseVertexNonManifold(TopologyRefiner& newRefiner, Index vertex, bool b);
|
||||
//
|
||||
// Also consider using TopologyLevel::ValidateTopology() when debugging to ensure
|
||||
// that topology has been completely and correctly specified.
|
||||
//
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
bool
|
||||
TopologyRefinerFactory<MESH>::assignFaceVaryingTopology(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
||||
|
||||
//
|
||||
// Optional assigning face-varying topology tables:
|
||||
//
|
||||
// Create independent face-varying primitive variable channels:
|
||||
// int createBaseFVarChannel(TopologyRefiner& newRefiner, int numValues)
|
||||
//
|
||||
// For each channel, populate the face-vertex values:
|
||||
// IndexArray setBaseFaceFVarValues(TopologyRefiner& newRefiner, Index face, int channel = 0)
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
bool
|
||||
TopologyRefinerFactory<MESH>::assignComponentTags(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
||||
|
||||
//
|
||||
// Optional tagging:
|
||||
// This is where any additional feature tags -- sharpness, holes, etc. -- can be
|
||||
// specified using:
|
||||
//
|
||||
// void setBaseEdgeSharpness(TopologyRefiner& newRefiner, Index edge, float sharpness)
|
||||
// void setBaseVertexSharpness(TopologyRefiner& newRefiner, Index vertex, float sharpness)
|
||||
//
|
||||
// void setBaseFaceHole(TopologyRefiner& newRefiner, Index face, bool hole)
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
void
|
||||
TopologyRefinerFactory<MESH>::reportInvalidTopology(
|
||||
TopologyError /* errCode */, char const * /* msg */, MESH const& /* mesh */) {
|
||||
|
||||
//
|
||||
// Optional topology validation error reporting:
|
||||
// This method is called whenever the factory encounters topology validation
|
||||
// errors. By default, nothing is reported
|
||||
//
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_TOPOLOGY_REFINER_FACTORY_H */
|
||||
61
src/osd/opensubdiv/far/types.h
Normal file
61
src/osd/opensubdiv/far/types.h
Normal file
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_TYPES_H
|
||||
#define OPENSUBDIV3_FAR_TYPES_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../vtr/types.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// Typedefs for indices that are inherited from the Vtr level -- eventually
|
||||
// these primitive Vtr types may be declared at a lower, more public level.
|
||||
//
|
||||
typedef Vtr::Index Index;
|
||||
typedef Vtr::LocalIndex LocalIndex;
|
||||
|
||||
typedef Vtr::IndexArray IndexArray;
|
||||
typedef Vtr::LocalIndexArray LocalIndexArray;
|
||||
|
||||
typedef Vtr::ConstIndexArray ConstIndexArray;
|
||||
typedef Vtr::ConstLocalIndexArray ConstLocalIndexArray;
|
||||
|
||||
inline bool IndexIsValid(Index index) { return Vtr::IndexIsValid(index); }
|
||||
|
||||
static const Index INDEX_INVALID = Vtr::INDEX_INVALID;
|
||||
static const int VALENCE_LIMIT = Vtr::VALENCE_LIMIT;
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_TYPES_H */
|
||||
58
src/osd/opensubdiv/hbr/CMakeLists.txt
Normal file
58
src/osd/opensubdiv/hbr/CMakeLists.txt
Normal file
@@ -0,0 +1,58 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
# with the following modification; you may not use this file except in
|
||||
# compliance with the Apache License and the following modification to it:
|
||||
# Section 6. Trademarks. is deleted and replaced with:
|
||||
#
|
||||
# 6. Trademarks. This License does not grant permission to use the trade
|
||||
# names, trademarks, service marks, or product names of the Licensor
|
||||
# and its affiliates, except as required to comply with Section 4(c) of
|
||||
# the License and to reproduce the content of the NOTICE file.
|
||||
#
|
||||
# You may obtain a copy of the Apache License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the Apache License with the above modification is
|
||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the Apache License for the specific
|
||||
# language governing permissions and limitations under the Apache License.
|
||||
#
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
set(PUBLIC_HEADER_FILES
|
||||
allocator.h
|
||||
bilinear.h
|
||||
catmark.h
|
||||
cornerEdit.h
|
||||
creaseEdit.h
|
||||
faceEdit.h
|
||||
face.h
|
||||
fvarData.h
|
||||
fvarEdit.h
|
||||
halfedge.h
|
||||
hierarchicalEdit.h
|
||||
holeEdit.h
|
||||
loop.h
|
||||
mesh.h
|
||||
subdivision.h
|
||||
vertexEdit.h
|
||||
vertex.h
|
||||
)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
install(
|
||||
FILES
|
||||
${PUBLIC_HEADER_FILES}
|
||||
DESTINATION
|
||||
"${CMAKE_INCDIR_BASE}/hbr"
|
||||
PERMISSIONS
|
||||
OWNER_READ
|
||||
GROUP_READ
|
||||
WORLD_READ )
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
172
src/osd/opensubdiv/hbr/allocator.h
Normal file
172
src/osd/opensubdiv/hbr/allocator.h
Normal file
@@ -0,0 +1,172 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRALLOCATOR_H
|
||||
#define OPENSUBDIV3_HBRALLOCATOR_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
typedef void (*HbrMemStatFunction)(size_t bytes);
|
||||
|
||||
/**
|
||||
* HbrAllocator - derived from UtBlockAllocator.h, but embedded in
|
||||
* libhbrep.
|
||||
*/
|
||||
template <typename T> class HbrAllocator {
|
||||
|
||||
public:
|
||||
|
||||
/// Constructor
|
||||
HbrAllocator(size_t *memorystat, int blocksize, void (*increment)(size_t bytes), void (*decrement)(size_t bytes), size_t elemsize = sizeof(T));
|
||||
|
||||
/// Destructor
|
||||
~HbrAllocator();
|
||||
|
||||
/// Create an allocated object
|
||||
T * Allocate();
|
||||
|
||||
/// Return an allocated object to the block allocator
|
||||
void Deallocate(T *);
|
||||
|
||||
/// Clear the allocator, deleting all allocated objects.
|
||||
void Clear();
|
||||
|
||||
void SetMemStatsIncrement(void (*increment)(size_t bytes)) { m_increment = increment; }
|
||||
|
||||
void SetMemStatsDecrement(void (*decrement)(size_t bytes)) { m_decrement = decrement; }
|
||||
|
||||
private:
|
||||
size_t *m_memorystat;
|
||||
const int m_blocksize;
|
||||
int m_elemsize;
|
||||
T** m_blocks;
|
||||
|
||||
// Number of actually allocated blocks
|
||||
int m_nblocks;
|
||||
|
||||
// Size of the m_blocks array (which is NOT the number of actually
|
||||
// allocated blocks)
|
||||
int m_blockCapacity;
|
||||
|
||||
int m_freecount;
|
||||
T * m_freelist;
|
||||
|
||||
// Memory statistics tracking routines
|
||||
HbrMemStatFunction m_increment;
|
||||
HbrMemStatFunction m_decrement;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
HbrAllocator<T>::HbrAllocator(size_t *memorystat, int blocksize, void (*increment)(size_t bytes), void (*decrement)(size_t bytes), size_t elemsize)
|
||||
: 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>
|
||||
HbrAllocator<T>::~HbrAllocator() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
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);
|
||||
*m_memorystat -= m_blocksize * m_elemsize;
|
||||
}
|
||||
free(m_blocks);
|
||||
m_blocks = 0;
|
||||
m_nblocks = 0;
|
||||
m_blockCapacity = 0;
|
||||
m_freecount = 0;
|
||||
m_freelist = NULL;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T*
|
||||
HbrAllocator<T>::Allocate() {
|
||||
if (!m_freecount) {
|
||||
|
||||
// Allocate a new block
|
||||
T* block = (T*) malloc(m_blocksize * m_elemsize);
|
||||
T* blockptr = block;
|
||||
// Run the constructors on each element using placement new
|
||||
for (int i = 0; i < m_blocksize; ++i) {
|
||||
new (blockptr) T();
|
||||
blockptr = (T*) ((char*) blockptr + m_elemsize);
|
||||
}
|
||||
if (m_increment) m_increment(m_blocksize * m_elemsize);
|
||||
*m_memorystat += m_blocksize * m_elemsize;
|
||||
|
||||
// Put the block's entries on the free list
|
||||
blockptr = block;
|
||||
for (int i = 0; i < m_blocksize - 1; ++i) {
|
||||
T* next = (T*) ((char*) blockptr + m_elemsize);
|
||||
blockptr->GetNext() = next;
|
||||
blockptr = next;
|
||||
}
|
||||
blockptr->GetNext() = 0;
|
||||
m_freelist = block;
|
||||
|
||||
// Keep track of the newly allocated block
|
||||
if (m_nblocks + 1 >= m_blockCapacity) {
|
||||
m_blockCapacity = m_blockCapacity * 2;
|
||||
if (m_blockCapacity < 1) m_blockCapacity = 1;
|
||||
m_blocks = (T**) realloc(m_blocks, m_blockCapacity * sizeof(T*));
|
||||
}
|
||||
m_blocks[m_nblocks] = block;
|
||||
m_nblocks++;
|
||||
m_freecount += m_blocksize;
|
||||
}
|
||||
T* obj = m_freelist;
|
||||
m_freelist = obj->GetNext();
|
||||
obj->GetNext() = 0;
|
||||
m_freecount--;
|
||||
return obj;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
HbrAllocator<T>::Deallocate(T * obj) {
|
||||
assert(!obj->GetNext());
|
||||
obj->GetNext() = m_freelist;
|
||||
m_freelist = obj;
|
||||
m_freecount++;
|
||||
}
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRALLOCATOR_H */
|
||||
909
src/osd/opensubdiv/hbr/bilinear.h
Normal file
909
src/osd/opensubdiv/hbr/bilinear.h
Normal file
@@ -0,0 +1,909 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRBILINEAR_H
|
||||
#define OPENSUBDIV3_HBRBILINEAR_H
|
||||
|
||||
/*#define HBR_DEBUG */
|
||||
#include "../hbr/subdivision.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T>
|
||||
class HbrBilinearSubdivision : public HbrSubdivision<T> {
|
||||
public:
|
||||
HbrBilinearSubdivision<T>()
|
||||
: HbrSubdivision<T>() {}
|
||||
|
||||
virtual HbrSubdivision<T>* Clone() const {
|
||||
return new HbrBilinearSubdivision<T>();
|
||||
}
|
||||
|
||||
virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face);
|
||||
virtual HbrFace<T>* RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex);
|
||||
virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
|
||||
virtual void GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
||||
|
||||
virtual bool HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face);
|
||||
virtual bool HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
|
||||
virtual bool HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
||||
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face);
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
||||
|
||||
virtual bool VertexIsExtraordinary(HbrMesh<T> const * /* mesh */, HbrVertex<T>* vertex) { return vertex->GetValence() != 4; }
|
||||
virtual bool FaceIsExtraordinary(HbrMesh<T> const * /* mesh */, HbrFace<T>* face) { return face->GetNumVertices() != 4; }
|
||||
|
||||
virtual int GetFaceChildrenCount(int nvertices) const { return nvertices; }
|
||||
|
||||
private:
|
||||
|
||||
// Transfers facevarying data from a parent face to a child face
|
||||
void transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, HbrFace<T>* child, int index);
|
||||
|
||||
// Transfers vertex and edge edits from a parent face to a child face
|
||||
void transferEditsToChild(HbrFace<T>* face, HbrFace<T>* child, int index);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrBilinearSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, HbrFace<T>* child, int index) {
|
||||
|
||||
typename HbrMesh<T>::InterpolateBoundaryMethod fvarinterp = mesh->GetFVarInterpolateBoundaryMethod();
|
||||
const int fvarcount = mesh->GetFVarCount();
|
||||
int fvarindex = 0;
|
||||
const int nv = face->GetNumVertices();
|
||||
bool extraordinary = (nv != 4);
|
||||
HbrVertex<T> *v = face->GetVertex(index), *childVertex;
|
||||
HbrHalfedge<T>* edge;
|
||||
|
||||
// We do the face subdivision rule first, because we may reuse the
|
||||
// result (stored in fv2) for the other subdivisions.
|
||||
float weight = 1.0f / nv;
|
||||
|
||||
// For the face center vertex, the facevarying data can be cleared
|
||||
// and averaged en masse, since the subdivision rules don't change
|
||||
// for any of the data - we use the smooth rule for all of it.
|
||||
// And since we know that the fvardata for this particular vertex
|
||||
// is smooth and therefore shareable amongst all incident faces,
|
||||
// we don't have to allocate extra storage for it. We also don't
|
||||
// have to compute it if some other face got to it first (as
|
||||
// indicated by the IsInitialized() flag).
|
||||
HbrFVarData<T>& fv2 = child->GetFVarData(extraordinary ? 2 : (index+2)%4);
|
||||
if (!fv2.IsInitialized()) {
|
||||
const int totalfvarwidth = mesh->GetTotalFVarWidth();
|
||||
fv2.ClearAll(totalfvarwidth);
|
||||
for (int j = 0; j < nv; ++j) {
|
||||
fv2.AddWithWeightAll(face->GetFVarData(j), totalfvarwidth, weight);
|
||||
}
|
||||
}
|
||||
assert(fv2.IsInitialized());
|
||||
|
||||
v->GuaranteeNeighbors();
|
||||
|
||||
// Make sure that that each of the vertices of the child face have
|
||||
// the appropriate facevarying storage as needed. If there are
|
||||
// discontinuities in any facevarying datum, the vertex must
|
||||
// allocate a new block of facevarying storage specific to the
|
||||
// child face.
|
||||
bool fv0IsSmooth, fv1IsSmooth, fv3IsSmooth;
|
||||
|
||||
childVertex = child->GetVertex(extraordinary ? 0 : (index+0)%4);
|
||||
fv0IsSmooth = v->IsFVarAllSmooth();
|
||||
if (!fv0IsSmooth) {
|
||||
childVertex->NewFVarData(child);
|
||||
}
|
||||
HbrFVarData<T>& fv0 = childVertex->GetFVarData(child);
|
||||
|
||||
edge = face->GetEdge(index);
|
||||
GuaranteeNeighbor(mesh, edge);
|
||||
assert(edge->GetOrgVertex() == v);
|
||||
childVertex = child->GetVertex(extraordinary ? 1 : (index+1)%4);
|
||||
fv1IsSmooth = !edge->IsFVarInfiniteSharpAnywhere();
|
||||
if (!fv1IsSmooth) {
|
||||
childVertex->NewFVarData(child);
|
||||
}
|
||||
HbrFVarData<T>& fv1 = childVertex->GetFVarData(child);
|
||||
|
||||
edge = edge->GetPrev();
|
||||
GuaranteeNeighbor(mesh, edge);
|
||||
assert(edge == face->GetEdge((index + nv - 1) % nv));
|
||||
assert(edge->GetDestVertex() == v);
|
||||
childVertex = child->GetVertex(extraordinary ? 3 : (index+3)%4);
|
||||
fv3IsSmooth = !edge->IsFVarInfiniteSharpAnywhere();
|
||||
if (!fv3IsSmooth) {
|
||||
childVertex->NewFVarData(child);
|
||||
}
|
||||
HbrFVarData<T>& fv3 = childVertex->GetFVarData(child);
|
||||
fvarindex = 0;
|
||||
for (int fvaritem = 0; fvaritem < fvarcount; ++fvaritem) {
|
||||
// Vertex subdivision rule. Analyze whether the vertex is on the
|
||||
// boundary and whether it's an infinitely sharp corner. We
|
||||
// determine the last by checking the propagate corners flag on
|
||||
// the mesh; if it's off, we check the two edges of this face
|
||||
// incident to that vertex and determining whether they are
|
||||
// facevarying boundary edges - this is analogous to what goes on
|
||||
// for the interpolateboundary tag (which when set to
|
||||
// EDGEANDCORNER marks vertices with a valence of two as being
|
||||
// sharp corners). If propagate corners is on, we check *all*
|
||||
// faces to see if two edges side by side are facevarying boundary
|
||||
// edges. The facevarying boundary check ignores geometric
|
||||
// sharpness, otherwise we may swim at geometric creases which
|
||||
// aren't actually discontinuous.
|
||||
bool infcorner = false;
|
||||
const int fvarwidth = mesh->GetFVarWidths()[fvaritem];
|
||||
const unsigned char fvarmask = v->GetFVarMask(fvaritem);
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryEdgeAndCorner) {
|
||||
if (fvarmask >= HbrVertex<T>::k_Corner) {
|
||||
infcorner = true;
|
||||
} else if (mesh->GetFVarPropagateCorners()) {
|
||||
if (v->IsFVarCorner(fvaritem)) {
|
||||
infcorner = true;
|
||||
}
|
||||
} else {
|
||||
if (face->GetEdge(index)->GetFVarSharpness(fvaritem, true) && face->GetEdge(index)->GetPrev()->GetFVarSharpness(fvaritem, true)) {
|
||||
infcorner = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Infinitely sharp vertex rule. Applied if the vertex is:
|
||||
// - undergoing no facevarying boundary interpolation;
|
||||
// - at a geometric crease, in either boundary interpolation case; or
|
||||
// - is an infinitely sharp facevarying vertex, in the EDGEANDCORNER case; or
|
||||
// - has a mask equal or greater than one, in the "always
|
||||
// sharp" interpolate boundary case
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
|
||||
(fvarinterp == HbrMesh<T>::k_InterpolateBoundaryAlwaysSharp &&
|
||||
fvarmask >= 1) ||
|
||||
v->GetSharpness() > HbrVertex<T>::k_Smooth ||
|
||||
infcorner) {
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 1.0f);
|
||||
}
|
||||
// Dart rule: unlike geometric creases, because there's two
|
||||
// discontinuous values for the one incident edge, we use the
|
||||
// boundary rule and not the smooth rule
|
||||
else if (fvarmask == 1) {
|
||||
assert(!v->OnBoundary());
|
||||
|
||||
// Use 0.75 of the current vert
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.75f);
|
||||
|
||||
// 0.125 of "two adjacent edge vertices", which in actuality
|
||||
// are the facevarying values of the same vertex but on each
|
||||
// side of the single incident facevarying sharp edge
|
||||
HbrHalfedge<T>* start = v->GetIncidentEdge(), *nextedge;
|
||||
edge = start;
|
||||
while (edge) {
|
||||
if (edge->GetFVarSharpness(fvaritem)) {
|
||||
break;
|
||||
}
|
||||
nextedge = v->GetNextEdge(edge);
|
||||
if (nextedge == start) {
|
||||
assert(0); // we should have found it by now
|
||||
break;
|
||||
} else if (!nextedge) {
|
||||
// should never get into this case - if the vertex is
|
||||
// on a boundary, it can never be a facevarying dart
|
||||
// vertex
|
||||
assert(0);
|
||||
edge = edge->GetPrev();
|
||||
break;
|
||||
} else {
|
||||
edge = nextedge;
|
||||
}
|
||||
}
|
||||
HbrVertex<T>* w = edge->GetDestVertex();
|
||||
HbrFace<T>* bestface = edge->GetLeftFace();
|
||||
int j;
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
bestface = edge->GetRightFace();
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
}
|
||||
// Boundary vertex rule
|
||||
else if (fvarmask != 0) {
|
||||
|
||||
// Use 0.75 of the current vert
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.75f);
|
||||
|
||||
// Compute 0.125 of two adjacent edge vertices. However the
|
||||
// two adjacent edge vertices we use must be part of the
|
||||
// facevarying "boundary". To find the first edge we cycle
|
||||
// counterclockwise around the current vertex v and look for
|
||||
// the first boundary edge
|
||||
|
||||
HbrFace<T>* bestface = face;
|
||||
HbrHalfedge<T>* bestedge = face->GetEdge(index)->GetPrev();
|
||||
HbrHalfedge<T>* starte = bestedge->GetOpposite();
|
||||
HbrVertex<T>* w = 0;
|
||||
if (!starte) {
|
||||
w = face->GetEdge(index)->GetPrev()->GetOrgVertex();
|
||||
} else {
|
||||
HbrHalfedge<T>* e = starte, *next;
|
||||
assert(starte->GetOrgVertex() == v);
|
||||
do {
|
||||
if (e->GetFVarSharpness(fvaritem) || !e->GetLeftFace()) {
|
||||
bestface = e->GetRightFace();
|
||||
bestedge = e;
|
||||
break;
|
||||
}
|
||||
next = v->GetNextEdge(e);
|
||||
if (!next) {
|
||||
bestface = e->GetLeftFace();
|
||||
w = e->GetPrev()->GetOrgVertex();
|
||||
break;
|
||||
}
|
||||
e = next;
|
||||
} while (e && e != starte);
|
||||
}
|
||||
if (!w) w = bestedge->GetDestVertex();
|
||||
int j;
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
|
||||
// Look for the other edge by cycling clockwise around v
|
||||
bestface = face;
|
||||
bestedge = face->GetEdge(index);
|
||||
starte = bestedge;
|
||||
w = 0;
|
||||
if (HbrHalfedge<T>* e = starte) {
|
||||
assert(starte->GetOrgVertex() == v);
|
||||
do {
|
||||
if (e->GetFVarSharpness(fvaritem) || !e->GetRightFace()) {
|
||||
bestface = e->GetLeftFace();
|
||||
bestedge = e;
|
||||
break;
|
||||
}
|
||||
assert(e->GetOpposite());
|
||||
e = v->GetPreviousEdge(e);
|
||||
} while (e && e != starte);
|
||||
}
|
||||
if (!w) w = bestedge->GetDestVertex();
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
|
||||
}
|
||||
// Smooth rule. Here, we can take a shortcut if we know that
|
||||
// the vertex is smooth and some other vertex has completely
|
||||
// computed the facevarying values
|
||||
else if (!fv0IsSmooth || !fv0.IsInitialized()) {
|
||||
int valence = v->GetValence();
|
||||
float invvalencesquared = 1.0f / (valence * valence);
|
||||
|
||||
// Use n-2/n of the current vertex value
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, invvalencesquared * valence * (valence - 2));
|
||||
|
||||
// Add 1/n^2 of surrounding edge vertices and surrounding face
|
||||
// averages. We loop over all surrounding faces..
|
||||
HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge;
|
||||
edge = start;
|
||||
while (edge) {
|
||||
HbrFace<T>* g = edge->GetLeftFace();
|
||||
weight = invvalencesquared / g->GetNumVertices();
|
||||
// .. and compute the average of each face. At the same
|
||||
// time, we look for the edge on that face whose origin is
|
||||
// the same as v, and add a contribution from its
|
||||
// destination vertex value; this takes care of the
|
||||
// surrounding edge vertex addition.
|
||||
for (int j = 0; j < g->GetNumVertices(); ++j) {
|
||||
fv0.AddWithWeight(g->GetFVarData(j), fvarindex, fvarwidth, weight);
|
||||
if (g->GetEdge(j)->GetOrgVertex() == v) {
|
||||
fv0.AddWithWeight(g->GetFVarData((j + 1) % g->GetNumVertices()), fvarindex, fvarwidth, invvalencesquared);
|
||||
}
|
||||
}
|
||||
edge = v->GetNextEdge(edge);
|
||||
if (edge == start) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Edge subdivision rule
|
||||
edge = face->GetEdge(index);
|
||||
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
|
||||
edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) {
|
||||
|
||||
// Sharp edge rule
|
||||
fv1.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f);
|
||||
fv1.AddWithWeight(face->GetFVarData((index + 1) % nv), fvarindex, fvarwidth, 0.5f);
|
||||
} else if (!fv1IsSmooth || !fv1.IsInitialized()) {
|
||||
// Smooth edge subdivision. Add 0.25 of adjacent vertices
|
||||
fv1.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.25f);
|
||||
fv1.AddWithWeight(face->GetFVarData((index + 1) % nv), fvarindex, fvarwidth, 0.25f);
|
||||
// Local subdivided face vertex
|
||||
fv1.AddWithWeight(fv2, fvarindex, fvarwidth, 0.25f);
|
||||
// Add 0.25 * average of neighboring face vertices
|
||||
HbrFace<T>* oppFace = edge->GetRightFace();
|
||||
weight = 0.25f / oppFace->GetNumVertices();
|
||||
for (int j = 0; j < oppFace->GetNumVertices(); ++j) {
|
||||
fv1.AddWithWeight(oppFace->GetFVarData(j), fvarindex, fvarwidth, weight);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Edge subdivision rule
|
||||
edge = edge->GetPrev();
|
||||
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
|
||||
edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) {
|
||||
|
||||
// Sharp edge rule
|
||||
fv3.SetWithWeight(face->GetFVarData((index + nv - 1) % nv), fvarindex, fvarwidth, 0.5f);
|
||||
fv3.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f);
|
||||
} else if (!fv3IsSmooth || !fv3.IsInitialized()) {
|
||||
// Smooth edge subdivision. Add 0.25 of adjacent vertices
|
||||
fv3.SetWithWeight(face->GetFVarData((index + nv - 1) % nv), fvarindex, fvarwidth, 0.25f);
|
||||
fv3.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.25f);
|
||||
// Local subdivided face vertex
|
||||
fv3.AddWithWeight(fv2, fvarindex, fvarwidth, 0.25f);
|
||||
// Add 0.25 * average of neighboring face vertices
|
||||
HbrFace<T>* oppFace = edge->GetRightFace();
|
||||
weight = 0.25f / oppFace->GetNumVertices();
|
||||
for (int j = 0; j < oppFace->GetNumVertices(); ++j) {
|
||||
fv3.AddWithWeight(oppFace->GetFVarData(j), fvarindex, fvarwidth, weight);
|
||||
}
|
||||
}
|
||||
|
||||
fvarindex += fvarwidth;
|
||||
}
|
||||
fv0.SetInitialized();
|
||||
fv1.SetInitialized();
|
||||
fv3.SetInitialized();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrBilinearSubdivision<T>::transferEditsToChild(HbrFace<T>* face, HbrFace<T>* child, int index) {
|
||||
|
||||
// Hand down hole tag
|
||||
child->SetHole(face->IsHole());
|
||||
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrBilinearSubdivision<T>::Refine(HbrMesh<T>* mesh, HbrFace<T>* face) {
|
||||
|
||||
// Create new quadrilateral children faces from this face
|
||||
HbrFace<T>* child;
|
||||
HbrVertex<T>* vertices[4];
|
||||
HbrHalfedge<T>* edge = face->GetFirstEdge();
|
||||
HbrHalfedge<T>* prevedge = edge->GetPrev();
|
||||
HbrHalfedge<T>* childedge;
|
||||
int nv = face->GetNumVertices();
|
||||
float sharpness;
|
||||
bool extraordinary = (nv != 4);
|
||||
// The funny indexing on vertices is done only for
|
||||
// non-extraordinary faces in order to correctly preserve
|
||||
// parametric space through the refinement. If we split an
|
||||
// extraordinary face then it doesn't matter.
|
||||
for (int i = 0; i < nv; ++i) {
|
||||
if (!face->GetChild(i)) {
|
||||
#ifdef HBR_DEBUG
|
||||
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);
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Creating face " << *child << " during refine\n";
|
||||
#endif
|
||||
|
||||
// Hand down edge sharpnesses
|
||||
childedge = vertex->Subdivide()->GetEdge(edge->Subdivide());
|
||||
assert(childedge);
|
||||
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(edge, edge->GetOrgVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(edge);
|
||||
|
||||
childedge = prevedge->Subdivide()->GetEdge(vertex->Subdivide());
|
||||
assert(childedge);
|
||||
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(prevedge, prevedge->GetDestVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(prevedge);
|
||||
|
||||
if (mesh->GetTotalFVarWidth()) {
|
||||
transferFVarToChild(mesh, face, child, i);
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrFace<T>*
|
||||
HbrBilinearSubdivision<T>::RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " forcing refine on " << *face << " at " << *vertex << '\n';
|
||||
#endif
|
||||
|
||||
// Create new quadrilateral children faces from this face
|
||||
HbrHalfedge<T>* edge = face->GetFirstEdge();
|
||||
HbrHalfedge<T>* prevedge = edge->GetPrev();
|
||||
HbrHalfedge<T>* childedge;
|
||||
int nv = face->GetNumVertices();
|
||||
float sharpness;
|
||||
bool extraordinary = (nv != 4);
|
||||
// The funny indexing on vertices is done only for
|
||||
// non-extraordinary faces in order to correctly preserve
|
||||
// parametric space through the refinement. If we split an
|
||||
// extraordinary face then it doesn't matter.
|
||||
for (int i = 0; i < nv; ++i) {
|
||||
if (edge->GetOrgVertex() == vertex) {
|
||||
if (!face->GetChild(i)) {
|
||||
HbrFace<T>* child;
|
||||
HbrVertex<T>* vertices[4];
|
||||
if (extraordinary) {
|
||||
vertices[0] = vertex->Subdivide();
|
||||
vertices[1] = edge->Subdivide();
|
||||
vertices[2] = face->Subdivide();
|
||||
vertices[3] = prevedge->Subdivide();
|
||||
} else {
|
||||
vertices[i] = vertex->Subdivide();
|
||||
vertices[(i+1)%4] = edge->Subdivide();
|
||||
vertices[(i+2)%4] = face->Subdivide();
|
||||
vertices[(i+3)%4] = prevedge->Subdivide();
|
||||
}
|
||||
#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';
|
||||
#endif
|
||||
child = mesh->NewFace(4, vertices, face, i);
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Creating face " << *child << " during refine\n";
|
||||
#endif
|
||||
// Hand down edge sharpness
|
||||
childedge = vertex->Subdivide()->GetEdge(edge->Subdivide());
|
||||
assert(childedge);
|
||||
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(edge, edge->GetOrgVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(edge);
|
||||
|
||||
childedge = prevedge->Subdivide()->GetEdge(vertex->Subdivide());
|
||||
assert(childedge);
|
||||
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(prevedge, prevedge->GetDestVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(prevedge);
|
||||
|
||||
if (mesh->GetTotalFVarWidth()) {
|
||||
transferFVarToChild(mesh, face, child, i);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrBilinearSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
|
||||
if (edge->GetOpposite()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For the given edge: if the parent of either of its incident
|
||||
// vertices is itself a _face_, then ensuring that this parent
|
||||
// face has refined at a particular vertex is sufficient to
|
||||
// ensure that both of the faces on each side of the edge have
|
||||
// been created.
|
||||
bool destParentWasEdge = true;
|
||||
HbrFace<T>* parentFace = edge->GetOrgVertex()->GetParentFace();
|
||||
HbrHalfedge<T>* parentEdge = edge->GetDestVertex()->GetParentEdge();
|
||||
if (!parentFace) {
|
||||
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);
|
||||
#ifdef HBR_DEBUG
|
||||
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());
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
if (parentVertex) {
|
||||
|
||||
assert(parentEdge);
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "\nparent edge is " << *parentEdge << "\n";
|
||||
#endif
|
||||
|
||||
// 1. Go up to the parent of my face
|
||||
|
||||
parentFace = edge->GetFace()->GetParent();
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "\nparent face is " << *parentFace << "\n";
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// FIXME: assertion?
|
||||
assert(edge->GetOpposite());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrBilinearSubdivision<T>::GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "\n\nneighbor guarantee at " << *vertex << " invoked\n";
|
||||
#endif
|
||||
|
||||
// If the vertex is a child of a face, guaranteeing the neighbors
|
||||
// of the vertex is simply a matter of ensuring the parent face
|
||||
// has refined.
|
||||
HbrFace<T>* parentFace = vertex->GetParentFace();
|
||||
if (parentFace) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " forcing full refine on parent face\n";
|
||||
#endif
|
||||
Refine(mesh, parentFace);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise if the vertex is a child of an edge, we need to
|
||||
// ensure that the parent faces on either side of the parent edge
|
||||
// 1) exist, and 2) have refined at both vertices of the parent
|
||||
// edge
|
||||
HbrHalfedge<T>* parentEdge = vertex->GetParentEdge();
|
||||
if (parentEdge) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
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);
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
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);
|
||||
}
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " end force\n";
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// The last case: the vertex is a child of a vertex. In this case
|
||||
// we have to first recursively guarantee that the parent's
|
||||
// adjacent faces also exist.
|
||||
HbrVertex<T>* parentVertex = vertex->GetParentVertex();
|
||||
if (parentVertex) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " recursive parent vertex guarantee call\n";
|
||||
#endif
|
||||
parentVertex->GuaranteeNeighbors();
|
||||
|
||||
// And then we refine all the face neighbors of the
|
||||
// parentVertex
|
||||
HbrHalfedge<T>* start = parentVertex->GetIncidentEdge(), *edge;
|
||||
edge = start;
|
||||
while (edge) {
|
||||
HbrFace<T>* f = edge->GetLeftFace();
|
||||
RefineFaceAtVertex(mesh, f, parentVertex);
|
||||
edge = parentVertex->GetNextEdge(edge);
|
||||
if (edge == start) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
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;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
HbrBilinearSubdivision<T>::HasLimit(HbrMesh<T>* /* mesh */, HbrHalfedge<T>* /* edge */) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) {
|
||||
|
||||
// Face rule: simply average all vertices on the face
|
||||
HbrVertex<T>* v = mesh->NewVertex();
|
||||
T& data = v->GetData();
|
||||
int nv = face->GetNumVertices();
|
||||
float weight = 1.0f / nv;
|
||||
|
||||
HbrHalfedge<T>* edge = face->GetFirstEdge();
|
||||
for (int i = 0; i < face->GetNumVertices(); ++i) {
|
||||
HbrVertex<T>* w = edge->GetOrgVertex();
|
||||
// If there are vertex edits we have to make sure the edit
|
||||
// has been applied
|
||||
if (mesh->HasVertexEdits()) {
|
||||
w->GuaranteeNeighbors();
|
||||
}
|
||||
data.AddWithWeight(w->GetData(), weight);
|
||||
data.AddVaryingWithWeight(w->GetData(), weight);
|
||||
edge = edge->GetNext();
|
||||
}
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Subdividing at " << *face << "\n";
|
||||
#endif
|
||||
|
||||
// Set the extraordinary flag if the face had anything other than
|
||||
// 4 vertices
|
||||
if (nv != 4) v->SetExtraordinary();
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " created " << *v << "\n";
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
float esharp = edge->GetSharpness();
|
||||
std::cerr << "Subdividing at " << *edge << " (sharpness = " << esharp << ")";
|
||||
#endif
|
||||
|
||||
HbrVertex<T>* v = mesh->NewVertex();
|
||||
T& data = v->GetData();
|
||||
|
||||
|
||||
// If there's the possibility of a crease edits, make sure the
|
||||
// edit has been applied
|
||||
if (mesh->HasCreaseEdits()) {
|
||||
edge->GuaranteeNeighbor();
|
||||
}
|
||||
|
||||
// If there's the possibility of vertex edits on either vertex, we
|
||||
// have to make sure the edit has been applied
|
||||
if (mesh->HasVertexEdits()) {
|
||||
edge->GetOrgVertex()->GuaranteeNeighbors();
|
||||
edge->GetDestVertex()->GuaranteeNeighbors();
|
||||
}
|
||||
|
||||
// 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
|
||||
data.AddVaryingWithWeight(edge->GetOrgVertex()->GetData(), 0.5f);
|
||||
data.AddVaryingWithWeight(edge->GetDestVertex()->GetData(), 0.5f);
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " created " << *v << "\n";
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrBilinearSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
|
||||
|
||||
HbrVertex<T>* v;
|
||||
|
||||
// If there are vertex edits we have to make sure the edit has
|
||||
// been applied by guaranteeing the neighbors of the
|
||||
// vertex. Unfortunately in this case, we can't share the data
|
||||
// with the parent
|
||||
if (mesh->HasVertexEdits()) {
|
||||
vertex->GuaranteeNeighbors();
|
||||
|
||||
v = mesh->NewVertex();
|
||||
T& data = v->GetData();
|
||||
|
||||
// Just copy the old value
|
||||
data.AddWithWeight(vertex->GetData(), 1.0f);
|
||||
|
||||
// Varying data is always just propagated down
|
||||
data.AddVaryingWithWeight(vertex->GetData(), 1.0f);
|
||||
|
||||
} else {
|
||||
// Create a new vertex that just shares the same data
|
||||
v = mesh->NewVertex(vertex->GetData());
|
||||
}
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Subdividing at " << *vertex << "\n";
|
||||
std::cerr << " created " << *v << "\n";
|
||||
#endif
|
||||
// Inherit extraordinary flag and sharpness
|
||||
if (vertex->IsExtraordinary()) v->SetExtraordinary();
|
||||
float sharp = vertex->GetSharpness();
|
||||
if (sharp >= HbrVertex<T>::k_InfinitelySharp) {
|
||||
v->SetSharpness(HbrVertex<T>::k_InfinitelySharp);
|
||||
} 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);
|
||||
} else {
|
||||
v->SetSharpness(HbrVertex<T>::k_Smooth);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRBILINEAR_H */
|
||||
1131
src/osd/opensubdiv/hbr/catmark.h
Normal file
1131
src/osd/opensubdiv/hbr/catmark.h
Normal file
File diff suppressed because it is too large
Load Diff
98
src/osd/opensubdiv/hbr/cornerEdit.h
Normal file
98
src/osd/opensubdiv/hbr/cornerEdit.h
Normal file
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRCORNEREDIT_H
|
||||
#define OPENSUBDIV3_HBRCORNEREDIT_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrCornerEdit;
|
||||
|
||||
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]) << ' ';
|
||||
}
|
||||
return out << static_cast<int>(path.vertexid) << "), sharpness = " << path.sharpness;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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) {
|
||||
}
|
||||
|
||||
HbrCornerEdit(int _faceid, int _nsubfaces, int *_subfaces, int _vertexid, typename HbrHierarchicalEdit<T>::Operation _op, float _sharpness)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), vertexid(static_cast<unsigned char>(_vertexid)), op(_op), sharpness(_sharpness) {
|
||||
}
|
||||
|
||||
virtual ~HbrCornerEdit() {}
|
||||
|
||||
friend std::ostream& operator<< <T> (std::ostream& out, const HbrCornerEdit<T>& path);
|
||||
|
||||
virtual void ApplyEditToFace(HbrFace<T>* face) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
|
||||
// Modify vertex sharpness. Note that we could actually do
|
||||
// this in ApplyEditToVertex as well!
|
||||
float sharp = 0.0f;
|
||||
if (op == HbrHierarchicalEdit<T>::Set) {
|
||||
sharp = sharpness;
|
||||
} else if (op == HbrHierarchicalEdit<T>::Add) {
|
||||
sharp = face->GetVertex(vertexid)->GetSharpness() + sharpness;
|
||||
} else if (op == HbrHierarchicalEdit<T>::Subtract) {
|
||||
sharp = face->GetVertex(vertexid)->GetSharpness() - sharpness;
|
||||
}
|
||||
if (sharp < HbrVertex<T>::k_Smooth) {
|
||||
sharp = HbrVertex<T>::k_Smooth;
|
||||
}
|
||||
if (sharp > HbrVertex<T>::k_InfinitelySharp) {
|
||||
sharp = HbrVertex<T>::k_InfinitelySharp;
|
||||
}
|
||||
face->GetVertex(vertexid)->SetSharpness(sharp);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// ID of the edge (you can think of this also as the id of the
|
||||
// origin vertex of the two-vertex length edge)
|
||||
const unsigned char vertexid;
|
||||
typename HbrHierarchicalEdit<T>::Operation op;
|
||||
// sharpness of the vertex edit
|
||||
const float sharpness;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRCORNEREDIT_H */
|
||||
100
src/osd/opensubdiv/hbr/creaseEdit.h
Normal file
100
src/osd/opensubdiv/hbr/creaseEdit.h
Normal file
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRCREASEEDIT_H
|
||||
#define OPENSUBDIV3_HBRCREASEEDIT_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrCreaseEdit;
|
||||
|
||||
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]) << ' ';
|
||||
}
|
||||
return out << static_cast<int>(path.edgeid) << "), sharpness = " << path.sharpness;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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) {
|
||||
}
|
||||
|
||||
HbrCreaseEdit(int _faceid, int _nsubfaces, int *_subfaces, int _edgeid, typename HbrHierarchicalEdit<T>::Operation _op, float _sharpness)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces), edgeid(static_cast<unsigned char>(_edgeid)), op(_op), sharpness(_sharpness) {
|
||||
}
|
||||
|
||||
virtual ~HbrCreaseEdit() {}
|
||||
|
||||
friend std::ostream& operator<< <T> (std::ostream& out, const HbrCreaseEdit<T>& path);
|
||||
|
||||
virtual void ApplyEditToFace(HbrFace<T>* face) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
|
||||
// Modify edge sharpness
|
||||
float sharp=0.0f;
|
||||
if (op == HbrHierarchicalEdit<T>::Set) {
|
||||
sharp = sharpness;
|
||||
} else if (op == HbrHierarchicalEdit<T>::Add) {
|
||||
sharp = face->GetEdge(edgeid)->GetSharpness() + sharpness;
|
||||
} else if (op == HbrHierarchicalEdit<T>::Subtract) {
|
||||
sharp = face->GetEdge(edgeid)->GetSharpness() - sharpness;
|
||||
}
|
||||
if (sharp < HbrHalfedge<T>::k_Smooth)
|
||||
sharp = HbrHalfedge<T>::k_Smooth;
|
||||
if (sharp > HbrHalfedge<T>::k_InfinitelySharp)
|
||||
sharp = HbrHalfedge<T>::k_InfinitelySharp;
|
||||
// We have to make sure the neighbor of the edge exists at
|
||||
// this point. Otherwise, if it comes into being late, it
|
||||
// will clobber the overriden sharpness and we will lose
|
||||
// the edit.
|
||||
face->GetEdge(edgeid)->GuaranteeNeighbor();
|
||||
face->GetEdge(edgeid)->SetSharpness(sharp);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// ID of the edge (you can think of this also as the id of the
|
||||
// origin vertex of the two-vertex length edge)
|
||||
const unsigned char edgeid;
|
||||
typename HbrHierarchicalEdit<T>::Operation op;
|
||||
// sharpness of the edge edit
|
||||
const float sharpness;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRCREASEEDIT_H */
|
||||
1029
src/osd/opensubdiv/hbr/face.h
Normal file
1029
src/osd/opensubdiv/hbr/face.h
Normal file
File diff suppressed because it is too large
Load Diff
125
src/osd/opensubdiv/hbr/faceEdit.h
Normal file
125
src/osd/opensubdiv/hbr/faceEdit.h
Normal file
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRFACEEDIT_H
|
||||
#define OPENSUBDIV3_HBRFACEEDIT_H
|
||||
|
||||
#include "../hbr/hierarchicalEdit.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrFaceEdit;
|
||||
|
||||
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]) << ' ';
|
||||
}
|
||||
return out << ")";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual ~HbrFaceEdit() {
|
||||
delete[] edit;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<< <T> (std::ostream& out, const HbrFaceEdit<T>& path);
|
||||
|
||||
// Return index of variable this edit applies to
|
||||
int GetIndex() const { return index; }
|
||||
|
||||
// Return width of the variable
|
||||
int GetWidth() const { return width; }
|
||||
|
||||
// Get the numerical value of the edit
|
||||
const float* GetEdit() const { return edit; }
|
||||
|
||||
// Get the type of operation
|
||||
typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; }
|
||||
|
||||
virtual void ApplyEditToFace(HbrFace<T>* face) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
|
||||
|
||||
int oldUniformIndex = face->GetUniformIndex();
|
||||
|
||||
// Any face below level 0 needs a new uniform index
|
||||
if (face->GetDepth() > 0) {
|
||||
face->SetUniformIndex(face->GetMesh()->NewUniformIndex());
|
||||
}
|
||||
|
||||
// Apply edit
|
||||
face->GetVertex(0)->GetData().ApplyFaceEdit(oldUniformIndex, face->GetUniformIndex(), *const_cast<const HbrFaceEdit<T>*>(this));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int index;
|
||||
int width;
|
||||
typename HbrHierarchicalEdit<T>::Operation op;
|
||||
float* edit;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRFACEEDIT_H */
|
||||
200
src/osd/opensubdiv/hbr/fvarData.h
Normal file
200
src/osd/opensubdiv/hbr/fvarData.h
Normal file
@@ -0,0 +1,200 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRFVARDATA_H
|
||||
#define OPENSUBDIV3_HBRFVARDATA_H
|
||||
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrFVarEdit;
|
||||
template <class T> class HbrFace;
|
||||
template <class T> class HbrVertex;
|
||||
|
||||
// This class implements a "face varying vector item". Really it's
|
||||
// just a smart wrapper around face varying data (itself just a bunch
|
||||
// of floats) stored on each vertex.
|
||||
template <class T> class HbrFVarData {
|
||||
|
||||
private:
|
||||
HbrFVarData()
|
||||
: faceid(0), initialized(0) {
|
||||
}
|
||||
|
||||
~HbrFVarData() {
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
HbrFVarData(const HbrFVarData &/* data */) {}
|
||||
|
||||
public:
|
||||
|
||||
// Sets the face id
|
||||
void SetFaceID(int id) {
|
||||
faceid = id;
|
||||
}
|
||||
|
||||
// Returns the id of the face to which this data is bound
|
||||
int GetFaceID() const {
|
||||
return faceid;
|
||||
}
|
||||
|
||||
// Clears the initialized flag
|
||||
void Uninitialize() {
|
||||
initialized = 0;
|
||||
faceid = 0;
|
||||
}
|
||||
|
||||
// Returns initialized flag
|
||||
bool IsInitialized() const {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
// Sets initialized flag
|
||||
void SetInitialized() {
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
// Return the data from the NgpFVVector
|
||||
float* GetData(int item) { return data + item; }
|
||||
|
||||
// Clears the indicates value of this item
|
||||
void Clear(int startindex, int width) {
|
||||
memset(data + startindex, 0, width * sizeof(float));
|
||||
}
|
||||
|
||||
// Clears all values of this item
|
||||
void ClearAll(int width) {
|
||||
initialized = 1;
|
||||
memset(data, 0, width * sizeof(float));
|
||||
}
|
||||
|
||||
// Set values of the indicated item (with the indicated weighing)
|
||||
// on this item
|
||||
void SetWithWeight(const HbrFVarData& fvvi, int startindex, int width, float weight) {
|
||||
float *dst = data + startindex;
|
||||
const float *src = fvvi.data + startindex;
|
||||
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;
|
||||
const float *src = fvvi.data + startindex;
|
||||
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;
|
||||
const float *src = fvvi.data;
|
||||
for (int i = 0; i < width; ++i) {
|
||||
*dst++ += weight * *src++;
|
||||
}
|
||||
}
|
||||
|
||||
// Compare all values item against a float buffer. Returns true
|
||||
// if all values match
|
||||
bool CompareAll(int width, const float *values, float tolerance=0.0f) const {
|
||||
if (!initialized) return false;
|
||||
for (int i = 0; i < width; ++i) {
|
||||
if (fabsf(values[i] - data[i]) > tolerance) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initializes data
|
||||
void SetAllData(int width, const float *values) {
|
||||
initialized = 1;
|
||||
memcpy(data, values, width * sizeof(float));
|
||||
}
|
||||
|
||||
// Compare this item against another item with tolerance. Returns
|
||||
// true if it compares identical
|
||||
bool Compare(const HbrFVarData& fvvi, int startindex, int width, float tolerance=0.0f) const {
|
||||
for (int i = 0; i < width; ++i) {
|
||||
if (fabsf(data[startindex + i] - fvvi.data[startindex + i]) > tolerance) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Modify the data of the item with an edit
|
||||
void ApplyFVarEdit(const HbrFVarEdit<T>& edit);
|
||||
|
||||
friend class HbrVertex<T>;
|
||||
|
||||
private:
|
||||
unsigned int faceid:31;
|
||||
unsigned int initialized:1;
|
||||
float data[1];
|
||||
};
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#include "../hbr/fvarEdit.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
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++;
|
||||
}
|
||||
}
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRFVARDATA_H */
|
||||
121
src/osd/opensubdiv/hbr/fvarEdit.h
Normal file
121
src/osd/opensubdiv/hbr/fvarEdit.h
Normal file
@@ -0,0 +1,121 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRFVAREDIT_H
|
||||
#define OPENSUBDIV3_HBRFVAREDIT_H
|
||||
|
||||
#include "../hbr/hierarchicalEdit.h"
|
||||
#include "../hbr/vertexEdit.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrFVarEdit;
|
||||
|
||||
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]) << ' ';
|
||||
}
|
||||
return out << static_cast<int>(path.vertexid) << "), edit = (" << path.edit[0] << ',' << path.edit[1] << ',' << path.edit[2] << ')';
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
virtual ~HbrFVarEdit() {
|
||||
delete[] edit;
|
||||
}
|
||||
|
||||
// Return the vertex id (the last element in the path)
|
||||
unsigned char GetVertexID() const { return vertexid; }
|
||||
|
||||
friend std::ostream& operator<< <T> (std::ostream& out, const HbrFVarEdit<T>& path);
|
||||
|
||||
// Return index into the facevarying data
|
||||
int GetIndex() const { return index; }
|
||||
|
||||
// Return width of the data
|
||||
int GetWidth() const { return width; }
|
||||
|
||||
// Return offset of the data
|
||||
int GetOffset() const { return offset; }
|
||||
|
||||
// Get the numerical value of the edit
|
||||
const float* GetEdit() const { return edit; }
|
||||
|
||||
// Get the type of operation
|
||||
typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; }
|
||||
|
||||
virtual void ApplyEditToFace(HbrFace<T>* face) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
|
||||
// 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
|
||||
// one that already exists) and modify that
|
||||
HbrFVarData<T> &fvt = face->GetVertex(vertexid)->GetFVarData(face);
|
||||
if (fvt.GetFaceID() != face->GetID()) {
|
||||
// This is the generic fvt, allocate a new copy and edit it
|
||||
HbrFVarData<T> &newfvt = face->GetVertex(vertexid)->NewFVarData(face);
|
||||
newfvt.SetAllData(face->GetMesh()->GetTotalFVarWidth(), fvt.GetData(0));
|
||||
newfvt.ApplyFVarEdit(*const_cast<const HbrFVarEdit<T>*>(this));
|
||||
} else {
|
||||
fvt.ApplyFVarEdit(*const_cast<const HbrFVarEdit<T>*>(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const unsigned char vertexid;
|
||||
const int index;
|
||||
const int width;
|
||||
const int offset;
|
||||
float* edit;
|
||||
typename HbrHierarchicalEdit<T>::Operation op;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRFVAREDIT_H */
|
||||
740
src/osd/opensubdiv/hbr/halfedge.h
Normal file
740
src/osd/opensubdiv/hbr/halfedge.h
Normal file
@@ -0,0 +1,740 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRHALFEDGE_H
|
||||
#define OPENSUBDIV3_HBRHALFEDGE_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
#ifdef HBRSTITCH
|
||||
#include "libgprims/stitch.h"
|
||||
#include "libgprims/stitchInternal.h"
|
||||
#endif
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrFace;
|
||||
template <class T> class HbrHalfedge;
|
||||
template <class T> class HbrVertex;
|
||||
template <class T> class HbrMesh;
|
||||
|
||||
template <class T> std::ostream& operator<<(std::ostream& out, const HbrHalfedge<T>& edge);
|
||||
|
||||
template <class T> class HbrHalfedge {
|
||||
|
||||
private:
|
||||
HbrHalfedge(): opposite(0), incidentVertex(-1), vchild(-1), sharpness(0.0f)
|
||||
#ifdef HBRSTITCH
|
||||
, stitchccw(1), raystitchccw(1)
|
||||
#endif
|
||||
, coarse(1)
|
||||
{
|
||||
}
|
||||
|
||||
HbrHalfedge(const HbrHalfedge &/* edge */) {}
|
||||
|
||||
~HbrHalfedge();
|
||||
|
||||
void Clear();
|
||||
|
||||
// Finish the initialization of the halfedge. Should only be
|
||||
// called by HbrFace
|
||||
void Initialize(HbrHalfedge<T>* opposite, int index, HbrVertex<T>* origin, unsigned int *fvarbits, HbrFace<T>* face);
|
||||
public:
|
||||
|
||||
// Returns the opposite half edge
|
||||
HbrHalfedge<T>* GetOpposite() const { return opposite; }
|
||||
|
||||
// Sets the opposite half edge
|
||||
void SetOpposite(HbrHalfedge<T>* opposite) { this->opposite = opposite; sharpness = opposite->sharpness; }
|
||||
|
||||
// Returns the next clockwise halfedge around the incident face
|
||||
HbrHalfedge<T>* GetNext() const {
|
||||
if (m_index == 4) {
|
||||
const size_t edgesize = sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*);
|
||||
if (lastedge) {
|
||||
return (HbrHalfedge<T>*) ((char*) this - (GetFace()->GetNumVertices() - 1) * edgesize);
|
||||
} else {
|
||||
return (HbrHalfedge<T>*) ((char*) this + edgesize);
|
||||
}
|
||||
} else {
|
||||
if (lastedge) {
|
||||
return (HbrHalfedge<T>*) ((char*) this - (m_index) * sizeof(HbrHalfedge<T>));
|
||||
} else {
|
||||
return (HbrHalfedge<T>*) ((char*) this + sizeof(HbrHalfedge<T>));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the previous counterclockwise halfedge around the incident face
|
||||
HbrHalfedge<T>* GetPrev() const {
|
||||
const size_t edgesize = (m_index == 4) ?
|
||||
(sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*)) :
|
||||
sizeof(HbrHalfedge<T>);
|
||||
if (firstedge) {
|
||||
return (HbrHalfedge<T>*) ((char*) this + (GetFace()->GetNumVertices() - 1) * edgesize);
|
||||
} else {
|
||||
return (HbrHalfedge<T>*) ((char*) this - edgesize);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the incident vertex
|
||||
HbrVertex<T>* GetVertex() const {
|
||||
return GetMesh()->GetVertex(incidentVertex);
|
||||
}
|
||||
|
||||
// Returns the incident vertex
|
||||
HbrVertex<T>* GetVertex(HbrMesh<T> *mesh) const {
|
||||
return mesh->GetVertex(incidentVertex);
|
||||
}
|
||||
|
||||
// Returns the incident vertex
|
||||
int GetVertexID() const {
|
||||
return incidentVertex;
|
||||
}
|
||||
|
||||
// Returns the source vertex
|
||||
HbrVertex<T>* GetOrgVertex() const {
|
||||
return GetVertex();
|
||||
}
|
||||
|
||||
// Returns the source vertex
|
||||
HbrVertex<T>* GetOrgVertex(HbrMesh<T> *mesh) const {
|
||||
return GetVertex(mesh);
|
||||
}
|
||||
|
||||
// Returns the source vertex id
|
||||
int GetOrgVertexID() const {
|
||||
return incidentVertex;
|
||||
}
|
||||
|
||||
// Changes the origin vertex. Generally not a good idea to do
|
||||
void SetOrgVertex(HbrVertex<T>* v) { incidentVertex = v->GetID(); }
|
||||
|
||||
// Returns the destination vertex
|
||||
HbrVertex<T>* GetDestVertex() const { return GetNext()->GetOrgVertex(); }
|
||||
|
||||
// Returns the destination vertex
|
||||
HbrVertex<T>* GetDestVertex(HbrMesh<T> *mesh) const { return GetNext()->GetOrgVertex(mesh); }
|
||||
|
||||
// Returns the destination vertex ID
|
||||
int GetDestVertexID() const { return GetNext()->GetOrgVertexID(); }
|
||||
|
||||
// Returns the incident facet
|
||||
HbrFace<T>* GetFace() const {
|
||||
if (m_index == 4) {
|
||||
// Pointer to face is stored after the data for the edge
|
||||
return *(HbrFace<T>**)((char *) this + sizeof(HbrHalfedge<T>));
|
||||
} else {
|
||||
return (HbrFace<T>*) ((char*) this - (m_index) * sizeof(HbrHalfedge<T>) -
|
||||
offsetof(HbrFace<T>, edges));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the mesh to which this edge belongs
|
||||
HbrMesh<T>* GetMesh() const { return GetFace()->GetMesh(); }
|
||||
|
||||
// Returns the face on the right
|
||||
HbrFace<T>* GetRightFace() const { return opposite ? opposite->GetLeftFace() : NULL; }
|
||||
|
||||
// Return the face on the left of the halfedge
|
||||
HbrFace<T>* GetLeftFace() const { return GetFace(); }
|
||||
|
||||
// Returns whether this is a boundary edge
|
||||
bool IsBoundary() const { return opposite == 0; }
|
||||
|
||||
// Tag the edge as being an infinitely sharp facevarying edge
|
||||
void SetFVarInfiniteSharp(int datum, bool infsharp) {
|
||||
int intindex = datum >> 4;
|
||||
unsigned int bits = infsharp << ((datum & 15) * 2);
|
||||
getFVarInfSharp()[intindex] |= bits;
|
||||
if (opposite) {
|
||||
opposite->getFVarInfSharp()[intindex] |= bits;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy fvar infinite sharpness flags from another edge
|
||||
void CopyFVarInfiniteSharpness(HbrHalfedge<T>* edge) {
|
||||
unsigned int *fvarinfsharp = getFVarInfSharp();
|
||||
if (fvarinfsharp) {
|
||||
const int fvarcount = GetMesh()->GetFVarCount();
|
||||
int fvarbitsSizePerEdge = ((fvarcount + 15) / 16);
|
||||
|
||||
if (edge->IsSharp(true)) {
|
||||
memset(fvarinfsharp, 0x55555555, fvarbitsSizePerEdge * sizeof(unsigned int));
|
||||
} else {
|
||||
memcpy(fvarinfsharp, edge->getFVarInfSharp(), fvarbitsSizePerEdge * sizeof(unsigned int));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns whether the edge is infinitely sharp in facevarying for
|
||||
// a particular facevarying datum
|
||||
bool GetFVarInfiniteSharp(int datum);
|
||||
|
||||
// Returns whether the edge is infinitely sharp in any facevarying
|
||||
// datum
|
||||
bool IsFVarInfiniteSharpAnywhere();
|
||||
|
||||
// Get the sharpness relative to facevarying data
|
||||
float GetFVarSharpness(int datum, bool ignoreGeometry=false);
|
||||
|
||||
// Returns the (raw) sharpness of the edge
|
||||
float GetSharpness() const { return sharpness; }
|
||||
|
||||
// Sets the sharpness of the edge
|
||||
void SetSharpness(float sharp) { sharpness = sharp; if (opposite) opposite->sharpness = sharp; ClearMask(); }
|
||||
|
||||
// Returns whether the edge is sharp at the current level of
|
||||
// subdivision (next = false) or at the next level of subdivision
|
||||
// (next = true).
|
||||
bool IsSharp(bool next) const { return (next ? (sharpness > 0.0f) : (sharpness >= 1.0f)); }
|
||||
|
||||
// Clears the masks of the adjacent edge vertices. Usually called
|
||||
// when a change in edge sharpness occurs.
|
||||
void ClearMask() { GetOrgVertex()->ClearMask(); GetDestVertex()->ClearMask(); }
|
||||
|
||||
// Subdivide the edge into a vertex if needed and return
|
||||
HbrVertex<T>* Subdivide();
|
||||
|
||||
// Make sure the edge has its opposite face
|
||||
void GuaranteeNeighbor();
|
||||
|
||||
// True if the edge has a subdivided child vertex
|
||||
bool HasChild() const { return vchild!=-1; }
|
||||
|
||||
// Remove the reference to subdivided vertex
|
||||
void RemoveChild() { vchild = -1; }
|
||||
|
||||
// Sharpness constants
|
||||
enum Mask {
|
||||
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 stitch edge exists, and this edge has no opposite, destroy
|
||||
// it
|
||||
void DestroyStitchEdges(int stitchcount) {
|
||||
if (!opposite) {
|
||||
StitchEdge **stitchEdge = getStitchEdges();
|
||||
for (int i = 0; i < stitchcount; ++i) {
|
||||
if (stitchEdge[i]) {
|
||||
StitchFreeEdge(stitchEdge[i]);
|
||||
stitchEdge[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StitchEdge* GetRayStitchEdge(int i) {
|
||||
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 **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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SplitRayStitchEdge(int i) {
|
||||
SplitStitchEdge(i + 2);
|
||||
}
|
||||
|
||||
void SetStitchEdge(int i, StitchEdge* edge) {
|
||||
StitchEdge **stitchEdges = getStitchEdges();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void* GetStitchData() const {
|
||||
if (stitchdatavalid) return GetMesh()->GetStitchData(this);
|
||||
else return 0;
|
||||
}
|
||||
|
||||
void SetStitchData(void* data) {
|
||||
GetMesh()->SetStitchData(this, data);
|
||||
stitchdatavalid = data ? 1 : 0;
|
||||
if (opposite) {
|
||||
opposite->GetMesh()->SetStitchData(opposite, 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;
|
||||
}
|
||||
}
|
||||
|
||||
void ToggleStitchCCW(bool raytraced) {
|
||||
if (raytraced) {
|
||||
raystitchccw = 1 - raystitchccw;
|
||||
if (opposite) opposite->raystitchccw = raystitchccw;
|
||||
} else {
|
||||
stitchccw = 1 - stitchccw;
|
||||
if (opposite) opposite->stitchccw = stitchccw;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Marks the edge as being "coarse" (belonging to the control
|
||||
// mesh). Generally this distinction only needs to be made if
|
||||
// we're worried about interpolateboundary behaviour
|
||||
void SetCoarse(bool c) { coarse = c; }
|
||||
bool IsCoarse() const { return coarse; }
|
||||
|
||||
friend class HbrFace<T>;
|
||||
|
||||
private:
|
||||
HbrHalfedge<T>* opposite;
|
||||
// Index of incident vertex
|
||||
int incidentVertex;
|
||||
|
||||
// Index of subdivided vertex child
|
||||
int vchild;
|
||||
float sharpness;
|
||||
|
||||
#ifdef HBRSTITCH
|
||||
unsigned short stitchccw:1;
|
||||
unsigned short raystitchccw:1;
|
||||
unsigned short stitchdatavalid:1;
|
||||
#endif
|
||||
unsigned short coarse:1;
|
||||
unsigned short lastedge:1;
|
||||
unsigned short firstedge:1;
|
||||
|
||||
// If m_index = 0, 1, 2 or 3: we are the m_index edge of an
|
||||
// incident face with 3 or 4 vertices.
|
||||
// If m_index = 4: our incident face has more than 4 vertices, and
|
||||
// we must do some extra math to determine what our actual index
|
||||
// is. See getIndex()
|
||||
unsigned short m_index:3;
|
||||
|
||||
// Returns the index of the edge relative to its incident face.
|
||||
// This relies on knowledge of the face's edge allocation pattern
|
||||
int getIndex() const {
|
||||
if (m_index < 4) {
|
||||
return m_index;
|
||||
} else {
|
||||
// We allocate room for up to 4 values (to handle tri or
|
||||
// quad) in the edges array. If there are more than that,
|
||||
// they _all_ go in the faces' extraedges array.
|
||||
HbrFace<T>* incidentFace = *(HbrFace<T>**)((char *) this + sizeof(HbrHalfedge<T>));
|
||||
return int(((char *) this - incidentFace->extraedges) /
|
||||
(sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*)));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns bitmask indicating whether a given facevarying datum
|
||||
// for the edge is infinitely sharp. Each datum has two bits, and
|
||||
// if those two bits are set to 3, it means the status has not
|
||||
// been computed yet.
|
||||
unsigned int *getFVarInfSharp() {
|
||||
unsigned int *fvarbits = GetFace()->fvarbits;
|
||||
if (fvarbits) {
|
||||
int fvarbitsSizePerEdge = ((GetMesh()->GetFVarCount() + 15) / 16);
|
||||
return fvarbits + getIndex() * fvarbitsSizePerEdge;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HBRSTITCH
|
||||
StitchEdge **getStitchEdges() {
|
||||
return GetFace()->stitchEdges + GetMesh()->GetStitchCount() * getIndex();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HBR_ADAPTIVE
|
||||
public:
|
||||
struct adaptiveFlags {
|
||||
unsigned isTransition:1;
|
||||
unsigned isTriangleHead:1;
|
||||
unsigned isWatertightCritical:1;
|
||||
|
||||
adaptiveFlags() : isTransition(0),isTriangleHead(0),isWatertightCritical(0) { }
|
||||
};
|
||||
|
||||
adaptiveFlags _adaptiveFlags;
|
||||
|
||||
bool IsInsideHole() const {
|
||||
|
||||
HbrFace<T> * left = GetLeftFace();
|
||||
if (left and (not left->IsHole()))
|
||||
return false;
|
||||
|
||||
HbrFace<T> * right = GetRightFace();
|
||||
if (right and (not right->IsHole()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsTransition() const { return _adaptiveFlags.isTransition; }
|
||||
|
||||
bool IsTriangleHead() const { return _adaptiveFlags.isTriangleHead; }
|
||||
|
||||
bool IsWatertightCritical() const { return _adaptiveFlags.isWatertightCritical; }
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrHalfedge<T>::Initialize(HbrHalfedge<T>* opposite, int index, HbrVertex<T>* origin,
|
||||
unsigned int *fvarbits, HbrFace<T>* face) {
|
||||
HbrMesh<T> *mesh = face->GetMesh();
|
||||
if (face->GetNumVertices() <= 4) {
|
||||
m_index = index;
|
||||
} else {
|
||||
m_index = 4;
|
||||
// Assumes upstream allocation ensured we have extra storage
|
||||
// for pointer to face after the halfedge data structure
|
||||
// itself
|
||||
*(HbrFace<T>**)((char *) this + sizeof(HbrHalfedge<T>)) = face;
|
||||
}
|
||||
|
||||
this->opposite = opposite;
|
||||
incidentVertex = origin->GetID();
|
||||
lastedge = (index == face->GetNumVertices() - 1);
|
||||
firstedge = (index == 0);
|
||||
if (opposite) {
|
||||
sharpness = opposite->sharpness;
|
||||
#ifdef HBRSTITCH
|
||||
StitchEdge **stitchEdges = face->stitchEdges +
|
||||
mesh->GetStitchCount() * index;
|
||||
for (int i = 0; i < mesh->GetStitchCount(); ++i) {
|
||||
stitchEdges[i] = opposite->getStitchEdges()[i];
|
||||
}
|
||||
stitchccw = opposite->stitchccw;
|
||||
raystitchccw = opposite->raystitchccw;
|
||||
stitchdatavalid = 0;
|
||||
if (stitchEdges && opposite->GetStitchData()) {
|
||||
mesh->SetStitchData(this, opposite->GetStitchData());
|
||||
stitchdatavalid = 1;
|
||||
}
|
||||
#endif
|
||||
if (fvarbits) {
|
||||
const int fvarcount = mesh->GetFVarCount();
|
||||
int fvarbitsSizePerEdge = ((fvarcount + 15) / 16);
|
||||
memcpy(fvarbits, opposite->getFVarInfSharp(), fvarbitsSizePerEdge * sizeof(unsigned int));
|
||||
}
|
||||
} else {
|
||||
sharpness = 0.0f;
|
||||
#ifdef HBRSTITCH
|
||||
StitchEdge **stitchEdges = getStitchEdges();
|
||||
for (int i = 0; i < mesh->GetStitchCount(); ++i) {
|
||||
stitchEdges[i] = 0;
|
||||
}
|
||||
stitchccw = 1;
|
||||
raystitchccw = 1;
|
||||
stitchdatavalid = 0;
|
||||
#endif
|
||||
if (fvarbits) {
|
||||
const int fvarcount = mesh->GetFVarCount();
|
||||
int fvarbitsSizePerEdge = ((fvarcount + 15) / 16);
|
||||
memset(fvarbits, 0xff, fvarbitsSizePerEdge * sizeof(unsigned int));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrHalfedge<T>::~HbrHalfedge() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrHalfedge<T>::Clear() {
|
||||
if (opposite) {
|
||||
opposite->opposite = 0;
|
||||
if (vchild != -1) {
|
||||
// Transfer ownership of the vchild to the opposite ptr
|
||||
opposite->vchild = vchild;
|
||||
|
||||
HbrVertex<T> *vchildVert = GetMesh()->GetVertex(vchild);
|
||||
// Done this way just for assertion sanity
|
||||
vchildVert->SetParent(static_cast<HbrHalfedge*>(0));
|
||||
vchildVert->SetParent(opposite);
|
||||
vchild = -1;
|
||||
}
|
||||
opposite = 0;
|
||||
}
|
||||
// Orphan the child vertex
|
||||
else if (vchild != -1) {
|
||||
HbrVertex<T> *vchildVert = GetMesh()->GetVertex(vchild);
|
||||
vchildVert->SetParent(static_cast<HbrHalfedge*>(0));
|
||||
vchild = -1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrHalfedge<T>::Subdivide() {
|
||||
HbrMesh<T>* mesh = GetMesh();
|
||||
if (vchild != -1) return mesh->GetVertex(vchild);
|
||||
// Make sure that our opposite doesn't "own" a subdivided vertex
|
||||
// already. If it does, use that
|
||||
if (opposite && opposite->vchild != -1) return mesh->GetVertex(opposite->vchild);
|
||||
HbrVertex<T>* vchildVert = mesh->GetSubdivision()->Subdivide(mesh, this);
|
||||
vchild = vchildVert->GetID();
|
||||
vchildVert->SetParent(this);
|
||||
return vchildVert;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrHalfedge<T>::GuaranteeNeighbor() {
|
||||
HbrMesh<T>* mesh = GetMesh();
|
||||
mesh->GetSubdivision()->GuaranteeNeighbor(mesh, this);
|
||||
}
|
||||
|
||||
// Determines whether an edge is infinitely sharp as far as its
|
||||
// facevarying data is concerned. Happens if the faces on both sides
|
||||
// disagree on the facevarying data at either of the shared vertices
|
||||
// on the edge.
|
||||
template <class T>
|
||||
bool
|
||||
HbrHalfedge<T>::GetFVarInfiniteSharp(int datum) {
|
||||
|
||||
// Check to see if already initialized
|
||||
int intindex = datum >> 4;
|
||||
int shift = (datum & 15) << 1;
|
||||
unsigned int *fvarinfsharp = getFVarInfSharp();
|
||||
unsigned int bits = (fvarinfsharp[intindex] >> shift) & 0x3;
|
||||
if (bits != 3) {
|
||||
assert (bits != 2);
|
||||
return bits ? true : false;
|
||||
}
|
||||
|
||||
// If there is no face varying data it can't be infinitely sharp!
|
||||
const int fvarwidth = GetMesh()->GetTotalFVarWidth();
|
||||
if (!fvarwidth) {
|
||||
bits = ~(0x3 << shift);
|
||||
fvarinfsharp[intindex] &= bits;
|
||||
if (opposite) opposite->getFVarInfSharp()[intindex] &= bits;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If either incident face is missing, it's a geometric boundary
|
||||
// edge, and also a facevarying boundary edge
|
||||
HbrFace<T>* left = GetLeftFace(), *right = GetRightFace();
|
||||
if (!left || !right) {
|
||||
bits = ~(0x2 << shift);
|
||||
fvarinfsharp[intindex] &= bits;
|
||||
if (opposite) opposite->getFVarInfSharp()[intindex] &= bits;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Look for the indices on each face which correspond to the
|
||||
// origin and destination vertices of the edge
|
||||
int lorg = -1, ldst = -1, rorg = -1, rdst = -1, i, nv;
|
||||
HbrHalfedge<T>* e;
|
||||
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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
assert(lorg >= 0 && ldst >= 0 && rorg >= 0 && rdst >= 0);
|
||||
// Compare the facevarying data to some tolerance
|
||||
const int startindex = GetMesh()->GetFVarIndices()[datum];
|
||||
const int width = GetMesh()->GetFVarWidths()[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;
|
||||
return true;
|
||||
}
|
||||
|
||||
bits = ~(0x3 << shift);
|
||||
fvarinfsharp[intindex] &= bits;
|
||||
if (opposite) opposite->getFVarInfSharp()[intindex] &= bits;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
HbrHalfedge<T>::IsFVarInfiniteSharpAnywhere() {
|
||||
|
||||
if (sharpness > k_Smooth) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < GetMesh()->GetFVarCount(); ++i) {
|
||||
if (GetFVarInfiniteSharp(i)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
float
|
||||
HbrHalfedge<T>::GetFVarSharpness(int datum, bool ignoreGeometry) {
|
||||
|
||||
if (GetFVarInfiniteSharp(datum)) 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) {
|
||||
SetFVarInfiniteSharp(datum, true);
|
||||
return k_InfinitelySharp;
|
||||
}
|
||||
}
|
||||
return k_Smooth;
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& out, const HbrHalfedge<T>& edge) {
|
||||
if (edge.IsBoundary()) out << "boundary ";
|
||||
out << "edge connecting ";
|
||||
if (edge.GetOrgVertex())
|
||||
out << *edge.GetOrgVertex();
|
||||
else
|
||||
out << "(none)";
|
||||
out << " to ";
|
||||
if (edge.GetDestVertex()) {
|
||||
out << *edge.GetDestVertex();
|
||||
} else {
|
||||
out << "(none)";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Sorts half edges by the relative ordering of the incident faces'
|
||||
// paths.
|
||||
template <class T>
|
||||
class HbrHalfedgeCompare {
|
||||
public:
|
||||
bool operator() (const HbrHalfedge<T>* a, HbrHalfedge<T>* b) const {
|
||||
return (a->GetFace()->GetPath() < b->GetFace()->GetPath());
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class HbrHalfedgeOperator {
|
||||
public:
|
||||
virtual void operator() (HbrHalfedge<T> &edge) = 0;
|
||||
virtual ~HbrHalfedgeOperator() {}
|
||||
};
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRHALFEDGE_H */
|
||||
171
src/osd/opensubdiv/hbr/hierarchicalEdit.h
Normal file
171
src/osd/opensubdiv/hbr/hierarchicalEdit.h
Normal file
@@ -0,0 +1,171 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRHIERARCHICALEDIT_H
|
||||
#define OPENSUBDIV3_HBRHIERARCHICALEDIT_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrHierarchicalEdit;
|
||||
template <class T> class HbrFace;
|
||||
template <class T> class HbrVertex;
|
||||
|
||||
template <class T>
|
||||
class HbrHierarchicalEdit {
|
||||
|
||||
public:
|
||||
typedef enum Operation {
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~HbrHierarchicalEdit() {
|
||||
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);
|
||||
}
|
||||
|
||||
// Return the face id (the first element in the path)
|
||||
int GetFaceID() const { return faceid; }
|
||||
|
||||
// Return the number of subfaces in the path
|
||||
int GetNSubfaces() const { return nsubfaces; }
|
||||
|
||||
// Return a subface element in the path
|
||||
unsigned char GetSubface(int index) const { return subfaces[index]; }
|
||||
|
||||
// Determines whether this hierarchical edit is relevant to the
|
||||
// face in question
|
||||
bool IsRelevantToFace(HbrFace<T>* face) const;
|
||||
|
||||
// Applys edit to face. All subclasses may override this method
|
||||
virtual void ApplyEditToFace(HbrFace<T>* /* face */) {}
|
||||
|
||||
// Applys edit to vertex. Subclasses may override this method.
|
||||
virtual void ApplyEditToVertex(HbrFace<T>* /* face */, HbrVertex<T>* /* vertex */) {}
|
||||
|
||||
#ifdef PRMAN
|
||||
// Gets the effect of this hierarchical edit on the bounding box.
|
||||
// Subclasses may override this method
|
||||
virtual void ApplyToBound(struct bbox& /* box */, RtMatrix * /* mx */) const {}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// ID of the top most face in the mesh which begins the path
|
||||
const int faceid;
|
||||
|
||||
// Number of subfaces
|
||||
const int nsubfaces;
|
||||
|
||||
// IDs of the subfaces
|
||||
unsigned char *subfaces;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class HbrHierarchicalEditComparator {
|
||||
public:
|
||||
bool operator() (const HbrHierarchicalEdit<T>* path1, const HbrHierarchicalEdit<T>* path2) const {
|
||||
return (*path1 < *path2);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#include "../hbr/face.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
HbrHierarchicalEdit<T>::IsRelevantToFace(HbrFace<T>* face) const {
|
||||
|
||||
// Key assumption: the face's first vertex edit is relevant to
|
||||
// that face. We will then compare ourselves to that edit and if
|
||||
// the first part of our subpath is identical to the entirety of
|
||||
// that subpath, this edit is relevant.
|
||||
|
||||
// Calling code is responsible for making sure we don't
|
||||
// dereference a null pointer here
|
||||
HbrHierarchicalEdit<T>* p = *face->GetHierarchicalEdits();
|
||||
if (!p) return false;
|
||||
|
||||
if (this == p) return true;
|
||||
|
||||
if (faceid != p->faceid) return false;
|
||||
|
||||
// If our path length is less than the face depth, it should mean
|
||||
// that we're dealing with another face somewhere up the path, so
|
||||
// we're not relevant
|
||||
if (nsubfaces < face->GetDepth()) return false;
|
||||
|
||||
if (memcmp(subfaces, p->subfaces, face->GetDepth() * sizeof(unsigned char)) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRHIERARCHICALEDIT_H */
|
||||
74
src/osd/opensubdiv/hbr/holeEdit.h
Normal file
74
src/osd/opensubdiv/hbr/holeEdit.h
Normal file
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRHOLEEDIT_H
|
||||
#define OPENSUBDIV3_HBRHOLEEDIT_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrHoleEdit;
|
||||
|
||||
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]) << ' ';
|
||||
}
|
||||
return out << ")";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class HbrHoleEdit : public HbrHierarchicalEdit<T> {
|
||||
|
||||
public:
|
||||
|
||||
HbrHoleEdit(int _faceid, int _nsubfaces, unsigned char *_subfaces)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces) {
|
||||
}
|
||||
|
||||
HbrHoleEdit(int _faceid, int _nsubfaces, int *_subfaces)
|
||||
: HbrHierarchicalEdit<T>(_faceid, _nsubfaces, _subfaces) {
|
||||
}
|
||||
|
||||
virtual ~HbrHoleEdit() {}
|
||||
|
||||
friend std::ostream& operator<< <T> (std::ostream& out, const HbrHoleEdit<T>& path);
|
||||
|
||||
virtual void ApplyEditToFace(HbrFace<T>* face) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
|
||||
face->SetHole();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRHOLEEDIT_H */
|
||||
979
src/osd/opensubdiv/hbr/loop.h
Normal file
979
src/osd/opensubdiv/hbr/loop.h
Normal file
@@ -0,0 +1,979 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRLOOP_H
|
||||
#define OPENSUBDIV3_HBRLOOP_H
|
||||
|
||||
#include <cmath>
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../hbr/subdivision.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
/* #define HBR_DEBUG */
|
||||
|
||||
template <class T>
|
||||
class HbrLoopSubdivision : public HbrSubdivision<T>{
|
||||
public:
|
||||
HbrLoopSubdivision<T>()
|
||||
: HbrSubdivision<T>() {}
|
||||
|
||||
virtual HbrSubdivision<T>* Clone() const {
|
||||
return new HbrLoopSubdivision<T>();
|
||||
}
|
||||
|
||||
virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face);
|
||||
virtual HbrFace<T>* RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex);
|
||||
virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
|
||||
virtual void GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
||||
|
||||
virtual bool HasLimit(HbrMesh<T>* mesh, HbrFace<T>* face);
|
||||
virtual bool HasLimit(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
|
||||
virtual bool HasLimit(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
||||
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face);
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge);
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
||||
|
||||
virtual bool VertexIsExtraordinary(HbrMesh<T> const * /* mesh */, HbrVertex<T>* vertex) { return vertex->GetValence() != 6; }
|
||||
virtual bool FaceIsExtraordinary(HbrMesh<T> const * /* mesh */, HbrFace<T>* face) { return face->GetNumVertices() != 3; }
|
||||
|
||||
virtual int GetFaceChildrenCount(int /* nvertices */) const { return 4; }
|
||||
|
||||
private:
|
||||
|
||||
// Transfers facevarying data from a parent face to a child face
|
||||
void transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, HbrFace<T>* child, int index);
|
||||
|
||||
// Transfers vertex and edge edits from a parent face to a child face
|
||||
void transferEditsToChild(HbrFace<T>* face, HbrFace<T>* child, int index);
|
||||
|
||||
// Generates the fourth child of a triangle: the triangle in the
|
||||
// middle whose vertices have parents which are all edges
|
||||
void refineFaceAtMiddle(HbrMesh<T>* mesh, HbrFace<T>* face);
|
||||
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrLoopSubdivision<T>::transferFVarToChild(HbrMesh<T>* mesh, HbrFace<T>* face, HbrFace<T>* child, int index) {
|
||||
typename HbrMesh<T>::InterpolateBoundaryMethod fvarinterp = mesh->GetFVarInterpolateBoundaryMethod();
|
||||
HbrVertex<T>* childVertex;
|
||||
|
||||
// In the case of index == 3, this is the middle face, and so
|
||||
// we need to do three edge subdivision rules
|
||||
if (index == 3) {
|
||||
const int fvarcount = mesh->GetFVarCount();
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
HbrHalfedge<T> *edge = face->GetEdge(i);
|
||||
GuaranteeNeighbor(mesh, edge);
|
||||
childVertex = child->GetVertex((i + 2) % 3);
|
||||
bool fvIsSmooth = !edge->IsFVarInfiniteSharpAnywhere();
|
||||
if (!fvIsSmooth) {
|
||||
childVertex->NewFVarData(child);
|
||||
}
|
||||
HbrFVarData<T>& fv = childVertex->GetFVarData(child);
|
||||
int fvarindex = 0;
|
||||
for (int fvaritem = 0; fvaritem < fvarcount; ++fvaritem) {
|
||||
const int fvarwidth = mesh->GetFVarWidths()[fvaritem];
|
||||
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
|
||||
face->GetEdge(i)->GetFVarSharpness(fvaritem) || face->GetEdge(i)->IsBoundary()) {
|
||||
|
||||
// Sharp edge rule
|
||||
fv.SetWithWeight(face->GetFVarData(i), fvarindex, fvarwidth, 0.5f);
|
||||
fv.AddWithWeight(face->GetFVarData((i + 1) % 3), fvarindex, fvarwidth, 0.5f);
|
||||
} else if (!fvIsSmooth || !fv.IsInitialized()) {
|
||||
// Smooth edge subdivision. Add 0.375 of adjacent vertices
|
||||
fv.SetWithWeight(face->GetFVarData(i), fvarindex, fvarwidth, 0.375f);
|
||||
fv.AddWithWeight(face->GetFVarData((i + 1) % 3), fvarindex, fvarwidth, 0.375f);
|
||||
// Add 0.125 of opposite vertices
|
||||
fv.AddWithWeight(face->GetFVarData((i + 2) % 3), fvarindex, fvarwidth, 0.125f);
|
||||
HbrFace<T>* oppFace = face->GetEdge(i)->GetRightFace();
|
||||
for (int j = 0; j < oppFace->GetNumVertices(); ++j) {
|
||||
if (oppFace->GetVertex(j) == face->GetVertex(i)) {
|
||||
fv.AddWithWeight(oppFace->GetFVarData((j+1)%oppFace->GetNumVertices()), fvarindex, fvarwidth, 0.125f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fvarindex += fvarwidth;
|
||||
}
|
||||
fv.SetInitialized();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
HbrHalfedge<T>* edge;
|
||||
HbrVertex<T>* v = face->GetVertex(index);
|
||||
|
||||
// Otherwise we proceed with one vertex and two edge subdivision
|
||||
// applications. First the vertex subdivision rule. Analyze
|
||||
// whether the vertex is on the boundary and whether it's an
|
||||
// infinitely sharp corner. We determine the last by checking the
|
||||
// propagate corners flag on the mesh; if it's off, we check the
|
||||
// two edges of this face incident to that vertex and determining
|
||||
// whether they are facevarying boundary edges - this is analogous
|
||||
// to what goes on for the interpolateboundary tag (which when set
|
||||
// to EDGEANDCORNER marks vertices with a valence of two as being
|
||||
// sharp corners). If propagate corners is on, we check *all*
|
||||
// faces to see if two edges side by side are facevarying boundary
|
||||
// edges. The facevarying boundary check ignores geometric
|
||||
// sharpness, otherwise we may swim at geometric creases which
|
||||
// aren't actually discontinuous.
|
||||
//
|
||||
// We need to make sure that that each of the vertices of the
|
||||
// child face have the appropriate facevarying storage as
|
||||
// needed. If there are discontinuities in any facevarying datum,
|
||||
// the vertex must allocate a new block of facevarying storage
|
||||
// specific to the child face.
|
||||
|
||||
v->GuaranteeNeighbors();
|
||||
|
||||
|
||||
bool fv0IsSmooth, fv1IsSmooth, fv2IsSmooth;
|
||||
|
||||
childVertex = child->GetVertex(index);
|
||||
fv0IsSmooth = v->IsFVarAllSmooth();
|
||||
if (!fv0IsSmooth) {
|
||||
childVertex->NewFVarData(child);
|
||||
}
|
||||
HbrFVarData<T>& fv0 = childVertex->GetFVarData(child);
|
||||
|
||||
edge = face->GetEdge(index);
|
||||
GuaranteeNeighbor(mesh, edge);
|
||||
assert(edge->GetOrgVertex() == v);
|
||||
childVertex = child->GetVertex((index + 1) % 3);
|
||||
fv1IsSmooth = !edge->IsFVarInfiniteSharpAnywhere();
|
||||
if (!fv1IsSmooth) {
|
||||
childVertex->NewFVarData(child);
|
||||
}
|
||||
HbrFVarData<T>& fv1 = childVertex->GetFVarData(child);
|
||||
|
||||
edge = edge->GetPrev();
|
||||
GuaranteeNeighbor(mesh, edge);
|
||||
assert(edge == face->GetEdge((index + 2) % 3));
|
||||
assert(edge->GetDestVertex() == v);
|
||||
childVertex = child->GetVertex((index + 2) % 3);
|
||||
fv2IsSmooth = !edge->IsFVarInfiniteSharpAnywhere();
|
||||
if (!fv2IsSmooth) {
|
||||
childVertex->NewFVarData(child);
|
||||
}
|
||||
HbrFVarData<T>& fv2 = childVertex->GetFVarData(child);
|
||||
|
||||
const int fvarcount = mesh->GetFVarCount();
|
||||
int fvarindex = 0;
|
||||
for (int fvaritem = 0; fvaritem < fvarcount; ++fvaritem) {
|
||||
bool infcorner = false;
|
||||
const int fvarwidth = mesh->GetFVarWidths()[fvaritem];
|
||||
const char fvarmask = v->GetFVarMask(fvaritem);
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryEdgeAndCorner) {
|
||||
if (fvarmask >= HbrVertex<T>::k_Corner) {
|
||||
infcorner = true;
|
||||
} else if (mesh->GetFVarPropagateCorners()) {
|
||||
if (v->IsFVarCorner(fvaritem)) {
|
||||
infcorner = true;
|
||||
}
|
||||
} else {
|
||||
if (face->GetEdge(index)->GetFVarSharpness(fvaritem, true) && face->GetEdge(index)->GetPrev()->GetFVarSharpness(fvaritem, true)) {
|
||||
infcorner = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Infinitely sharp vertex rule. Applied if the vertex is:
|
||||
// - undergoing no facevarying boundary interpolation;
|
||||
// - at a geometric crease, in either boundary interpolation case; or
|
||||
// - is an infinitely sharp facevarying vertex, in the EDGEANDCORNER case; or
|
||||
// - has a mask equal or greater than one, in the "always
|
||||
// sharp" interpolate boundary case
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
|
||||
(fvarinterp == HbrMesh<T>::k_InterpolateBoundaryAlwaysSharp &&
|
||||
fvarmask >= 1) ||
|
||||
v->GetSharpness() > HbrVertex<T>::k_Smooth ||
|
||||
infcorner) {
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 1.0f);
|
||||
}
|
||||
// Dart rule: unlike geometric creases, because there's two
|
||||
// discontinuous values for the one incident edge, we use the
|
||||
// boundary rule and not the smooth rule
|
||||
else if (fvarmask == 1) {
|
||||
// Use 0.75 of the current vert
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.75f);
|
||||
|
||||
// 0.125 of "two adjacent edge vertices", which in actuality
|
||||
// are the facevarying values of the same vertex but on each
|
||||
// side of the single incident facevarying sharp edge
|
||||
HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge, *nextedge;
|
||||
edge = start;
|
||||
while (edge) {
|
||||
if (edge->GetFVarSharpness(fvaritem)) {
|
||||
break;
|
||||
}
|
||||
nextedge = v->GetNextEdge(edge);
|
||||
if (nextedge == start) {
|
||||
assert(0); // we should have found it by now
|
||||
break;
|
||||
} else if (!nextedge) {
|
||||
// should never get into this case - if the vertex is
|
||||
// on a boundary, it can never be a facevarying dart
|
||||
// vertex
|
||||
assert(0);
|
||||
edge = edge->GetPrev();
|
||||
break;
|
||||
} else {
|
||||
edge = nextedge;
|
||||
}
|
||||
}
|
||||
HbrVertex<T>* w = edge->GetDestVertex();
|
||||
HbrFace<T>* bestface = edge->GetLeftFace();
|
||||
int j;
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
bestface = edge->GetRightFace();
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
}
|
||||
// Boundary vertex rule (can use FVarSmooth, which is equivalent
|
||||
// to checking that it's sharper than a dart)
|
||||
else if (fvarmask != 0) {
|
||||
|
||||
// Use 0.75 of the current vert
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.75f);
|
||||
|
||||
// Compute 0.125 of two adjacent edge vertices. However the
|
||||
// two adjacent edge vertices we use must be part of the
|
||||
// facevarying "boundary". To find the first edge we cycle
|
||||
// counterclockwise around the current vertex v and look for
|
||||
// the first boundary edge
|
||||
|
||||
HbrFace<T>* bestface = face;
|
||||
HbrHalfedge<T>* bestedge = face->GetEdge(index)->GetPrev();
|
||||
HbrHalfedge<T>* starte = bestedge->GetOpposite();
|
||||
HbrVertex<T>* w = 0;
|
||||
if (!starte) {
|
||||
w = face->GetEdge(index)->GetPrev()->GetOrgVertex();
|
||||
} else {
|
||||
HbrHalfedge<T>* e = starte, *next;
|
||||
assert(starte->GetOrgVertex() == v);
|
||||
do {
|
||||
if (e->GetFVarSharpness(fvaritem) || !e->GetLeftFace()) {
|
||||
bestface = e->GetRightFace();
|
||||
bestedge = e;
|
||||
break;
|
||||
}
|
||||
next = v->GetNextEdge(e);
|
||||
if (!next) {
|
||||
bestface = e->GetLeftFace();
|
||||
w = e->GetPrev()->GetOrgVertex();
|
||||
break;
|
||||
}
|
||||
e = next;
|
||||
} while (e && e != starte);
|
||||
}
|
||||
if (!w) w = bestedge->GetDestVertex();
|
||||
int j;
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
|
||||
// Look for the other edge by cycling clockwise around v
|
||||
bestface = face;
|
||||
bestedge = face->GetEdge(index);
|
||||
starte = bestedge;
|
||||
w = 0;
|
||||
if (HbrHalfedge<T>* e = starte) {
|
||||
assert(starte->GetOrgVertex() == v);
|
||||
do {
|
||||
if (e->GetFVarSharpness(fvaritem) || !e->GetRightFace()) {
|
||||
bestface = e->GetLeftFace();
|
||||
bestedge = e;
|
||||
break;
|
||||
}
|
||||
assert(e->GetOpposite());
|
||||
e = v->GetPreviousEdge(e);
|
||||
} while (e && e != starte);
|
||||
}
|
||||
if (!w) w = bestedge->GetDestVertex();
|
||||
for (j = 0; j < bestface->GetNumVertices(); ++j) {
|
||||
if (bestface->GetVertex(j) == w) break;
|
||||
}
|
||||
assert(j != bestface->GetNumVertices());
|
||||
fv0.AddWithWeight(bestface->GetFVarData(j), fvarindex, fvarwidth, 0.125f);
|
||||
|
||||
}
|
||||
// Smooth rule
|
||||
else if (!fv0IsSmooth || !fv0.IsInitialized()) {
|
||||
int valence = v->GetValence();
|
||||
float invvalence = 1.0f / valence;
|
||||
float beta = 0.25f * cosf((float)M_PI * 2.0f * invvalence) + 0.375f;
|
||||
beta = beta * beta;
|
||||
beta = (0.625f - beta) * invvalence;
|
||||
|
||||
// Use 1 - beta * valence of the current vertex value
|
||||
fv0.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 1 - (beta * valence));
|
||||
|
||||
// Add beta of surrounding vertices averages. We loop over all
|
||||
// surrounding faces..
|
||||
HbrHalfedge<T>* start = v->GetIncidentEdge(), *edge;
|
||||
edge = start;
|
||||
while (edge) {
|
||||
HbrFace<T>* g = edge->GetLeftFace();
|
||||
|
||||
// .. and look for the edge on that face whose origin is
|
||||
// the same as v, and add a contribution from its
|
||||
// destination vertex value; this takes care of the
|
||||
// surrounding edge vertex addition.
|
||||
for (int j = 0; j < g->GetNumVertices(); ++j) {
|
||||
if (g->GetEdge(j)->GetOrgVertex() == v) {
|
||||
fv0.AddWithWeight(g->GetFVarData((j + 1) % g->GetNumVertices()), fvarindex, fvarwidth, beta);
|
||||
break;
|
||||
}
|
||||
}
|
||||
edge = v->GetNextEdge(edge);
|
||||
if (edge == start) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Edge subdivision rule
|
||||
HbrHalfedge<T>* edge = face->GetEdge(index);
|
||||
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
|
||||
edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) {
|
||||
|
||||
// Sharp edge rule
|
||||
fv1.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f);
|
||||
fv1.AddWithWeight(face->GetFVarData((index + 1) % 3), fvarindex, fvarwidth, 0.5f);
|
||||
} else if (!fv1IsSmooth || !fv1.IsInitialized()) {
|
||||
// Smooth edge subdivision. Add 0.375 of adjacent vertices
|
||||
fv1.SetWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.375f);
|
||||
fv1.AddWithWeight(face->GetFVarData((index + 1) % 3), fvarindex, fvarwidth, 0.375f);
|
||||
// Add 0.125 of opposite vertices
|
||||
fv1.AddWithWeight(face->GetFVarData((index + 2) % 3), fvarindex, fvarwidth, 0.125f);
|
||||
HbrFace<T>* oppFace = edge->GetRightFace();
|
||||
for (int j = 0; j < oppFace->GetNumVertices(); ++j) {
|
||||
if (oppFace->GetVertex(j) == v) {
|
||||
fv1.AddWithWeight(oppFace->GetFVarData((j+1)%oppFace->GetNumVertices()), fvarindex, fvarwidth, 0.125f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Edge subdivision rule
|
||||
edge = edge->GetPrev();
|
||||
|
||||
if (fvarinterp == HbrMesh<T>::k_InterpolateBoundaryNone ||
|
||||
edge->GetFVarSharpness(fvaritem) || edge->IsBoundary()) {
|
||||
|
||||
// Sharp edge rule
|
||||
fv2.SetWithWeight(face->GetFVarData((index + 2) % 3), fvarindex, fvarwidth, 0.5f);
|
||||
fv2.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.5f);
|
||||
} else if (!fv2IsSmooth || !fv2.IsInitialized()) {
|
||||
// Smooth edge subdivision. Add 0.375 of adjacent vertices
|
||||
fv2.SetWithWeight(face->GetFVarData((index + 2) % 3), fvarindex, fvarwidth, 0.375f);
|
||||
fv2.AddWithWeight(face->GetFVarData(index), fvarindex, fvarwidth, 0.375f);
|
||||
// Add 0.125 of opposite vertices
|
||||
fv2.AddWithWeight(face->GetFVarData((index + 1) % 3), fvarindex, fvarwidth, 0.125f);
|
||||
|
||||
HbrFace<T>* oppFace = edge->GetRightFace();
|
||||
for (int j = 0; j < oppFace->GetNumVertices(); ++j) {
|
||||
if (oppFace->GetVertex(j) == v) {
|
||||
fv2.AddWithWeight(oppFace->GetFVarData((j+2)%oppFace->GetNumVertices()), fvarindex, fvarwidth, 0.125f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fvarindex += fvarwidth;
|
||||
}
|
||||
fv0.SetInitialized();
|
||||
fv1.SetInitialized();
|
||||
fv2.SetInitialized();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrLoopSubdivision<T>::transferEditsToChild(HbrFace<T>* face, HbrFace<T>* child, int index) {
|
||||
|
||||
// Hand down hole tag
|
||||
child->SetHole(face->IsHole());
|
||||
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrLoopSubdivision<T>::Refine(HbrMesh<T>* mesh, HbrFace<T>* face) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "\n\nRefining face " << *face << "\n";
|
||||
#endif
|
||||
|
||||
assert(face->GetNumVertices() == 3); // or triangulate it?
|
||||
|
||||
HbrHalfedge<T>* edge = face->GetFirstEdge();
|
||||
HbrHalfedge<T>* prevedge = edge->GetPrev();
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
HbrVertex<T>* vertex = edge->GetOrgVertex();
|
||||
if (!face->GetChild(i)) {
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Kid " << i << "\n";
|
||||
#endif
|
||||
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);
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Creating face " << *child << " during refine\n";
|
||||
#endif
|
||||
|
||||
// Hand down edge sharpness
|
||||
float sharpness;
|
||||
HbrHalfedge<T>* childedge;
|
||||
|
||||
childedge = child->GetEdge(i);
|
||||
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(
|
||||
edge, edge->GetOrgVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(edge);
|
||||
|
||||
childedge = child->GetEdge((i+2)%3);
|
||||
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(
|
||||
prevedge, prevedge->GetDestVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(prevedge);
|
||||
|
||||
if (mesh->GetTotalFVarWidth()) {
|
||||
transferFVarToChild(mesh, face, child, i);
|
||||
}
|
||||
|
||||
transferEditsToChild(face, child, i);
|
||||
|
||||
}
|
||||
prevedge = edge;
|
||||
edge = edge->GetNext();
|
||||
}
|
||||
|
||||
refineFaceAtMiddle(mesh, face);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrFace<T>*
|
||||
HbrLoopSubdivision<T>::RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " forcing refine on " << *face << " at " << *vertex << '\n';
|
||||
#endif
|
||||
HbrHalfedge<T>* edge = face->GetFirstEdge();
|
||||
HbrHalfedge<T>* prevedge = edge->GetPrev();
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (edge->GetOrgVertex() == vertex) {
|
||||
if (!face->GetChild(i)) {
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Kid " << i << "\n";
|
||||
#endif
|
||||
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);
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Creating face " << *child << " during refine\n";
|
||||
#endif
|
||||
|
||||
// Hand down edge sharpness
|
||||
float sharpness;
|
||||
HbrHalfedge<T>* childedge;
|
||||
|
||||
childedge = child->GetEdge(i);
|
||||
if ((sharpness = edge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(
|
||||
edge, edge->GetOrgVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(edge);
|
||||
|
||||
childedge = child->GetEdge((i+2)%3);
|
||||
if ((sharpness = prevedge->GetSharpness()) > HbrHalfedge<T>::k_Smooth) {
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(
|
||||
prevedge, prevedge->GetDestVertex(), childedge);
|
||||
}
|
||||
childedge->CopyFVarInfiniteSharpness(prevedge);
|
||||
|
||||
if (mesh->GetTotalFVarWidth()) {
|
||||
transferFVarToChild(mesh, face, child, i);
|
||||
}
|
||||
|
||||
transferEditsToChild(face, child, i);
|
||||
|
||||
return child;
|
||||
} else {
|
||||
return face->GetChild(i);
|
||||
}
|
||||
}
|
||||
prevedge = edge;
|
||||
edge = edge->GetNext();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrLoopSubdivision<T>::GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
|
||||
if (edge->GetOpposite()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "\n\nneighbor guarantee at " << *edge << " invoked\n";
|
||||
#endif
|
||||
|
||||
/*
|
||||
Imagine the following:
|
||||
|
||||
X
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
X \
|
||||
/\ \
|
||||
2/ \3 \
|
||||
/ \ \
|
||||
X------X--------X
|
||||
1
|
||||
|
||||
If the parent of _both_ incident vertices are themselves edges,
|
||||
(like the edge marked 3 above), then this edge is in the center
|
||||
of the parent face. Refining the parent face in the middle or
|
||||
refining the parent face at one vertex (where the two parent
|
||||
edges meet) should suffice
|
||||
*/
|
||||
HbrHalfedge<T>* parentEdge1 = edge->GetOrgVertex()->GetParentEdge();
|
||||
HbrHalfedge<T>* parentEdge2 = edge->GetDestVertex()->GetParentEdge();
|
||||
if (parentEdge1 && parentEdge2) {
|
||||
#ifdef HBR_DEBUG
|
||||
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;
|
||||
}
|
||||
|
||||
// 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";
|
||||
#endif
|
||||
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";
|
||||
#endif
|
||||
HbrVertex<T>* parentVertex1 = edge->GetOrgVertex()->GetParentVertex();
|
||||
assert(parentVertex1);
|
||||
RefineFaceAtVertex(mesh, parentEdge2->GetLeftFace(), parentVertex1);
|
||||
if (parentEdge2->GetRightFace()) {
|
||||
RefineFaceAtVertex(mesh, parentEdge2->GetRightFace(), parentVertex1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrLoopSubdivision<T>::GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "\n\nneighbor guarantee at " << *vertex << " invoked\n";
|
||||
#endif
|
||||
|
||||
assert(vertex->GetParentFace() == 0);
|
||||
|
||||
// The first case: the vertex is a child of an edge. Make sure
|
||||
// that the parent faces on either side of the parent edge exist,
|
||||
// and have 1) refined at both vertices of the parent edge, and 2)
|
||||
// have refined their "middle" face (which doesn't live at either
|
||||
// vertex).
|
||||
|
||||
HbrHalfedge<T>* parentEdge = vertex->GetParentEdge();
|
||||
if (parentEdge) {
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "parent edge situation " << *parentEdge << "\n";
|
||||
#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;
|
||||
}
|
||||
|
||||
// The second case: the vertex is a child of a vertex. In this case
|
||||
// we have to recursively guarantee that the parent's adjacent
|
||||
// faces also exist.
|
||||
HbrVertex<T>* parentVertex = vertex->GetParentVertex();
|
||||
if (parentVertex) {
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "parent vertex situation " << *parentVertex << "\n";
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
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;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
if (edge->GetSharpness() >= HbrHalfedge<T>::k_InfinitelySharp) return true;
|
||||
|
||||
if (!HasLimit(mesh, edge->GetOrgVertex()) || !HasLimit(mesh, edge->GetDestVertex())) return false;
|
||||
|
||||
return !edge->IsBoundary();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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
|
||||
HbrHalfedge<T>* start = vertex->GetIncidentEdge(), *edge, *next;
|
||||
edge = start;
|
||||
while (edge) {
|
||||
if (edge->IsBoundary() && edge->GetSharpness() < HbrHalfedge<T>::k_InfinitelySharp) {
|
||||
return false;
|
||||
}
|
||||
next = vertex->GetNextEdge(edge);
|
||||
if (next == start) {
|
||||
break;
|
||||
} else if (!next) {
|
||||
edge = edge->GetPrev();
|
||||
if (edge->IsBoundary() && edge->GetSharpness() < HbrHalfedge<T>::k_InfinitelySharp) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
edge = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrLoopSubdivision<T>::Subdivide(HbrMesh<T>* /* mesh */, HbrFace<T>* /* face */) {
|
||||
// In loop subdivision, faces never subdivide
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrLoopSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Subdividing at " << *edge << "\n";
|
||||
#endif
|
||||
// Ensure the opposite face exists.
|
||||
GuaranteeNeighbor(mesh, edge);
|
||||
|
||||
float esharp = edge->GetSharpness();
|
||||
HbrVertex<T>* v = mesh->NewVertex();
|
||||
T& data = v->GetData();
|
||||
|
||||
// If there's the possibility of vertex edits on either vertex, we
|
||||
// have to make sure the edit has been applied
|
||||
if (mesh->HasVertexEdits()) {
|
||||
edge->GetOrgVertex()->GuaranteeNeighbors();
|
||||
edge->GetDestVertex()->GuaranteeNeighbors();
|
||||
}
|
||||
|
||||
if (!edge->IsBoundary() && esharp <= 1.0f) {
|
||||
|
||||
// Of the two half-edges, pick one of them consistently such
|
||||
// that the org and dest vertices are also consistent through
|
||||
// multi-threading. It doesn't matter as far as the
|
||||
// theoretical calculation is concerned, but it is desirable
|
||||
// to be consistent about it in the face of the limitations of
|
||||
// floating point commutativity. So we always pick the
|
||||
// half-edge such that its incident face is the smallest of
|
||||
// the two faces, as far as the face paths are concerned.
|
||||
if (edge->GetOpposite() && edge->GetOpposite()->GetFace()->GetPath() < edge->GetFace()->GetPath()) {
|
||||
edge = edge->GetOpposite();
|
||||
}
|
||||
|
||||
// Handle both the smooth and fractional sharpness cases. We
|
||||
// lerp between the sharp case (average of the two end points)
|
||||
// and the unsharp case (3/8 of each of the two end points
|
||||
// plus 1/8 of the two opposite face averages).
|
||||
|
||||
// Lerp end point weight between non sharp contribution of
|
||||
// 3/8 and the sharp contribution of 0.5.
|
||||
float endPtWeight = 0.375f + esharp * (0.5f - 0.375f);
|
||||
data.AddWithWeight(edge->GetOrgVertex()->GetData(), endPtWeight);
|
||||
data.AddWithWeight(edge->GetDestVertex()->GetData(), endPtWeight);
|
||||
|
||||
// Lerp the opposite pt weights between non sharp contribution
|
||||
// of 1/8 and the sharp contribution of 0.
|
||||
float oppPtWeight = 0.125f * (1 - esharp);
|
||||
HbrHalfedge<T>* ee = edge->GetNext();
|
||||
data.AddWithWeight(ee->GetDestVertex()->GetData(), oppPtWeight);
|
||||
ee = edge->GetOpposite()->GetNext();
|
||||
data.AddWithWeight(ee->GetDestVertex()->GetData(), oppPtWeight);
|
||||
} else {
|
||||
// Fully sharp edge, just average the two end points
|
||||
data.AddWithWeight(edge->GetOrgVertex()->GetData(), 0.5f);
|
||||
data.AddWithWeight(edge->GetDestVertex()->GetData(), 0.5f);
|
||||
}
|
||||
|
||||
// Varying data is always the average of two end points
|
||||
data.AddVaryingWithWeight(edge->GetOrgVertex()->GetData(), 0.5f);
|
||||
data.AddVaryingWithWeight(edge->GetDestVertex()->GetData(), 0.5f);
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << " created " << *v << "\n";
|
||||
#endif
|
||||
|
||||
// Only boundary edges will create extraordinary vertices
|
||||
if (edge->IsBoundary()) {
|
||||
v->SetExtraordinary();
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HbrVertex<T>*
|
||||
HbrLoopSubdivision<T>::Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
|
||||
|
||||
// Ensure the ring of faces around this vertex exists before
|
||||
// we compute the valence
|
||||
vertex->GuaranteeNeighbors();
|
||||
|
||||
float valence = static_cast<float>(vertex->GetValence());
|
||||
float invvalence = 1.0f / valence;
|
||||
|
||||
HbrVertex<T>* v = mesh->NewVertex();
|
||||
T& data = v->GetData();
|
||||
|
||||
// Due to fractional weights we may need to do two subdivision
|
||||
// passes
|
||||
int masks[2];
|
||||
float weights[2];
|
||||
int passes;
|
||||
masks[0] = vertex->GetMask(false);
|
||||
masks[1] = vertex->GetMask(true);
|
||||
// If the masks are different, we subdivide twice: once using the
|
||||
// current mask, once using the mask at the next level of
|
||||
// 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;
|
||||
} else {
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Varying data is always just propagated down
|
||||
data.AddVaryingWithWeight(vertex->GetData(), 1.0f);
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Subdividing at " << *vertex << "\n";
|
||||
std::cerr << " created " << *v << "\n";
|
||||
#endif
|
||||
// Inherit extraordinary flag and sharpness
|
||||
if (vertex->IsExtraordinary()) v->SetExtraordinary();
|
||||
float sharp = vertex->GetSharpness();
|
||||
if (sharp >= HbrVertex<T>::k_InfinitelySharp) {
|
||||
v->SetSharpness(HbrVertex<T>::k_InfinitelySharp);
|
||||
} else if (sharp > HbrVertex<T>::k_Smooth) {
|
||||
v->SetSharpness(std::max((float) HbrVertex<T>::k_Smooth, sharp - 1.0f));
|
||||
} else {
|
||||
v->SetSharpness(HbrVertex<T>::k_Smooth);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrLoopSubdivision<T>::refineFaceAtMiddle(HbrMesh<T>* mesh, HbrFace<T>* face) {
|
||||
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Refining middle face of " << *face << "\n";
|
||||
#endif
|
||||
|
||||
if (!face->GetChild(3)) {
|
||||
HbrFace<T>* child;
|
||||
HbrVertex<T>* vertices[3];
|
||||
|
||||
// The fourth face is not an obvious child of any vertex. We
|
||||
// assign it index 3 despite there being no fourth vertex in
|
||||
// the triangle. The ordering of vertices here is done to
|
||||
// preserve parametric space as best we can
|
||||
vertices[0] = face->GetEdge(1)->Subdivide();
|
||||
vertices[1] = face->GetEdge(2)->Subdivide();
|
||||
vertices[2] = face->GetEdge(0)->Subdivide();
|
||||
child = mesh->NewFace(3, vertices, face, 3);
|
||||
#ifdef HBR_DEBUG
|
||||
std::cerr << "Creating face " << *child << "\n";
|
||||
#endif
|
||||
if (mesh->GetTotalFVarWidth()) {
|
||||
transferFVarToChild(mesh, face, child, 3);
|
||||
}
|
||||
|
||||
transferEditsToChild(face, child, 3);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRLOOP_H */
|
||||
1012
src/osd/opensubdiv/hbr/mesh.h
Normal file
1012
src/osd/opensubdiv/hbr/mesh.h
Normal file
File diff suppressed because it is too large
Load Diff
293
src/osd/opensubdiv/hbr/subdivision.h
Normal file
293
src/osd/opensubdiv/hbr/subdivision.h
Normal file
@@ -0,0 +1,293 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRSUBDIVISION_H
|
||||
#define OPENSUBDIV3_HBRSUBDIVISION_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrFace;
|
||||
template <class T> class HbrVertex;
|
||||
template <class T> class HbrHalfedge;
|
||||
template <class T> class HbrMesh;
|
||||
template <class T> class HbrSubdivision {
|
||||
public:
|
||||
HbrSubdivision<T>()
|
||||
: creaseSubdivision(k_CreaseNormal) {}
|
||||
|
||||
virtual ~HbrSubdivision<T>() {}
|
||||
|
||||
virtual HbrSubdivision<T>* Clone() const = 0;
|
||||
|
||||
// How to subdivide a face
|
||||
virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face) = 0;
|
||||
|
||||
// Subdivide a face only at a particular vertex (creating one child)
|
||||
virtual HbrFace<T>* RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex) = 0;
|
||||
|
||||
// Refine all faces around a particular vertex
|
||||
virtual void RefineAtVertex(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
||||
|
||||
// Given an edge, try to ensure the edge's opposite exists by
|
||||
// forcing refinement up the hierarchy
|
||||
virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) = 0;
|
||||
|
||||
// Given an vertex, ensure all faces in the ring around it exist
|
||||
// by forcing refinement up the hierarchy
|
||||
virtual void GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex) = 0;
|
||||
|
||||
// Returns true if the vertex, edge, or face has a limit point,
|
||||
// curve, or surface associated with it
|
||||
virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrFace<T>* /* face */) { return true; }
|
||||
virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrHalfedge<T>* /* edge */) { return true; }
|
||||
virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrVertex<T>* /* vertex */) { return true; }
|
||||
|
||||
// How to turn faces, edges, and vertices into vertices
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) = 0;
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) = 0;
|
||||
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) = 0;
|
||||
|
||||
// Returns true if the vertex is extraordinary in the subdivision scheme
|
||||
virtual bool VertexIsExtraordinary(HbrMesh<T> const * /* mesh */, HbrVertex<T>* /* vertex */) { return false; }
|
||||
|
||||
// Returns true if the face is extraordinary in the subdivision scheme
|
||||
virtual bool FaceIsExtraordinary(HbrMesh<T> const * /* 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
|
||||
// is to simply assign the current edge's crease strength - 1
|
||||
// to both of the child subedges. The "Chaikin" rule looks at the
|
||||
// current edge and incident edges to the current edge's end
|
||||
// vertices, and weighs them; for more information consult
|
||||
// the Geri's Game paper.
|
||||
enum CreaseSubdivision {
|
||||
k_CreaseNormal,
|
||||
k_CreaseChaikin
|
||||
};
|
||||
CreaseSubdivision GetCreaseSubdivisionMethod() const { return creaseSubdivision; }
|
||||
void SetCreaseSubdivisionMethod(CreaseSubdivision method) { creaseSubdivision = method; }
|
||||
|
||||
// Figures out how to assign a crease weight on an edge to its
|
||||
// subedge. The subedge must be a child of the parent edge
|
||||
// (either subedge->GetOrgVertex() or subedge->GetDestVertex()
|
||||
// == edge->Subdivide()). The vertex supplied must NOT be
|
||||
// a parent of the subedge; it is either the origin or
|
||||
// destination vertex of edge.
|
||||
void SubdivideCreaseWeight(HbrHalfedge<T>* edge, HbrVertex<T>* vertex, HbrHalfedge<T>* subedge);
|
||||
|
||||
// Returns the expected number of children faces after subdivision
|
||||
// for a face with the given number of vertices.
|
||||
virtual int GetFaceChildrenCount(int nvertices) const = 0;
|
||||
|
||||
protected:
|
||||
CreaseSubdivision creaseSubdivision;
|
||||
|
||||
// Helper routine for subclasses: for a given vertex, sums
|
||||
// contributions from surrounding vertices
|
||||
void AddSurroundingVerticesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, float weight, T* data);
|
||||
|
||||
// Helper routine for subclasses: for a given vertex with a crease
|
||||
// mask, adds contributions from the two crease edges
|
||||
void AddCreaseEdgesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, bool next, float weight, T* data);
|
||||
|
||||
private:
|
||||
// Helper class used by AddSurroundingVerticesWithWeight
|
||||
class SmoothSubdivisionVertexOperator : public HbrVertexOperator<T> {
|
||||
public:
|
||||
SmoothSubdivisionVertexOperator(T* data, bool meshHasEdits, float weight)
|
||||
: m_data(data),
|
||||
m_meshHasEdits(meshHasEdits),
|
||||
m_weight(weight)
|
||||
{
|
||||
}
|
||||
virtual void operator() (HbrVertex<T> &vertex) {
|
||||
// Must ensure vertex edits have been applied
|
||||
if (m_meshHasEdits) {
|
||||
vertex.GuaranteeNeighbors();
|
||||
}
|
||||
m_data->AddWithWeight(vertex.GetData(), m_weight);
|
||||
}
|
||||
private:
|
||||
T* m_data;
|
||||
const bool m_meshHasEdits;
|
||||
const float m_weight;
|
||||
};
|
||||
|
||||
// Helper class used by AddCreaseEdgesWithWeight
|
||||
class CreaseSubdivisionHalfedgeOperator : public HbrHalfedgeOperator<T> {
|
||||
public:
|
||||
CreaseSubdivisionHalfedgeOperator(HbrVertex<T> *vertex, T* data, bool meshHasEdits, bool next, float weight)
|
||||
: m_vertex(vertex),
|
||||
m_data(data),
|
||||
m_meshHasEdits(meshHasEdits),
|
||||
m_next(next),
|
||||
m_weight(weight),
|
||||
m_count(0)
|
||||
{
|
||||
}
|
||||
virtual void operator() (HbrHalfedge<T> &edge) {
|
||||
if (m_count < 2 && edge.IsSharp(m_next)) {
|
||||
HbrVertex<T>* a = edge.GetDestVertex();
|
||||
if (a == m_vertex) a = edge.GetOrgVertex();
|
||||
// Must ensure vertex edits have been applied
|
||||
if (m_meshHasEdits) {
|
||||
a->GuaranteeNeighbors();
|
||||
}
|
||||
m_data->AddWithWeight(a->GetData(), m_weight);
|
||||
m_count++;
|
||||
}
|
||||
}
|
||||
private:
|
||||
HbrVertex<T>* m_vertex;
|
||||
T* m_data;
|
||||
const bool m_meshHasEdits;
|
||||
const bool m_next;
|
||||
const float m_weight;
|
||||
int m_count;
|
||||
};
|
||||
|
||||
private:
|
||||
// Helper class used by RefineAtVertex.
|
||||
class RefineFaceAtVertexOperator : public HbrFaceOperator<T> {
|
||||
public:
|
||||
RefineFaceAtVertexOperator(HbrSubdivision<T>* subdivision, HbrMesh<T>* mesh, HbrVertex<T> *vertex)
|
||||
: m_subdivision(subdivision),
|
||||
m_mesh(mesh),
|
||||
m_vertex(vertex)
|
||||
{
|
||||
}
|
||||
virtual void operator() (HbrFace<T> &face) {
|
||||
m_subdivision->RefineFaceAtVertex(m_mesh, &face, m_vertex);
|
||||
}
|
||||
private:
|
||||
HbrSubdivision<T>* const m_subdivision;
|
||||
HbrMesh<T>* const m_mesh;
|
||||
HbrVertex<T>* const m_vertex;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrSubdivision<T>::RefineAtVertex(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
|
||||
GuaranteeNeighbors(mesh, vertex);
|
||||
RefineFaceAtVertexOperator op(this, mesh, vertex);
|
||||
vertex->ApplyOperatorSurroundingFaces(op);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrSubdivision<T>::SubdivideCreaseWeight(HbrHalfedge<T>* edge, HbrVertex<T>* vertex, HbrHalfedge<T>* subedge) {
|
||||
|
||||
float sharpness = edge->GetSharpness();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
int n = 0;
|
||||
|
||||
// Add 1/4 of the sharpness of all crease edges incident to
|
||||
// the vertex (other than this crease edge)
|
||||
class ChaikinEdgeCreaseOperator : public HbrHalfedgeOperator<T> {
|
||||
public:
|
||||
|
||||
ChaikinEdgeCreaseOperator(
|
||||
HbrHalfedge<T> const * edge, float & childsharp, int & count) :
|
||||
m_edge(edge), m_childsharp(childsharp), m_count(count) { }
|
||||
|
||||
virtual void operator() (HbrHalfedge<T> &edge) {
|
||||
|
||||
// Skip original edge or it's opposite
|
||||
if ((&edge==m_edge) || (&edge==m_edge->GetOpposite()))
|
||||
return;
|
||||
if (edge.GetSharpness() > HbrHalfedge<T>::k_Smooth) {
|
||||
m_childsharp += edge.GetSharpness();
|
||||
++m_count;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
HbrHalfedge<T> const * m_edge;
|
||||
float & m_childsharp;
|
||||
int & m_count;
|
||||
};
|
||||
|
||||
ChaikinEdgeCreaseOperator op(edge, childsharp, n);
|
||||
vertex->GuaranteeNeighbors();
|
||||
vertex->ApplyOperatorSurroundingEdges(op);
|
||||
|
||||
if (n) {
|
||||
childsharp = childsharp * 0.25f / float(n);
|
||||
}
|
||||
|
||||
// Add 3/4 of the sharpness of this crease edge
|
||||
childsharp += sharpness * 0.75f;
|
||||
childsharp -= 1.0f;
|
||||
if (childsharp < (float) HbrHalfedge<T>::k_Smooth) {
|
||||
childsharp = (float) HbrHalfedge<T>::k_Smooth;
|
||||
}
|
||||
subedge->SetSharpness(childsharp);
|
||||
|
||||
} else {
|
||||
sharpness -= 1.0f;
|
||||
if (sharpness < (float) HbrHalfedge<T>::k_Smooth) {
|
||||
sharpness = (float) HbrHalfedge<T>::k_Smooth;
|
||||
}
|
||||
subedge->SetSharpness(sharpness);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrSubdivision<T>::AddSurroundingVerticesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, float weight, T* data) {
|
||||
SmoothSubdivisionVertexOperator op(data, mesh->HasVertexEdits(), weight);
|
||||
vertex->ApplyOperatorSurroundingVertices(op);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
HbrSubdivision<T>::AddCreaseEdgesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, bool next, float weight, T* data) {
|
||||
CreaseSubdivisionHalfedgeOperator op(vertex, data, mesh->HasVertexEdits(), next, weight);
|
||||
vertex->ApplyOperatorSurroundingEdges(op);
|
||||
}
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRSUBDIVISION_H */
|
||||
1558
src/osd/opensubdiv/hbr/vertex.h
Normal file
1558
src/osd/opensubdiv/hbr/vertex.h
Normal file
File diff suppressed because it is too large
Load Diff
241
src/osd/opensubdiv/hbr/vertexEdit.h
Normal file
241
src/osd/opensubdiv/hbr/vertexEdit.h
Normal file
@@ -0,0 +1,241 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_HBRVERTEXEDIT_H
|
||||
#define OPENSUBDIV3_HBRVERTEXEDIT_H
|
||||
|
||||
#include <algorithm>
|
||||
#include "../hbr/hierarchicalEdit.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
template <class T> class HbrVertexEdit;
|
||||
|
||||
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]) << ' ';
|
||||
}
|
||||
return out << static_cast<int>(path.vertexid) << "), edit = (" << path.edit[0] << ',' << path.edit[1] << ',' << path.edit[2] << ')';
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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));
|
||||
}
|
||||
|
||||
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(static_cast<unsigned char>(_vertexid)), index(_index), width(_width), isP(_isP), op(_op) {
|
||||
edit = new float[width];
|
||||
memcpy(edit, _edit, width * sizeof(float));
|
||||
}
|
||||
|
||||
virtual ~HbrVertexEdit() {
|
||||
delete[] edit;
|
||||
}
|
||||
|
||||
// Return the vertex id (the last element in the path)
|
||||
unsigned char GetVertexID() const { return vertexid; }
|
||||
|
||||
friend std::ostream& operator<< <T> (std::ostream& out, const HbrVertexEdit<T>& path);
|
||||
|
||||
// Return index of variable this edit applies to
|
||||
int GetIndex() const { return index; }
|
||||
|
||||
// Return width of the variable
|
||||
int GetWidth() const { return width; }
|
||||
|
||||
// Get the numerical value of the edit
|
||||
const float* GetEdit() const { return edit; }
|
||||
|
||||
// Get the type of operation
|
||||
typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; }
|
||||
|
||||
virtual void ApplyEditToFace(HbrFace<T>* face) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
|
||||
// Tags the vertex as being edited; it'll figure out what to
|
||||
// when GuaranteeNeighbor is called
|
||||
face->GetVertex(vertexid)->SetVertexEdit();
|
||||
}
|
||||
// In any event, mark the face as having a vertex edit (which
|
||||
// may only be applied on subfaces)
|
||||
face->MarkVertexEdits();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PRMAN
|
||||
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
|
||||
|
||||
private:
|
||||
const unsigned char vertexid;
|
||||
int index;
|
||||
int width;
|
||||
unsigned isP:1;
|
||||
typename HbrHierarchicalEdit<T>::Operation op;
|
||||
float* edit;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
virtual ~HbrMovingVertexEdit() {
|
||||
delete[] edit;
|
||||
}
|
||||
|
||||
// Return the vertex id (the last element in the path)
|
||||
unsigned char GetVertexID() const { return vertexid; }
|
||||
|
||||
friend std::ostream& operator<< <T> (std::ostream& out, const HbrVertexEdit<T>& path);
|
||||
|
||||
// Return index of variable this edit applies to
|
||||
int GetIndex() const { return index; }
|
||||
|
||||
// Return width of the variable
|
||||
int GetWidth() const { return width; }
|
||||
|
||||
// Get the numerical value of the edit
|
||||
const float* GetEdit() const { return edit; }
|
||||
|
||||
// Get the type of operation
|
||||
typename HbrHierarchicalEdit<T>::Operation GetOperation() const { return op; }
|
||||
|
||||
virtual void ApplyEditToFace(HbrFace<T>* face) {
|
||||
if (HbrHierarchicalEdit<T>::GetNSubfaces() == face->GetDepth()) {
|
||||
// Tags the vertex as being edited; it'll figure out what to
|
||||
// when GuaranteeNeighbor is called
|
||||
face->GetVertex(vertexid)->SetVertexEdit();
|
||||
}
|
||||
// In any event, mark the face as having a vertex edit (which
|
||||
// may only be applied on subfaces)
|
||||
face->MarkVertexEdits();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PRMAN
|
||||
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
|
||||
|
||||
private:
|
||||
const unsigned char vertexid;
|
||||
int index;
|
||||
int width;
|
||||
unsigned isP:1;
|
||||
typename HbrHierarchicalEdit<T>::Operation op;
|
||||
float* edit;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_HBRVERTEXEDIT_H */
|
||||
45
src/osd/opensubdiv/osd/Android.mk
Normal file
45
src/osd/opensubdiv/osd/Android.mk
Normal file
@@ -0,0 +1,45 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
# with the following modification; you may not use this file except in
|
||||
# compliance with the Apache License and the following modification to it:
|
||||
# Section 6. Trademarks. is deleted and replaced with:
|
||||
#
|
||||
# 6. Trademarks. This License does not grant permission to use the trade
|
||||
# names, trademarks, service marks, or product names of the Licensor
|
||||
# and its affiliates, except as required to comply with Section 4(c) of
|
||||
# the License and to reproduce the content of the NOTICE file.
|
||||
#
|
||||
# You may obtain a copy of the Apache License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the Apache License with the above modification is
|
||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the Apache License for the specific
|
||||
# language governing permissions and limitations under the Apache License.
|
||||
#
|
||||
|
||||
# This file is used by the Android NDK to allow OpenSubdiv libraries
|
||||
# to be imported by client modules.
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE = OpenSubdivOsdCPU
|
||||
LOCAL_SRC_FILES = libs/armeabi-v7a/libosdCPU.so
|
||||
LOCAL_EXPORT_C_INCLUDES = $(LOCAL_PATH)/include
|
||||
|
||||
include $(PREBUILT_SHARED_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE = OpenSubdivOsdGPU
|
||||
LOCAL_SRC_FILES = libs/armeabi-v7a/libosdGPU.so
|
||||
LOCAL_EXPORT_C_INCLUDES = $(LOCAL_PATH)/include
|
||||
|
||||
include $(PREBUILT_SHARED_LIBRARY)
|
||||
|
||||
425
src/osd/opensubdiv/osd/CMakeLists.txt
Executable file
425
src/osd/opensubdiv/osd/CMakeLists.txt
Executable file
@@ -0,0 +1,425 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
# with the following modification; you may not use this file except in
|
||||
# compliance with the Apache License and the following modification to it:
|
||||
# Section 6. Trademarks. is deleted and replaced with:
|
||||
#
|
||||
# 6. Trademarks. This License does not grant permission to use the trade
|
||||
# names, trademarks, service marks, or product names of the Licensor
|
||||
# and its affiliates, except as required to comply with Section 4(c) of
|
||||
# the License and to reproduce the content of the NOTICE file.
|
||||
#
|
||||
# You may obtain a copy of the Apache License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the Apache License with the above modification is
|
||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the Apache License for the specific
|
||||
# language governing permissions and limitations under the Apache License.
|
||||
#
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# source & headers
|
||||
set(CPU_SOURCE_FILES
|
||||
cpuEvaluator.cpp
|
||||
cpuKernel.cpp
|
||||
cpuPatchTable.cpp
|
||||
cpuVertexBuffer.cpp
|
||||
)
|
||||
|
||||
set(GPU_SOURCE_FILES )
|
||||
|
||||
set(INC_FILES )
|
||||
|
||||
set(PRIVATE_HEADER_FILES
|
||||
cpuKernel.h
|
||||
)
|
||||
|
||||
set(PUBLIC_HEADER_FILES
|
||||
bufferDescriptor.h
|
||||
cpuEvaluator.h
|
||||
cpuPatchTable.h
|
||||
cpuVertexBuffer.h
|
||||
mesh.h
|
||||
nonCopyable.h
|
||||
opengl.h
|
||||
types.h
|
||||
)
|
||||
|
||||
list(APPEND KERNEL_FILES
|
||||
patchBasisCommonTypes.h
|
||||
patchBasisCommon.h
|
||||
patchBasisCommonEval.h
|
||||
)
|
||||
|
||||
set(DOXY_HEADER_FILES ${PUBLIC_HEADER_FILES})
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
set(OPENMP_PUBLIC_HEADERS
|
||||
ompEvaluator.h
|
||||
ompKernel.h
|
||||
)
|
||||
|
||||
if(OPENMP_FOUND )
|
||||
list(APPEND CPU_SOURCE_FILES
|
||||
ompEvaluator.cpp
|
||||
ompKernel.cpp
|
||||
)
|
||||
|
||||
list(APPEND PUBLIC_HEADER_FILES ${OPENMP_PUBLIC_HEADERS})
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
list(APPEND PLATFORM_CPU_LIBRARIES gomp)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND DOXY_HEADER_FILES ${OPENMP_PUBLIC_HEADERS})
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
set(TBB_PUBLIC_HEADERS
|
||||
tbbEvaluator.h
|
||||
tbbKernel.h
|
||||
)
|
||||
|
||||
if( TBB_FOUND )
|
||||
include_directories("${TBB_INCLUDE_DIR}")
|
||||
|
||||
list(APPEND CPU_SOURCE_FILES
|
||||
tbbEvaluator.cpp
|
||||
tbbKernel.cpp
|
||||
)
|
||||
|
||||
list(APPEND PUBLIC_HEADER_FILES ${TBB_PUBLIC_HEADERS})
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
list(APPEND PLATFORM_CPU_LIBRARIES gomp)
|
||||
endif()
|
||||
|
||||
list(APPEND PLATFORM_CPU_LIBRARIES
|
||||
${TBB_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND DOXY_HEADER_FILES ${TBB_PUBLIC_HEADERS})
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# GL code & dependencies
|
||||
set(GL_PUBLIC_HEADERS
|
||||
cpuGLVertexBuffer.h
|
||||
glLegacyGregoryPatchTable.h
|
||||
glPatchTable.h
|
||||
glVertexBuffer.h
|
||||
glMesh.h
|
||||
glslPatchShaderSource.h
|
||||
)
|
||||
|
||||
if( (NOT NO_OPENGL) AND (OPENGL_FOUND OR OPENGLES_FOUND) )
|
||||
list(APPEND GPU_SOURCE_FILES
|
||||
cpuGLVertexBuffer.cpp
|
||||
glLegacyGregoryPatchTable.cpp
|
||||
glPatchTable.cpp
|
||||
glVertexBuffer.cpp
|
||||
glslPatchShaderSource.cpp
|
||||
)
|
||||
list(APPEND PUBLIC_HEADER_FILES ${GL_PUBLIC_HEADERS})
|
||||
if ( OPENGL_FOUND )
|
||||
list(APPEND KERNEL_FILES
|
||||
glslPatchCommon.glsl
|
||||
glslPatchCommonTess.glsl
|
||||
glslPatchBoxSplineTriangle.glsl
|
||||
glslPatchBSpline.glsl
|
||||
glslPatchGregory.glsl
|
||||
glslPatchGregoryBasis.glsl
|
||||
glslPatchGregoryTriangle.glsl
|
||||
glslPatchLegacy.glsl
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND DOXY_HEADER_FILES ${GL_PUBLIC_HEADERS})
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# OpenGL 4.2 dependencies
|
||||
# note : (GLSL transform feedback kernels require GL 4.2)
|
||||
set(GL_4_2_PUBLIC_HEADERS
|
||||
glXFBEvaluator.h
|
||||
)
|
||||
|
||||
if( OPENGL_4_2_FOUND )
|
||||
list(APPEND GPU_SOURCE_FILES
|
||||
glXFBEvaluator.cpp
|
||||
)
|
||||
list(APPEND PUBLIC_HEADER_FILES ${GL_4_2_PUBLIC_HEADERS})
|
||||
list(APPEND KERNEL_FILES
|
||||
glslXFBKernel.glsl
|
||||
)
|
||||
list(APPEND PLATFORM_GPU_LIBRARIES
|
||||
${OPENGL_LOADER_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND DOXY_HEADER_FILES ${GL_4_2_PUBLIC_HEADERS})
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# OpenGL 4.3 dependencies
|
||||
# note : (GLSL compute shader kernels require GL 4.3)
|
||||
set(GL_4_3_PUBLIC_HEADERS
|
||||
glComputeEvaluator.h
|
||||
)
|
||||
|
||||
if( OPENGL_4_3_FOUND )
|
||||
list(APPEND GPU_SOURCE_FILES
|
||||
glComputeEvaluator.cpp
|
||||
)
|
||||
list(APPEND PUBLIC_HEADER_FILES ${GL_4_3_PUBLIC_HEADERS})
|
||||
list(APPEND KERNEL_FILES
|
||||
glslComputeKernel.glsl
|
||||
)
|
||||
list(APPEND PLATFORM_GPU_LIBRARIES
|
||||
${OPENGL_LOADER_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND DOXY_HEADER_FILES ${GL_4_3_PUBLIC_HEADERS})
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# DX11 code & dependencies
|
||||
set(DXSDK_PUBLIC_HEADERS
|
||||
cpuD3D11VertexBuffer.h
|
||||
d3d11ComputeEvaluator.h
|
||||
d3d11LegacyGregoryPatchTable.h
|
||||
d3d11PatchTable.h
|
||||
d3d11VertexBuffer.h
|
||||
d3d11Mesh.h
|
||||
hlslPatchShaderSource.h
|
||||
)
|
||||
if( DXSDK_FOUND )
|
||||
list(APPEND GPU_SOURCE_FILES
|
||||
cpuD3D11VertexBuffer.cpp
|
||||
d3d11ComputeEvaluator.cpp
|
||||
d3d11LegacyGregoryPatchTable.cpp
|
||||
d3d11PatchTable.cpp
|
||||
d3d11VertexBuffer.cpp
|
||||
hlslPatchShaderSource.cpp
|
||||
)
|
||||
list(APPEND PUBLIC_HEADER_FILES ${DXSDK_PUBLIC_HEADERS})
|
||||
list(APPEND KERNEL_FILES
|
||||
hlslComputeKernel.hlsl
|
||||
hlslPatchCommon.hlsl
|
||||
hlslPatchCommonTess.hlsl
|
||||
hlslPatchBoxSplineTriangle.hlsl
|
||||
hlslPatchBSpline.hlsl
|
||||
hlslPatchGregory.hlsl
|
||||
hlslPatchGregoryBasis.hlsl
|
||||
hlslPatchGregoryTriangle.hlsl
|
||||
hlslPatchLegacy.hlsl
|
||||
)
|
||||
list(APPEND PLATFORM_GPU_LIBRARIES
|
||||
${DXSDK_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND DOXY_HEADER_FILES ${DXSDK_PUBLIC_HEADERS})
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Metal code & dependencies
|
||||
set(METAL_PUBLIC_HEADERS
|
||||
mtlVertexBuffer.h
|
||||
mtlComputeEvaluator.h
|
||||
mtlLegacyGregoryPatchTable.h
|
||||
mtlPatchTable.h
|
||||
mtlMesh.h
|
||||
mtlPatchShaderSource.h
|
||||
mtlCommon.h
|
||||
)
|
||||
|
||||
|
||||
if( METAL_FOUND )
|
||||
set(METAL_SOURCE_FILES
|
||||
mtlVertexBuffer.mm
|
||||
mtlComputeEvaluator.mm
|
||||
mtlLegacyGregoryPatchTable.mm
|
||||
mtlPatchTable.mm
|
||||
mtlVertexBuffer.mm
|
||||
mtlPatchShaderSource.mm
|
||||
)
|
||||
|
||||
set_source_files_properties(
|
||||
${METAL_SOURCE_FILES}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS
|
||||
"-fobjc-arc")
|
||||
|
||||
list(APPEND GPU_SOURCE_FILES ${METAL_SOURCE_FILES})
|
||||
|
||||
|
||||
|
||||
list(APPEND PUBLIC_HEADER_FILES ${METAL_PUBLIC_HEADERS})
|
||||
list(APPEND KERNEL_FILES
|
||||
mtlComputeKernel.metal
|
||||
mtlPatchCommon.metal
|
||||
mtlPatchCommonTess.metal
|
||||
mtlPatchBoxSplineTriangle.metal
|
||||
mtlPatchBSpline.metal
|
||||
mtlPatchGregory.metal
|
||||
mtlPatchGregoryBasis.metal
|
||||
mtlPatchGregoryTriangle.metal
|
||||
mtlPatchLegacy.metal
|
||||
)
|
||||
list(APPEND PLATFORM_GPU_LIBRARIES
|
||||
${METAL_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND DOXY_HEADER_FILES ${METAL_PUBLIC_HEADERS})
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# OpenCL code & dependencies
|
||||
set(OPENCL_PUBLIC_HEADERS
|
||||
clEvaluator.h
|
||||
clPatchTable.h
|
||||
clVertexBuffer.h
|
||||
opencl.h
|
||||
)
|
||||
|
||||
if ( OPENCL_FOUND )
|
||||
list(APPEND GPU_SOURCE_FILES
|
||||
clEvaluator.cpp
|
||||
clPatchTable.cpp
|
||||
clVertexBuffer.cpp
|
||||
)
|
||||
list(APPEND PUBLIC_HEADER_FILES ${OPENCL_PUBLIC_HEADERS})
|
||||
list(APPEND KERNEL_FILES
|
||||
clKernel.cl
|
||||
)
|
||||
list(APPEND PLATFORM_GPU_LIBRARIES
|
||||
${OPENCL_LIBRARIES}
|
||||
)
|
||||
include_directories( "${OPENCL_INCLUDE_DIRS}" )
|
||||
if ( OPENGL_FOUND )
|
||||
list(APPEND GPU_SOURCE_FILES clGLVertexBuffer.cpp)
|
||||
list(APPEND PUBLIC_HEADER_FILES clGLVertexBuffer.h)
|
||||
endif()
|
||||
|
||||
if ( OPENCL_D3D11_INTEROP_FOUND )
|
||||
list(APPEND GPU_SOURCE_FILES
|
||||
clD3D11VertexBuffer.cpp
|
||||
)
|
||||
list(APPEND PUBLIC_HEADER_FILES
|
||||
clD3D11VertexBuffer.h
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND DOXY_HEADER_FILES ${OPENCL_PUBLIC_HEADERS})
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# CUDA code & dependencies
|
||||
set(CUDA_PUBLIC_HEADERS
|
||||
cudaEvaluator.h
|
||||
cudaPatchTable.h
|
||||
cudaVertexBuffer.h
|
||||
)
|
||||
|
||||
if( CUDA_FOUND )
|
||||
list(APPEND GPU_SOURCE_FILES
|
||||
cudaEvaluator.cpp
|
||||
cudaPatchTable.cpp
|
||||
cudaVertexBuffer.cpp
|
||||
)
|
||||
list(APPEND PUBLIC_HEADER_FILES ${CUDA_PUBLIC_HEADERS})
|
||||
list(APPEND CUDA_KERNEL_FILES
|
||||
osd/cudaKernel.cu
|
||||
)
|
||||
set (CUDA_KERNEL_FILES ${CUDA_KERNEL_FILES} PARENT_SCOPE)
|
||||
if ( OPENGL_FOUND )
|
||||
list(APPEND GPU_SOURCE_FILES
|
||||
cudaGLVertexBuffer.cpp
|
||||
)
|
||||
list(APPEND PUBLIC_HEADER_FILES
|
||||
cudaGLVertexBuffer.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if( DXSDK_FOUND )
|
||||
list(APPEND GPU_SOURCE_FILES
|
||||
cudaD3D11VertexBuffer.cpp
|
||||
)
|
||||
list(APPEND PUBLIC_HEADER_FILES
|
||||
cudaD3D11VertexBuffer.h
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND DOXY_HEADER_FILES ${CUDA_PUBLIC_HEADERS})
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
osd_stringify("${KERNEL_FILES}" INC_FILES)
|
||||
|
||||
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
source_group("Kernels" FILES ${KERNEL_FILES})
|
||||
|
||||
source_group("Inc" FILES ${INC_FILES})
|
||||
|
||||
# Compile objs first for both the CPU and GPU libs -----
|
||||
add_library(osd_cpu_obj
|
||||
OBJECT
|
||||
${CPU_SOURCE_FILES}
|
||||
${PRIVATE_HEADER_FILES}
|
||||
${PUBLIC_HEADER_FILES}
|
||||
)
|
||||
|
||||
set_target_properties(osd_cpu_obj
|
||||
PROPERTIES
|
||||
FOLDER "opensubdiv"
|
||||
)
|
||||
|
||||
if( GPU_SOURCE_FILES )
|
||||
add_library(osd_gpu_obj
|
||||
OBJECT
|
||||
${GPU_SOURCE_FILES}
|
||||
${PRIVATE_HEADER_FILES}
|
||||
${PUBLIC_HEADER_FILES}
|
||||
${INC_FILES}
|
||||
)
|
||||
set_target_properties(osd_gpu_obj
|
||||
PROPERTIES
|
||||
FOLDER "opensubdiv"
|
||||
)
|
||||
endif()
|
||||
|
||||
osd_add_doxy_headers( "${DOXY_HEADER_FILES}" )
|
||||
|
||||
install(
|
||||
FILES
|
||||
${PUBLIC_HEADER_FILES}
|
||||
DESTINATION
|
||||
"${CMAKE_INCDIR_BASE}/osd"
|
||||
PERMISSIONS
|
||||
OWNER_READ
|
||||
GROUP_READ
|
||||
WORLD_READ )
|
||||
|
||||
#if (ANDROID)
|
||||
# install(
|
||||
# FILES
|
||||
# Android.mk
|
||||
# DESTINATION
|
||||
# "${LIBRARY_OUTPUT_PATH_ROOT}"
|
||||
# PERMISSIONS
|
||||
# OWNER_READ
|
||||
# GROUP_READ
|
||||
# WORLD_READ )
|
||||
#endif()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
112
src/osd/opensubdiv/osd/bufferDescriptor.h
Normal file
112
src/osd/opensubdiv/osd/bufferDescriptor.h
Normal file
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_OSD_BUFFER_DESCRIPTOR_H
|
||||
#define OPENSUBDIV3_OSD_BUFFER_DESCRIPTOR_H
|
||||
|
||||
#include "../version.h"
|
||||
#include <string.h>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
/// \brief BufferDescriptor is a struct which describes buffer elements in
|
||||
/// interleaved data buffers. Almost all Osd Evaluator APIs take
|
||||
/// BufferDescriptors along with device-specific buffer objects.
|
||||
///
|
||||
/// The offset of BufferDescriptor can also be used to express a
|
||||
/// batching offset if the data buffer is combined across multiple
|
||||
/// objects together.
|
||||
///
|
||||
/// * Note that each element has the same data type (float)
|
||||
///
|
||||
|
||||
// example:
|
||||
// n
|
||||
// -----+----------------------------------------+-------------------------
|
||||
// | vertex 0 |
|
||||
// -----+----------------------------------------+-------------------------
|
||||
// | X Y Z R G B A Xu Yu Zu Xv Yv Zv |
|
||||
// -----+----------------------------------------+-------------------------
|
||||
// <------------- stride = 13 -------------->
|
||||
//
|
||||
// - XYZ (offset = n+0, length = 3, stride = 13)
|
||||
// - RGBA (offset = n+3, length = 4, stride = 13)
|
||||
// - uTangent (offset = n+7, length = 3, stride = 13)
|
||||
// - vTangent (offset = n+10, length = 3, stride = 13)
|
||||
//
|
||||
struct BufferDescriptor {
|
||||
|
||||
/// Default Constructor
|
||||
BufferDescriptor() : offset(0), length(0), stride(0) { }
|
||||
|
||||
/// Constructor
|
||||
BufferDescriptor(int o, int l, int s) : offset(o), length(l), stride(s) { }
|
||||
|
||||
/// Returns the relative offset within a stride
|
||||
int GetLocalOffset() const {
|
||||
return stride > 0 ? offset % stride : 0;
|
||||
}
|
||||
|
||||
/// True if the descriptor values are internally consistent
|
||||
bool IsValid() const {
|
||||
return ((length > 0) &&
|
||||
(length <= stride - GetLocalOffset()));
|
||||
}
|
||||
|
||||
/// Resets the descriptor to default
|
||||
void Reset() {
|
||||
offset = length = stride = 0;
|
||||
}
|
||||
|
||||
/// True if the descriptors are identical
|
||||
bool operator == (BufferDescriptor const &other) const {
|
||||
return (offset == other.offset &&
|
||||
length == other.length &&
|
||||
stride == other.stride);
|
||||
}
|
||||
|
||||
/// True if the descriptors are not identical
|
||||
bool operator != (BufferDescriptor const &other) const {
|
||||
return !(this->operator==(other));
|
||||
}
|
||||
|
||||
/// offset to desired element data
|
||||
int offset;
|
||||
/// number or length of the data
|
||||
int length;
|
||||
/// stride to the next element
|
||||
int stride;
|
||||
};
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_OSD_BUFFER_DESCRIPTOR_H
|
||||
233
src/osd/opensubdiv/osd/clD3D11VertexBuffer.cpp
Normal file
233
src/osd/opensubdiv/osd/clD3D11VertexBuffer.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../osd/clD3D11VertexBuffer.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <D3D11.h>
|
||||
#if defined(OPENSUBDIV_HAS_CL_D3D11_H)
|
||||
#include <CL/cl_d3d11.h>
|
||||
#elif defined(OPENSUBDIV_HAS_CL_D3D11_EXT_H)
|
||||
#include <CL/cl_d3d11_ext.h>
|
||||
#else
|
||||
#error "d3d11.h or d3d11_ext.h must be found in cmake"
|
||||
#endif
|
||||
|
||||
#include "../far/error.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
#if defined(OPENSUBDIV_HAS_CL_D3D11_H)
|
||||
typedef clCreateFromD3D11BufferKHR_fn clCreateFromD3D11Buffer_fn;
|
||||
typedef clEnqueueAcquireD3D11ObjectsKHR_fn clEnqueueAcquireD3D11Objects_fn;
|
||||
typedef clEnqueueReleaseD3D11ObjectsKHR_fn clEnqueueReleaseD3D11Objects_fn;
|
||||
#else
|
||||
typedef clCreateFromD3D11BufferNV_fn clCreateFromD3D11Buffer_fn;
|
||||
typedef clEnqueueAcquireD3D11ObjectsNV_fn clEnqueueAcquireD3D11Objects_fn;
|
||||
typedef clEnqueueReleaseD3D11ObjectsNV_fn clEnqueueReleaseD3D11Objects_fn;
|
||||
#endif
|
||||
|
||||
static clCreateFromD3D11Buffer_fn clCreateFromD3D11Buffer = NULL;
|
||||
static clEnqueueAcquireD3D11Objects_fn clEnqueueAcquireD3D11Objects = NULL;
|
||||
static clEnqueueReleaseD3D11Objects_fn clEnqueueReleaseD3D11Objects = NULL;
|
||||
|
||||
// XXX: clGetExtensionFunctionAddress is marked as deprecated and
|
||||
// clGetExtensionFunctionAddressForPlatform should be used,
|
||||
// however it requires OpenCL 1.2.
|
||||
// until we bump the requirement to 1.2, mute the deprecated warning.
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable: 4996)
|
||||
#endif
|
||||
|
||||
|
||||
static void resolveInteropFunctions() {
|
||||
|
||||
if (! clCreateFromD3D11Buffer) {
|
||||
clCreateFromD3D11Buffer =
|
||||
(clCreateFromD3D11Buffer_fn)
|
||||
clGetExtensionFunctionAddress("clCreateFromD3D11BufferKHR");
|
||||
}
|
||||
if (! clCreateFromD3D11Buffer) {
|
||||
clCreateFromD3D11Buffer =
|
||||
(clCreateFromD3D11Buffer_fn)
|
||||
clGetExtensionFunctionAddress("clCreateFromD3D11BufferNV");
|
||||
}
|
||||
|
||||
if (! clEnqueueAcquireD3D11Objects) {
|
||||
clEnqueueAcquireD3D11Objects = (clEnqueueAcquireD3D11Objects_fn)
|
||||
clGetExtensionFunctionAddress("clEnqueueAcquireD3D11ObjectsKHR");
|
||||
}
|
||||
if (! clEnqueueAcquireD3D11Objects) {
|
||||
clEnqueueAcquireD3D11Objects = (clEnqueueAcquireD3D11Objects_fn)
|
||||
clGetExtensionFunctionAddress("clEnqueueAcquireD3D11ObjectsNV");
|
||||
}
|
||||
|
||||
if (! clEnqueueReleaseD3D11Objects) {
|
||||
clEnqueueReleaseD3D11Objects = (clEnqueueReleaseD3D11Objects_fn)
|
||||
clGetExtensionFunctionAddress("clEnqueueReleaseD3D11ObjectsKHR");
|
||||
}
|
||||
if (! clEnqueueReleaseD3D11Objects) {
|
||||
clEnqueueReleaseD3D11Objects = (clEnqueueReleaseD3D11Objects_fn)
|
||||
clGetExtensionFunctionAddress("clEnqueueReleaseD3D11ObjectsNV");
|
||||
}
|
||||
}
|
||||
|
||||
CLD3D11VertexBuffer::CLD3D11VertexBuffer(int numElements, int numVertices)
|
||||
: _numElements(numElements), _numVertices(numVertices),
|
||||
_d3d11Buffer(NULL), _clMemory(NULL), _clQueue(NULL), _clMapped(false) {
|
||||
}
|
||||
|
||||
CLD3D11VertexBuffer::~CLD3D11VertexBuffer() {
|
||||
|
||||
unmap();
|
||||
clReleaseMemObject(_clMemory);
|
||||
_d3d11Buffer->Release();
|
||||
}
|
||||
|
||||
CLD3D11VertexBuffer *
|
||||
CLD3D11VertexBuffer::Create(int numElements, int numVertices,
|
||||
cl_context clContext,
|
||||
ID3D11DeviceContext *deviceContext) {
|
||||
CLD3D11VertexBuffer *instance =
|
||||
new CLD3D11VertexBuffer(numElements, numVertices);
|
||||
|
||||
ID3D11Device *device;
|
||||
deviceContext->GetDevice(&device);
|
||||
|
||||
if (instance->allocate(clContext, device)) return instance;
|
||||
delete instance;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CLD3D11VertexBuffer::UpdateData(const float *src, int startVertex,
|
||||
int numVertices, cl_command_queue queue) {
|
||||
|
||||
size_t size = numVertices * _numElements * sizeof(float);
|
||||
size_t offset = startVertex * _numElements * sizeof(float);
|
||||
|
||||
map(queue);
|
||||
clEnqueueWriteBuffer(queue, _clMemory, true, offset, size, src, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
CLD3D11VertexBuffer::GetNumElements() const {
|
||||
|
||||
return _numElements;
|
||||
}
|
||||
|
||||
int
|
||||
CLD3D11VertexBuffer::GetNumVertices() const {
|
||||
|
||||
return _numVertices;
|
||||
}
|
||||
|
||||
cl_mem
|
||||
CLD3D11VertexBuffer::BindCLBuffer(cl_command_queue queue) {
|
||||
|
||||
map(queue);
|
||||
return _clMemory;
|
||||
}
|
||||
|
||||
ID3D11Buffer *
|
||||
CLD3D11VertexBuffer::BindD3D11Buffer(ID3D11DeviceContext *deviceContext) {
|
||||
|
||||
unmap();
|
||||
return _d3d11Buffer;
|
||||
}
|
||||
|
||||
bool
|
||||
CLD3D11VertexBuffer::allocate(cl_context clContext, ID3D11Device *device) {
|
||||
|
||||
D3D11_BUFFER_DESC hBufferDesc;
|
||||
hBufferDesc.ByteWidth = _numElements * _numVertices * sizeof(float);
|
||||
hBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
hBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_SHADER_RESOURCE;
|
||||
hBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
hBufferDesc.MiscFlags = 0;
|
||||
hBufferDesc.StructureByteStride = sizeof(float);
|
||||
|
||||
HRESULT hr;
|
||||
hr = device->CreateBuffer(&hBufferDesc, NULL, &_d3d11Buffer);
|
||||
if (FAILED(hr)) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "Fail in CreateBuffer\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! clCreateFromD3D11Buffer) {
|
||||
resolveInteropFunctions();
|
||||
if (! clCreateFromD3D11Buffer) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// register d3d11buffer as cl memory
|
||||
cl_int err;
|
||||
|
||||
_clMemory = clCreateFromD3D11Buffer(clContext, CL_MEM_READ_WRITE, _d3d11Buffer, &err);
|
||||
|
||||
if (err != CL_SUCCESS) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CLD3D11VertexBuffer::map(cl_command_queue queue) {
|
||||
|
||||
if (_clMapped) return;
|
||||
_clQueue = queue;
|
||||
|
||||
if (! clEnqueueAcquireD3D11Objects) {
|
||||
resolveInteropFunctions();
|
||||
if (! clEnqueueAcquireD3D11Objects) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
clEnqueueAcquireD3D11Objects(queue, 1, &_clMemory, 0, 0, 0);
|
||||
_clMapped = true;
|
||||
}
|
||||
|
||||
void
|
||||
CLD3D11VertexBuffer::unmap() {
|
||||
|
||||
if (! _clMapped) return;
|
||||
if (! clEnqueueReleaseD3D11Objects) {
|
||||
resolveInteropFunctions();
|
||||
if (! clEnqueueReleaseD3D11Objects) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
clEnqueueReleaseD3D11Objects(_clQueue, 1, &_clMemory, 0, 0, 0);
|
||||
_clMapped = false;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
143
src/osd/opensubdiv/osd/clD3D11VertexBuffer.h
Normal file
143
src/osd/opensubdiv/osd/clD3D11VertexBuffer.h
Normal file
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_OSD_CL_D3D11_VERTEX_BUFFER_H
|
||||
#define OPENSUBDIV3_OSD_CL_D3D11_VERTEX_BUFFER_H
|
||||
|
||||
#include "../version.h"
|
||||
#include "../osd/opencl.h"
|
||||
|
||||
struct ID3D11VertexShader;
|
||||
struct ID3D11HullShader;
|
||||
struct ID3D11DomainShader;
|
||||
struct ID3D11GeometryShader;
|
||||
struct ID3D11PixelShader;
|
||||
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11ShaderResourceView;
|
||||
struct ID3D11Device;
|
||||
struct ID3D11DeviceContext;
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
///
|
||||
/// \brief Concrete vertex buffer class for OpenCL subdivision and DirectX
|
||||
/// drawing.
|
||||
///
|
||||
/// D3D11VertexBuffer implements CLVertexBufferInterface and
|
||||
/// D3D11VertexBufferInterface.
|
||||
///
|
||||
/// An instance of this buffer class can be passed to D3D11ComputeEvaluator.
|
||||
///
|
||||
class CLD3D11VertexBuffer {
|
||||
public:
|
||||
/// Creator. Returns NULL if error.
|
||||
static CLD3D11VertexBuffer * Create(int numElements, int numVertices,
|
||||
cl_context clContext,
|
||||
ID3D11DeviceContext *deviceContext);
|
||||
|
||||
/// template version for custom context (OpenCL) used by OsdMesh
|
||||
template<typename DEVICE_CONTEXT>
|
||||
static CLD3D11VertexBuffer * Create(int numElements, int numVertices,
|
||||
DEVICE_CONTEXT context) {
|
||||
return Create(numElements, numVertices,
|
||||
context->GetContext(),
|
||||
context->GetDeviceContext());
|
||||
}
|
||||
|
||||
|
||||
/// Destructor.
|
||||
virtual ~CLD3D11VertexBuffer();
|
||||
|
||||
/// This method is meant to be used in client code in order to provide coarse
|
||||
/// vertices data to Osd.
|
||||
void UpdateData(const float *src, int startVertex, int numVertices,
|
||||
cl_command_queue clQueue);
|
||||
|
||||
/// template version for custom context (OpenCL) used by OsdMesh
|
||||
template<typename DEVICE_CONTEXT>
|
||||
void UpdateData(const float *src, int startVertex, int numVertices,
|
||||
DEVICE_CONTEXT context) {
|
||||
UpdateData(src, startVertex, numVertices, context->GetCommandQueue());
|
||||
}
|
||||
|
||||
/// Returns how many elements defined in this vertex buffer.
|
||||
int GetNumElements() const;
|
||||
|
||||
/// Returns how many vertices allocated in this vertex buffer.
|
||||
int GetNumVertices() const;
|
||||
|
||||
/// Returns the CL memory object.
|
||||
cl_mem BindCLBuffer(cl_command_queue queue);
|
||||
|
||||
/// Returns the D3D11 buffer object.
|
||||
ID3D11Buffer *BindD3D11Buffer(ID3D11DeviceContext *deviceContext);
|
||||
|
||||
/// Returns the D3D11 buffer object (for Osd::Mesh interface)
|
||||
ID3D11Buffer *BindVBO(ID3D11DeviceContext *deviceContext) {
|
||||
return BindD3D11Buffer(deviceContext);
|
||||
}
|
||||
|
||||
/// template version for custom context (OpenCL) used by OsdMesh
|
||||
template<typename DEVICE_CONTEXT>
|
||||
ID3D11Buffer *BindVBO(DEVICE_CONTEXT context) {
|
||||
return BindD3D11Buffer(context->GetDeviceContext());
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Constructor.
|
||||
CLD3D11VertexBuffer(int numElements, int numVertices);
|
||||
|
||||
/// Allocates this buffer and registers as a cl resource.
|
||||
/// Returns true if success.
|
||||
bool allocate(cl_context clContext, ID3D11Device *device);
|
||||
|
||||
/// Acquire a resource from DirectX.
|
||||
void map(cl_command_queue queue);
|
||||
|
||||
/// Releases a resource to DirectX.
|
||||
void unmap();
|
||||
|
||||
private:
|
||||
int _numElements;
|
||||
int _numVertices;
|
||||
ID3D11Buffer *_d3d11Buffer;
|
||||
cl_command_queue _clQueue;
|
||||
cl_mem _clMemory;
|
||||
|
||||
bool _clMapped;
|
||||
|
||||
};
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_OSD_CL_D3D11_VERTEX_BUFFER_H
|
||||
541
src/osd/opensubdiv/osd/clEvaluator.cpp
Normal file
541
src/osd/opensubdiv/osd/clEvaluator.cpp
Normal file
@@ -0,0 +1,541 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../osd/clEvaluator.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
|
||||
#include "../osd/opencl.h"
|
||||
#include "../far/error.h"
|
||||
#include "../far/stencilTable.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
static const char *clSource =
|
||||
#include "clKernel.gen.h"
|
||||
;
|
||||
static const char *patchBasisTypesSource =
|
||||
#include "patchBasisCommonTypes.gen.h"
|
||||
;
|
||||
static const char *patchBasisSource =
|
||||
#include "patchBasisCommon.gen.h"
|
||||
;
|
||||
static const char *patchBasisEvalSource =
|
||||
#include "patchBasisCommonEval.gen.h"
|
||||
;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
template <class T> cl_mem
|
||||
createCLBuffer(std::vector<T> const & src, cl_context clContext) {
|
||||
if (src.empty()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cl_int errNum = 0;
|
||||
cl_mem devicePtr = clCreateBuffer(clContext,
|
||||
CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR,
|
||||
src.size()*sizeof(T),
|
||||
(void*)(&src.at(0)),
|
||||
&errNum);
|
||||
|
||||
if (errNum != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "clCreateBuffer: %d", errNum);
|
||||
}
|
||||
|
||||
return devicePtr;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
CLStencilTable::CLStencilTable(Far::StencilTable const *stencilTable,
|
||||
cl_context clContext) {
|
||||
_numStencils = stencilTable->GetNumStencils();
|
||||
|
||||
if (_numStencils > 0) {
|
||||
_sizes = createCLBuffer(stencilTable->GetSizes(), clContext);
|
||||
_offsets = createCLBuffer(stencilTable->GetOffsets(), clContext);
|
||||
_indices = createCLBuffer(stencilTable->GetControlIndices(),
|
||||
clContext);
|
||||
_weights = createCLBuffer(stencilTable->GetWeights(), clContext);
|
||||
_duWeights = _dvWeights = NULL;
|
||||
_duuWeights = _duvWeights = _dvvWeights = NULL;
|
||||
} else {
|
||||
_sizes = _offsets = _indices = _weights = NULL;
|
||||
_duWeights = _dvWeights = NULL;
|
||||
_duuWeights = _duvWeights = _dvvWeights = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CLStencilTable::CLStencilTable(Far::LimitStencilTable const *limitStencilTable,
|
||||
cl_context clContext) {
|
||||
_numStencils = limitStencilTable->GetNumStencils();
|
||||
|
||||
if (_numStencils > 0) {
|
||||
_sizes = createCLBuffer(limitStencilTable->GetSizes(), clContext);
|
||||
_offsets = createCLBuffer(limitStencilTable->GetOffsets(), clContext);
|
||||
_indices = createCLBuffer(limitStencilTable->GetControlIndices(),
|
||||
clContext);
|
||||
_weights = createCLBuffer(limitStencilTable->GetWeights(), clContext);
|
||||
_duWeights = createCLBuffer(
|
||||
limitStencilTable->GetDuWeights(), clContext);
|
||||
_dvWeights = createCLBuffer(
|
||||
limitStencilTable->GetDvWeights(), clContext);
|
||||
_duuWeights = createCLBuffer(
|
||||
limitStencilTable->GetDuuWeights(), clContext);
|
||||
_duvWeights = createCLBuffer(
|
||||
limitStencilTable->GetDuvWeights(), clContext);
|
||||
_dvvWeights = createCLBuffer(
|
||||
limitStencilTable->GetDvvWeights(), clContext);
|
||||
} else {
|
||||
_sizes = _offsets = _indices = _weights = NULL;
|
||||
_duWeights = _dvWeights = NULL;
|
||||
_duuWeights = _duvWeights = _dvvWeights = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CLStencilTable::~CLStencilTable() {
|
||||
if (_sizes) clReleaseMemObject(_sizes);
|
||||
if (_offsets) clReleaseMemObject(_offsets);
|
||||
if (_indices) clReleaseMemObject(_indices);
|
||||
if (_weights) clReleaseMemObject(_weights);
|
||||
if (_duWeights) clReleaseMemObject(_duWeights);
|
||||
if (_dvWeights) clReleaseMemObject(_dvWeights);
|
||||
if (_duuWeights) clReleaseMemObject(_duuWeights);
|
||||
if (_duvWeights) clReleaseMemObject(_duvWeights);
|
||||
if (_dvvWeights) clReleaseMemObject(_dvvWeights);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
CLEvaluator::CLEvaluator(cl_context context, cl_command_queue queue)
|
||||
: _clContext(context), _clCommandQueue(queue),
|
||||
_program(NULL), _stencilKernel(NULL), _stencilDerivKernel(NULL),
|
||||
_patchKernel(NULL) {
|
||||
}
|
||||
|
||||
CLEvaluator::~CLEvaluator() {
|
||||
if (_stencilKernel) clReleaseKernel(_stencilKernel);
|
||||
if (_stencilDerivKernel) clReleaseKernel(_stencilDerivKernel);
|
||||
if (_patchKernel) clReleaseKernel(_patchKernel);
|
||||
if (_program) clReleaseProgram(_program);
|
||||
}
|
||||
|
||||
bool
|
||||
CLEvaluator::Compile(BufferDescriptor const &srcDesc,
|
||||
BufferDescriptor const &dstDesc,
|
||||
BufferDescriptor const & /*duDesc*/,
|
||||
BufferDescriptor const & /*dvDesc*/,
|
||||
BufferDescriptor const & /*duuDesc*/,
|
||||
BufferDescriptor const & /*duvDesc*/,
|
||||
BufferDescriptor const & /*dvvDesc*/) {
|
||||
if (srcDesc.length > dstDesc.length) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR,
|
||||
"srcDesc length must be less than or equal to "
|
||||
"dstDesc length.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
cl_int errNum;
|
||||
|
||||
std::ostringstream defines;
|
||||
defines << "#define LENGTH " << srcDesc.length << "\n"
|
||||
<< "#define SRC_STRIDE " << srcDesc.stride << "\n"
|
||||
<< "#define DST_STRIDE " << dstDesc.stride << "\n"
|
||||
<< "#define OSD_PATCH_BASIS_OPENCL\n";
|
||||
std::string defineStr = defines.str();
|
||||
|
||||
const char *sources[] = { defineStr.c_str(),
|
||||
patchBasisTypesSource,
|
||||
patchBasisSource,
|
||||
patchBasisEvalSource,
|
||||
clSource };
|
||||
_program = clCreateProgramWithSource(_clContext, 5, sources, 0, &errNum);
|
||||
if (errNum != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR,
|
||||
"clCreateProgramWithSource (%d)", errNum);
|
||||
}
|
||||
|
||||
errNum = clBuildProgram(_program, 0, NULL, NULL, NULL, NULL);
|
||||
if (errNum != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "clBuildProgram (%d) \n", errNum);
|
||||
|
||||
cl_int numDevices = 0;
|
||||
clGetContextInfo(
|
||||
_clContext, CL_CONTEXT_NUM_DEVICES,
|
||||
sizeof(cl_uint), &numDevices, NULL);
|
||||
|
||||
cl_device_id *devices = new cl_device_id[numDevices];
|
||||
clGetContextInfo(_clContext, CL_CONTEXT_DEVICES,
|
||||
sizeof(cl_device_id)*numDevices, devices, NULL);
|
||||
|
||||
for (int i = 0; i < numDevices; ++i) {
|
||||
char cBuildLog[10240];
|
||||
clGetProgramBuildInfo(
|
||||
_program, devices[i],
|
||||
CL_PROGRAM_BUILD_LOG, sizeof(cBuildLog), cBuildLog, NULL);
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, cBuildLog);
|
||||
}
|
||||
delete[] devices;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_stencilKernel = clCreateKernel(_program, "computeStencils", &errNum);
|
||||
if (errNum != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "buildKernel (%d)\n", errNum);
|
||||
return false;
|
||||
}
|
||||
|
||||
_stencilDerivKernel = clCreateKernel(_program,
|
||||
"computeStencilsDerivatives", &errNum);
|
||||
if (errNum != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "buildKernel (%d)\n", errNum);
|
||||
return false;
|
||||
}
|
||||
|
||||
_patchKernel = clCreateKernel(_program, "computePatches", &errNum);
|
||||
|
||||
if (errNum != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "buildKernel (%d)\n", errNum);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CLEvaluator::EvalStencils(cl_mem src, BufferDescriptor const &srcDesc,
|
||||
cl_mem dst, BufferDescriptor const &dstDesc,
|
||||
cl_mem sizes,
|
||||
cl_mem offsets,
|
||||
cl_mem indices,
|
||||
cl_mem weights,
|
||||
int start, int end,
|
||||
unsigned int numStartEvents,
|
||||
const cl_event* startEvents,
|
||||
cl_event* endEvent) const {
|
||||
if (end <= start) return true;
|
||||
|
||||
size_t globalWorkSize = (size_t)(end - start);
|
||||
|
||||
clSetKernelArg(_stencilKernel, 0, sizeof(cl_mem), &src);
|
||||
clSetKernelArg(_stencilKernel, 1, sizeof(int), &srcDesc.offset);
|
||||
clSetKernelArg(_stencilKernel, 2, sizeof(cl_mem), &dst);
|
||||
clSetKernelArg(_stencilKernel, 3, sizeof(int), &dstDesc.offset);
|
||||
clSetKernelArg(_stencilKernel, 4, sizeof(cl_mem), &sizes);
|
||||
clSetKernelArg(_stencilKernel, 5, sizeof(cl_mem), &offsets);
|
||||
clSetKernelArg(_stencilKernel, 6, sizeof(cl_mem), &indices);
|
||||
clSetKernelArg(_stencilKernel, 7, sizeof(cl_mem), &weights);
|
||||
clSetKernelArg(_stencilKernel, 8, sizeof(int), &start);
|
||||
clSetKernelArg(_stencilKernel, 9, sizeof(int), &end);
|
||||
|
||||
cl_int errNum = clEnqueueNDRangeKernel(
|
||||
_clCommandQueue, _stencilKernel, 1, NULL,
|
||||
&globalWorkSize, NULL, numStartEvents, startEvents, endEvent);
|
||||
|
||||
if (errNum != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR,
|
||||
"ApplyStencilKernel (%d) ", errNum);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (endEvent == NULL)
|
||||
{
|
||||
clFinish(_clCommandQueue);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CLEvaluator::EvalStencils(cl_mem src, BufferDescriptor const &srcDesc,
|
||||
cl_mem dst, BufferDescriptor const &dstDesc,
|
||||
cl_mem du, BufferDescriptor const &duDesc,
|
||||
cl_mem dv, BufferDescriptor const &dvDesc,
|
||||
cl_mem sizes,
|
||||
cl_mem offsets,
|
||||
cl_mem indices,
|
||||
cl_mem weights,
|
||||
cl_mem duWeights,
|
||||
cl_mem dvWeights,
|
||||
int start, int end,
|
||||
unsigned int numStartEvents,
|
||||
const cl_event* startEvents,
|
||||
cl_event* endEvent) const {
|
||||
if (end <= start) return true;
|
||||
|
||||
size_t globalWorkSize = (size_t)(end - start);
|
||||
|
||||
BufferDescriptor empty;
|
||||
clSetKernelArg(_stencilDerivKernel, 0, sizeof(cl_mem), &src);
|
||||
clSetKernelArg(_stencilDerivKernel, 1, sizeof(int), &srcDesc.offset);
|
||||
clSetKernelArg(_stencilDerivKernel, 2, sizeof(cl_mem), &dst);
|
||||
clSetKernelArg(_stencilDerivKernel, 3, sizeof(int), &dstDesc.offset);
|
||||
clSetKernelArg(_stencilDerivKernel, 4, sizeof(cl_mem), &du);
|
||||
clSetKernelArg(_stencilDerivKernel, 5, sizeof(int), &duDesc.offset);
|
||||
clSetKernelArg(_stencilDerivKernel, 6, sizeof(int), &duDesc.stride);
|
||||
clSetKernelArg(_stencilDerivKernel, 7, sizeof(cl_mem), &dv);
|
||||
clSetKernelArg(_stencilDerivKernel, 8, sizeof(int), &dvDesc.offset);
|
||||
clSetKernelArg(_stencilDerivKernel, 9, sizeof(int), &dvDesc.stride);
|
||||
clSetKernelArg(_stencilDerivKernel, 10, sizeof(cl_mem), NULL);
|
||||
clSetKernelArg(_stencilDerivKernel, 11, sizeof(int), &empty.offset);
|
||||
clSetKernelArg(_stencilDerivKernel, 12, sizeof(int), &empty.stride);
|
||||
clSetKernelArg(_stencilDerivKernel, 13, sizeof(cl_mem), NULL);
|
||||
clSetKernelArg(_stencilDerivKernel, 14, sizeof(int), &empty.offset);
|
||||
clSetKernelArg(_stencilDerivKernel, 15, sizeof(int), &empty.stride);
|
||||
clSetKernelArg(_stencilDerivKernel, 16, sizeof(cl_mem), NULL);
|
||||
clSetKernelArg(_stencilDerivKernel, 17, sizeof(int), &empty.offset);
|
||||
clSetKernelArg(_stencilDerivKernel, 18, sizeof(int), &empty.stride);
|
||||
clSetKernelArg(_stencilDerivKernel, 19, sizeof(cl_mem), &sizes);
|
||||
clSetKernelArg(_stencilDerivKernel, 20, sizeof(cl_mem), &offsets);
|
||||
clSetKernelArg(_stencilDerivKernel, 21, sizeof(cl_mem), &indices);
|
||||
clSetKernelArg(_stencilDerivKernel, 22, sizeof(cl_mem), &weights);
|
||||
clSetKernelArg(_stencilDerivKernel, 23, sizeof(cl_mem), &duWeights);
|
||||
clSetKernelArg(_stencilDerivKernel, 24, sizeof(cl_mem), &dvWeights);
|
||||
clSetKernelArg(_stencilDerivKernel, 25, sizeof(cl_mem), NULL);
|
||||
clSetKernelArg(_stencilDerivKernel, 26, sizeof(cl_mem), NULL);
|
||||
clSetKernelArg(_stencilDerivKernel, 27, sizeof(cl_mem), NULL);
|
||||
clSetKernelArg(_stencilDerivKernel, 28, sizeof(int), &start);
|
||||
clSetKernelArg(_stencilDerivKernel, 29, sizeof(int), &end);
|
||||
|
||||
cl_int errNum = clEnqueueNDRangeKernel(
|
||||
_clCommandQueue, _stencilDerivKernel, 1, NULL,
|
||||
&globalWorkSize, NULL, numStartEvents, startEvents, endEvent);
|
||||
|
||||
if (errNum != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR,
|
||||
"ApplyStencilKernel (%d) ", errNum);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (endEvent == NULL) {
|
||||
clFinish(_clCommandQueue);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CLEvaluator::EvalStencils(cl_mem src, BufferDescriptor const &srcDesc,
|
||||
cl_mem dst, BufferDescriptor const &dstDesc,
|
||||
cl_mem du, BufferDescriptor const &duDesc,
|
||||
cl_mem dv, BufferDescriptor const &dvDesc,
|
||||
cl_mem duu, BufferDescriptor const &duuDesc,
|
||||
cl_mem duv, BufferDescriptor const &duvDesc,
|
||||
cl_mem dvv, BufferDescriptor const &dvvDesc,
|
||||
cl_mem sizes,
|
||||
cl_mem offsets,
|
||||
cl_mem indices,
|
||||
cl_mem weights,
|
||||
cl_mem duWeights,
|
||||
cl_mem dvWeights,
|
||||
cl_mem duuWeights,
|
||||
cl_mem duvWeights,
|
||||
cl_mem dvvWeights,
|
||||
int start, int end,
|
||||
unsigned int numStartEvents,
|
||||
const cl_event* startEvents,
|
||||
cl_event* endEvent) const {
|
||||
if (end <= start) return true;
|
||||
|
||||
size_t globalWorkSize = (size_t)(end - start);
|
||||
|
||||
clSetKernelArg(_stencilDerivKernel, 0, sizeof(cl_mem), &src);
|
||||
clSetKernelArg(_stencilDerivKernel, 1, sizeof(int), &srcDesc.offset);
|
||||
clSetKernelArg(_stencilDerivKernel, 2, sizeof(cl_mem), &dst);
|
||||
clSetKernelArg(_stencilDerivKernel, 3, sizeof(int), &dstDesc.offset);
|
||||
clSetKernelArg(_stencilDerivKernel, 4, sizeof(cl_mem), &du);
|
||||
clSetKernelArg(_stencilDerivKernel, 5, sizeof(int), &duDesc.offset);
|
||||
clSetKernelArg(_stencilDerivKernel, 6, sizeof(int), &duDesc.stride);
|
||||
clSetKernelArg(_stencilDerivKernel, 7, sizeof(cl_mem), &dv);
|
||||
clSetKernelArg(_stencilDerivKernel, 8, sizeof(int), &dvDesc.offset);
|
||||
clSetKernelArg(_stencilDerivKernel, 9, sizeof(int), &dvDesc.stride);
|
||||
clSetKernelArg(_stencilDerivKernel, 10, sizeof(cl_mem), &duu);
|
||||
clSetKernelArg(_stencilDerivKernel, 11, sizeof(int), &duuDesc.offset);
|
||||
clSetKernelArg(_stencilDerivKernel, 12, sizeof(int), &duuDesc.stride);
|
||||
clSetKernelArg(_stencilDerivKernel, 13, sizeof(cl_mem), &duv);
|
||||
clSetKernelArg(_stencilDerivKernel, 14, sizeof(int), &duvDesc.offset);
|
||||
clSetKernelArg(_stencilDerivKernel, 15, sizeof(int), &duvDesc.stride);
|
||||
clSetKernelArg(_stencilDerivKernel, 16, sizeof(cl_mem), &dvv);
|
||||
clSetKernelArg(_stencilDerivKernel, 17, sizeof(int), &dvvDesc.offset);
|
||||
clSetKernelArg(_stencilDerivKernel, 18, sizeof(int), &dvvDesc.stride);
|
||||
clSetKernelArg(_stencilDerivKernel, 19, sizeof(cl_mem), &sizes);
|
||||
clSetKernelArg(_stencilDerivKernel, 20, sizeof(cl_mem), &offsets);
|
||||
clSetKernelArg(_stencilDerivKernel, 21, sizeof(cl_mem), &indices);
|
||||
clSetKernelArg(_stencilDerivKernel, 22, sizeof(cl_mem), &weights);
|
||||
clSetKernelArg(_stencilDerivKernel, 23, sizeof(cl_mem), &duWeights);
|
||||
clSetKernelArg(_stencilDerivKernel, 24, sizeof(cl_mem), &dvWeights);
|
||||
clSetKernelArg(_stencilDerivKernel, 25, sizeof(cl_mem), &duuWeights);
|
||||
clSetKernelArg(_stencilDerivKernel, 26, sizeof(cl_mem), &duvWeights);
|
||||
clSetKernelArg(_stencilDerivKernel, 27, sizeof(cl_mem), &dvvWeights);
|
||||
clSetKernelArg(_stencilDerivKernel, 28, sizeof(int), &start);
|
||||
clSetKernelArg(_stencilDerivKernel, 29, sizeof(int), &end);
|
||||
|
||||
cl_int errNum = clEnqueueNDRangeKernel(
|
||||
_clCommandQueue, _stencilDerivKernel, 1, NULL,
|
||||
&globalWorkSize, NULL, numStartEvents, startEvents, endEvent);
|
||||
|
||||
if (errNum != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR,
|
||||
"ApplyStencilKernel (%d) ", errNum);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (endEvent == NULL) {
|
||||
clFinish(_clCommandQueue);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CLEvaluator::EvalPatches(cl_mem src, BufferDescriptor const &srcDesc,
|
||||
cl_mem dst, BufferDescriptor const &dstDesc,
|
||||
cl_mem du, BufferDescriptor const &duDesc,
|
||||
cl_mem dv, BufferDescriptor const &dvDesc,
|
||||
int numPatchCoords,
|
||||
cl_mem patchCoordsBuffer,
|
||||
cl_mem patchArrayBuffer,
|
||||
cl_mem patchIndexBuffer,
|
||||
cl_mem patchParamBuffer,
|
||||
unsigned int numStartEvents,
|
||||
const cl_event* startEvents,
|
||||
cl_event* endEvent) const {
|
||||
|
||||
size_t globalWorkSize = (size_t)(numPatchCoords);
|
||||
|
||||
BufferDescriptor empty;
|
||||
clSetKernelArg(_patchKernel, 0, sizeof(cl_mem), &src);
|
||||
clSetKernelArg(_patchKernel, 1, sizeof(int), &srcDesc.offset);
|
||||
clSetKernelArg(_patchKernel, 2, sizeof(cl_mem), &dst);
|
||||
clSetKernelArg(_patchKernel, 3, sizeof(int), &dstDesc.offset);
|
||||
clSetKernelArg(_patchKernel, 4, sizeof(cl_mem), &du);
|
||||
clSetKernelArg(_patchKernel, 5, sizeof(int), &duDesc.offset);
|
||||
clSetKernelArg(_patchKernel, 6, sizeof(int), &duDesc.stride);
|
||||
clSetKernelArg(_patchKernel, 7, sizeof(cl_mem), &dv);
|
||||
clSetKernelArg(_patchKernel, 8, sizeof(int), &dvDesc.offset);
|
||||
clSetKernelArg(_patchKernel, 9, sizeof(int), &dvDesc.stride);
|
||||
clSetKernelArg(_patchKernel, 10, sizeof(cl_mem), NULL);
|
||||
clSetKernelArg(_patchKernel, 11, sizeof(int), &empty.offset);
|
||||
clSetKernelArg(_patchKernel, 12, sizeof(int), &empty.stride);
|
||||
clSetKernelArg(_patchKernel, 13, sizeof(cl_mem), NULL);
|
||||
clSetKernelArg(_patchKernel, 14, sizeof(int), &empty.offset);
|
||||
clSetKernelArg(_patchKernel, 15, sizeof(int), &empty.stride);
|
||||
clSetKernelArg(_patchKernel, 16, sizeof(cl_mem), NULL);
|
||||
clSetKernelArg(_patchKernel, 17, sizeof(int), &empty.offset);
|
||||
clSetKernelArg(_patchKernel, 18, sizeof(int), &empty.stride);
|
||||
clSetKernelArg(_patchKernel, 19, sizeof(cl_mem), &patchCoordsBuffer);
|
||||
clSetKernelArg(_patchKernel, 20, sizeof(cl_mem), &patchArrayBuffer);
|
||||
clSetKernelArg(_patchKernel, 21, sizeof(cl_mem), &patchIndexBuffer);
|
||||
clSetKernelArg(_patchKernel, 22, sizeof(cl_mem), &patchParamBuffer);
|
||||
|
||||
cl_int errNum = clEnqueueNDRangeKernel(
|
||||
_clCommandQueue, _patchKernel, 1, NULL,
|
||||
&globalWorkSize, NULL, numStartEvents, startEvents, endEvent);
|
||||
|
||||
if (errNum != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR,
|
||||
"ApplyPatchKernel (%d) ", errNum);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (endEvent == NULL) {
|
||||
clFinish(_clCommandQueue);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CLEvaluator::EvalPatches(cl_mem src, BufferDescriptor const &srcDesc,
|
||||
cl_mem dst, BufferDescriptor const &dstDesc,
|
||||
cl_mem du, BufferDescriptor const &duDesc,
|
||||
cl_mem dv, BufferDescriptor const &dvDesc,
|
||||
cl_mem duu, BufferDescriptor const &duuDesc,
|
||||
cl_mem duv, BufferDescriptor const &duvDesc,
|
||||
cl_mem dvv, BufferDescriptor const &dvvDesc,
|
||||
int numPatchCoords,
|
||||
cl_mem patchCoordsBuffer,
|
||||
cl_mem patchArrayBuffer,
|
||||
cl_mem patchIndexBuffer,
|
||||
cl_mem patchParamBuffer,
|
||||
unsigned int numStartEvents,
|
||||
const cl_event* startEvents,
|
||||
cl_event* endEvent) const {
|
||||
|
||||
size_t globalWorkSize = (size_t)(numPatchCoords);
|
||||
|
||||
clSetKernelArg(_patchKernel, 0, sizeof(cl_mem), &src);
|
||||
clSetKernelArg(_patchKernel, 1, sizeof(int), &srcDesc.offset);
|
||||
clSetKernelArg(_patchKernel, 2, sizeof(cl_mem), &dst);
|
||||
clSetKernelArg(_patchKernel, 3, sizeof(int), &dstDesc.offset);
|
||||
clSetKernelArg(_patchKernel, 4, sizeof(cl_mem), &du);
|
||||
clSetKernelArg(_patchKernel, 5, sizeof(int), &duDesc.offset);
|
||||
clSetKernelArg(_patchKernel, 6, sizeof(int), &duDesc.stride);
|
||||
clSetKernelArg(_patchKernel, 7, sizeof(cl_mem), &dv);
|
||||
clSetKernelArg(_patchKernel, 8, sizeof(int), &dvDesc.offset);
|
||||
clSetKernelArg(_patchKernel, 9, sizeof(int), &dvDesc.stride);
|
||||
clSetKernelArg(_patchKernel, 10, sizeof(cl_mem), &duu);
|
||||
clSetKernelArg(_patchKernel, 11, sizeof(int), &duuDesc.offset);
|
||||
clSetKernelArg(_patchKernel, 12, sizeof(int), &duuDesc.stride);
|
||||
clSetKernelArg(_patchKernel, 13, sizeof(cl_mem), &duv);
|
||||
clSetKernelArg(_patchKernel, 14, sizeof(int), &duvDesc.offset);
|
||||
clSetKernelArg(_patchKernel, 15, sizeof(int), &duvDesc.stride);
|
||||
clSetKernelArg(_patchKernel, 16, sizeof(cl_mem), &dvv);
|
||||
clSetKernelArg(_patchKernel, 17, sizeof(int), &dvvDesc.offset);
|
||||
clSetKernelArg(_patchKernel, 18, sizeof(int), &dvvDesc.stride);
|
||||
clSetKernelArg(_patchKernel, 19, sizeof(cl_mem), &patchCoordsBuffer);
|
||||
clSetKernelArg(_patchKernel, 20, sizeof(cl_mem), &patchArrayBuffer);
|
||||
clSetKernelArg(_patchKernel, 21, sizeof(cl_mem), &patchIndexBuffer);
|
||||
clSetKernelArg(_patchKernel, 22, sizeof(cl_mem), &patchParamBuffer);
|
||||
|
||||
cl_int errNum = clEnqueueNDRangeKernel(
|
||||
_clCommandQueue, _patchKernel, 1, NULL,
|
||||
&globalWorkSize, NULL, numStartEvents, startEvents, endEvent);
|
||||
|
||||
if (errNum != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR,
|
||||
"ApplyPatchKernel (%d) ", errNum);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (endEvent == NULL) {
|
||||
clFinish(_clCommandQueue);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
void
|
||||
CLEvaluator::Synchronize(cl_command_queue clCommandQueue) {
|
||||
clFinish(clCommandQueue);
|
||||
}
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
2636
src/osd/opensubdiv/osd/clEvaluator.h
Normal file
2636
src/osd/opensubdiv/osd/clEvaluator.h
Normal file
File diff suppressed because it is too large
Load Diff
152
src/osd/opensubdiv/osd/clGLVertexBuffer.cpp
Normal file
152
src/osd/opensubdiv/osd/clGLVertexBuffer.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "glLoader.h"
|
||||
|
||||
#include "../osd/clGLVertexBuffer.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
CLGLVertexBuffer::CLGLVertexBuffer(int numElements,
|
||||
int numVertices,
|
||||
cl_context /* clContext */)
|
||||
: _numElements(numElements), _numVertices(numVertices),
|
||||
_vbo(0), _clQueue(0), _clMemory(0), _clMapped(false) {
|
||||
|
||||
// Initialize internal OpenGL loader library if necessary
|
||||
OpenSubdiv::internal::GLLoader::libraryInitializeGL();
|
||||
}
|
||||
|
||||
CLGLVertexBuffer::~CLGLVertexBuffer() {
|
||||
|
||||
unmap();
|
||||
clReleaseMemObject(_clMemory);
|
||||
glDeleteBuffers(1, &_vbo);
|
||||
}
|
||||
|
||||
CLGLVertexBuffer *
|
||||
CLGLVertexBuffer::Create(int numElements, int numVertices, cl_context clContext)
|
||||
{
|
||||
CLGLVertexBuffer *instance =
|
||||
new CLGLVertexBuffer(numElements, numVertices, clContext);
|
||||
if (instance->allocate(clContext)) return instance;
|
||||
delete instance;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CLGLVertexBuffer::UpdateData(const float *src, int startVertex, int numVertices,
|
||||
cl_command_queue queue) {
|
||||
|
||||
size_t size = numVertices * _numElements * sizeof(float);
|
||||
size_t offset = startVertex * _numElements * sizeof(float);
|
||||
|
||||
map(queue);
|
||||
clEnqueueWriteBuffer(queue, _clMemory, true, offset, size, src, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
CLGLVertexBuffer::GetNumElements() const {
|
||||
|
||||
return _numElements;
|
||||
}
|
||||
|
||||
int
|
||||
CLGLVertexBuffer::GetNumVertices() const {
|
||||
|
||||
return _numVertices;
|
||||
}
|
||||
|
||||
cl_mem
|
||||
CLGLVertexBuffer::BindCLBuffer(cl_command_queue queue) {
|
||||
|
||||
map(queue);
|
||||
return _clMemory;
|
||||
}
|
||||
|
||||
GLuint
|
||||
CLGLVertexBuffer::BindVBO(void * /*deviceContext*/) {
|
||||
|
||||
unmap();
|
||||
return _vbo;
|
||||
}
|
||||
|
||||
bool
|
||||
CLGLVertexBuffer::allocate(cl_context clContext) {
|
||||
|
||||
assert(clContext);
|
||||
|
||||
// create GL buffer first
|
||||
int size = _numElements * _numVertices * sizeof(float);
|
||||
|
||||
#if defined(GL_ARB_direct_state_access)
|
||||
if (OSD_OPENGL_HAS(ARB_direct_state_access)) {
|
||||
glCreateBuffers(1, &_vbo);
|
||||
glNamedBufferData(_vbo, size, 0, GL_DYNAMIC_DRAW);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
GLint prev = 0;
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &prev);
|
||||
glGenBuffers(1, &_vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, prev);
|
||||
}
|
||||
|
||||
// register vbo as cl memory
|
||||
cl_int err;
|
||||
_clMemory = clCreateFromGLBuffer(clContext,
|
||||
CL_MEM_READ_WRITE, _vbo, &err);
|
||||
|
||||
if (err != CL_SUCCESS) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CLGLVertexBuffer::map(cl_command_queue queue) {
|
||||
|
||||
if (_clMapped) return; // XXX: what if another queue is given?
|
||||
_clQueue = queue;
|
||||
clEnqueueAcquireGLObjects(queue, 1, &_clMemory, 0, 0, 0);
|
||||
_clMapped = true;
|
||||
}
|
||||
|
||||
void
|
||||
CLGLVertexBuffer::unmap() {
|
||||
|
||||
if (! _clMapped) return;
|
||||
clEnqueueReleaseGLObjects(_clQueue, 1, &_clMemory, 0, 0, 0);
|
||||
_clMapped = false;
|
||||
}
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
119
src/osd/opensubdiv/osd/clGLVertexBuffer.h
Normal file
119
src/osd/opensubdiv/osd/clGLVertexBuffer.h
Normal file
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_OSD_CL_GL_VERTEX_BUFFER_H
|
||||
#define OPENSUBDIV3_OSD_CL_GL_VERTEX_BUFFER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../osd/opengl.h"
|
||||
#include "../osd/opencl.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
///
|
||||
/// \brief Concrete vertex buffer class for OpenCL subdivision and OpenGL drawing.
|
||||
///
|
||||
/// CLGLVertexBuffer implements CLVertexBufferInterface and
|
||||
/// GLVertexBufferInterface.
|
||||
///
|
||||
/// The buffer interop between OpenCL and GL is handled automatically when a
|
||||
/// client calls BindCLBuffer and BindVBO methods.
|
||||
///
|
||||
class CLGLVertexBuffer {
|
||||
public:
|
||||
/// Creator. Returns NULL if error.
|
||||
static CLGLVertexBuffer * Create(int numElements,
|
||||
int numVertices,
|
||||
cl_context clContext);
|
||||
|
||||
template <typename DEVICE_CONTEXT>
|
||||
static CLGLVertexBuffer * Create(int numElements, int numVertices,
|
||||
DEVICE_CONTEXT context) {
|
||||
return Create(numElements, numVertices, context->GetContext());
|
||||
}
|
||||
|
||||
/// Destructor.
|
||||
~CLGLVertexBuffer();
|
||||
|
||||
/// This method is meant to be used in client code in order to provide
|
||||
/// coarse vertices data to Osd.
|
||||
void UpdateData(const float *src, int startVertex, int numVertices,
|
||||
cl_command_queue clQueue);
|
||||
|
||||
template<typename DEVICE_CONTEXT>
|
||||
void UpdateData(const float *src, int startVertex, int numVertices,
|
||||
DEVICE_CONTEXT context) {
|
||||
UpdateData(src, startVertex, numVertices, context->GetCommandQueue());
|
||||
}
|
||||
|
||||
/// Returns how many elements defined in this vertex buffer.
|
||||
int GetNumElements() const;
|
||||
|
||||
/// Returns how many vertices allocated in this vertex buffer.
|
||||
int GetNumVertices() const;
|
||||
|
||||
/// Returns the CL memory object. GL buffer will be mapped to CL memory
|
||||
/// space if necessary.
|
||||
cl_mem BindCLBuffer(cl_command_queue queue);
|
||||
|
||||
/// Returns the GL buffer object. If the buffer is mapped to CL memory
|
||||
/// space, it will be unmapped back to GL.
|
||||
GLuint BindVBO(void *deviceContext = NULL);
|
||||
|
||||
protected:
|
||||
/// Constructor.
|
||||
CLGLVertexBuffer(int numElements, int numVertices, cl_context clContext);
|
||||
|
||||
/// Allocates VBO for this buffer and register as a CL resource.
|
||||
/// Returns true if success.
|
||||
bool allocate(cl_context clContext);
|
||||
|
||||
/// Acquires a resource from GL.
|
||||
void map(cl_command_queue queue);
|
||||
|
||||
/// Releases a resource to GL.
|
||||
void unmap();
|
||||
|
||||
private:
|
||||
int _numElements;
|
||||
int _numVertices;
|
||||
GLuint _vbo;
|
||||
cl_command_queue _clQueue;
|
||||
cl_mem _clMemory;
|
||||
|
||||
bool _clMapped;
|
||||
};
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_OSD_CL_GL_VERTEX_BUFFER_H
|
||||
249
src/osd/opensubdiv/osd/clKernel.cl
Normal file
249
src/osd/opensubdiv/osd/clKernel.cl
Normal file
@@ -0,0 +1,249 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
struct Vertex {
|
||||
float v[LENGTH];
|
||||
};
|
||||
|
||||
static void clear(struct Vertex *vertex) {
|
||||
for (int i = 0; i < LENGTH; i++) {
|
||||
vertex->v[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static void addWithWeight(struct Vertex *dst,
|
||||
__global float *srcOrigin,
|
||||
int index, float weight) {
|
||||
|
||||
__global float *src = srcOrigin + index * SRC_STRIDE;
|
||||
for (int i = 0; i < LENGTH; ++i) {
|
||||
dst->v[i] += src[i] * weight;
|
||||
}
|
||||
}
|
||||
|
||||
static void writeVertex(__global float *dstOrigin,
|
||||
int index,
|
||||
struct Vertex *src) {
|
||||
|
||||
__global float *dst = dstOrigin + index * DST_STRIDE;
|
||||
for (int i = 0; i < LENGTH; ++i) {
|
||||
dst[i] = src->v[i];
|
||||
}
|
||||
}
|
||||
static void writeVertexStride(__global float *dstOrigin,
|
||||
int index,
|
||||
struct Vertex *src,
|
||||
int stride) {
|
||||
|
||||
__global float *dst = dstOrigin + index * stride;
|
||||
for (int i = 0; i < LENGTH; ++i) {
|
||||
dst[i] = src->v[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__kernel void computeStencils(
|
||||
__global float * src, int srcOffset,
|
||||
__global float * dst, int dstOffset,
|
||||
__global int * sizes,
|
||||
__global int * offsets,
|
||||
__global int * indices,
|
||||
__global float * weights,
|
||||
int batchStart, int batchEnd) {
|
||||
|
||||
int current = get_global_id(0) + batchStart;
|
||||
|
||||
if (current>=batchEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct Vertex v;
|
||||
clear(&v);
|
||||
|
||||
int size = sizes[current],
|
||||
offset = offsets[current];
|
||||
|
||||
src += srcOffset;
|
||||
dst += dstOffset;
|
||||
|
||||
for (int i=0; i<size; ++i) {
|
||||
addWithWeight(&v, src, indices[offset+i], weights[offset+i]);
|
||||
}
|
||||
|
||||
writeVertex(dst, current, &v);
|
||||
}
|
||||
|
||||
__kernel void computeStencilsDerivatives(
|
||||
__global float * src, int srcOffset,
|
||||
__global float * dst, int dstOffset,
|
||||
__global float * du, int duOffset, int duStride,
|
||||
__global float * dv, int dvOffset, int dvStride,
|
||||
__global float * duu, int duuOffset, int duuStride,
|
||||
__global float * duv, int duvOffset, int duvStride,
|
||||
__global float * dvv, int dvvOffset, int dvvStride,
|
||||
__global int * sizes,
|
||||
__global int * offsets,
|
||||
__global int * indices,
|
||||
__global float * weights,
|
||||
__global float * duWeights,
|
||||
__global float * dvWeights,
|
||||
__global float * duuWeights,
|
||||
__global float * duvWeights,
|
||||
__global float * dvvWeights,
|
||||
int batchStart, int batchEnd) {
|
||||
|
||||
int current = get_global_id(0) + batchStart;
|
||||
|
||||
if (current>=batchEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct Vertex v, vdu, vdv, vduu, vduv, vdvv;
|
||||
clear(&v);
|
||||
clear(&vdu);
|
||||
clear(&vdv);
|
||||
clear(&vduu);
|
||||
clear(&vduv);
|
||||
clear(&vdvv);
|
||||
|
||||
int size = sizes[current],
|
||||
offset = offsets[current];
|
||||
|
||||
if (src) src += srcOffset;
|
||||
if (dst) dst += dstOffset;
|
||||
if (du) du += duOffset;
|
||||
if (dv) dv += dvOffset;
|
||||
if (duu) duu += duuOffset;
|
||||
if (duv) duv += duvOffset;
|
||||
if (dvv) dvv += dvvOffset;
|
||||
|
||||
for (int i=0; i<size; ++i) {
|
||||
int ofs = offset + i;
|
||||
int vid = indices[ofs];
|
||||
if (weights) addWithWeight( &v, src, vid, weights[ofs]);
|
||||
if (duWeights) addWithWeight(&vdu, src, vid, duWeights[ofs]);
|
||||
if (dvWeights) addWithWeight(&vdv, src, vid, dvWeights[ofs]);
|
||||
if (duuWeights) addWithWeight(&vduu, src, vid, duuWeights[ofs]);
|
||||
if (duvWeights) addWithWeight(&vduv, src, vid, duvWeights[ofs]);
|
||||
if (dvvWeights) addWithWeight(&vdvv, src, vid, dvvWeights[ofs]);
|
||||
}
|
||||
|
||||
if (dst) writeVertex (dst, current, &v);
|
||||
if (du) writeVertexStride(du, current, &vdu, duStride);
|
||||
if (dv) writeVertexStride(dv, current, &vdv, dvStride);
|
||||
if (duu) writeVertexStride(duu, current, &vduu, duuStride);
|
||||
if (duv) writeVertexStride(duv, current, &vduv, duvStride);
|
||||
if (dvv) writeVertexStride(dvv, current, &vdvv, dvvStride);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
__kernel void computePatches(__global float *src, int srcOffset,
|
||||
__global float *dst, int dstOffset,
|
||||
__global float *du, int duOffset, int duStride,
|
||||
__global float *dv, int dvOffset, int dvStride,
|
||||
__global float *duu, int duuOffset, int duuStride,
|
||||
__global float *duv, int duvOffset, int duvStride,
|
||||
__global float *dvv, int dvvOffset, int dvvStride,
|
||||
__global struct OsdPatchCoord *patchCoords,
|
||||
__global struct OsdPatchArray *patchArrayBuffer,
|
||||
__global int *patchIndexBuffer,
|
||||
__global struct OsdPatchParam *patchParamBuffer) {
|
||||
int current = get_global_id(0);
|
||||
|
||||
if (src) src += srcOffset;
|
||||
if (dst) dst += dstOffset;
|
||||
if (du) du += duOffset;
|
||||
if (dv) dv += dvOffset;
|
||||
if (duu) duu += duuOffset;
|
||||
if (duv) duv += duvOffset;
|
||||
if (dvv) dvv += dvvOffset;
|
||||
|
||||
struct OsdPatchCoord coord = patchCoords[current];
|
||||
struct OsdPatchArray array = patchArrayBuffer[coord.arrayIndex];
|
||||
struct OsdPatchParam param = patchParamBuffer[coord.patchIndex];
|
||||
|
||||
int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
|
||||
|
||||
float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
|
||||
int nPoints = OsdEvaluatePatchBasis(patchType, param,
|
||||
coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
|
||||
|
||||
int indexBase = array.indexBase + array.stride *
|
||||
(coord.patchIndex - array.primitiveIdBase);
|
||||
|
||||
struct Vertex v;
|
||||
clear(&v);
|
||||
for (int i = 0; i < nPoints; ++i) {
|
||||
int index = patchIndexBuffer[indexBase + i];
|
||||
addWithWeight(&v, src, index, wP[i]);
|
||||
}
|
||||
writeVertex(dst, current, &v);
|
||||
|
||||
if (du) {
|
||||
struct Vertex vdu;
|
||||
clear(&vdu);
|
||||
for (int i = 0; i < nPoints; ++i) {
|
||||
int index = patchIndexBuffer[indexBase + i];
|
||||
addWithWeight(&vdu, src, index, wDu[i]);
|
||||
}
|
||||
writeVertexStride(du, current, &vdu, duStride);
|
||||
}
|
||||
if (dv) {
|
||||
struct Vertex vdv;
|
||||
clear(&vdv);
|
||||
for (int i = 0; i < nPoints; ++i) {
|
||||
int index = patchIndexBuffer[indexBase + i];
|
||||
addWithWeight(&vdv, src, index, wDv[i]);
|
||||
}
|
||||
writeVertexStride(dv, current, &vdv, dvStride);
|
||||
}
|
||||
if (duu) {
|
||||
struct Vertex vduu;
|
||||
clear(&vduu);
|
||||
for (int i = 0; i < nPoints; ++i) {
|
||||
int index = patchIndexBuffer[indexBase + i];
|
||||
addWithWeight(&vduu, src, index, wDuu[i]);
|
||||
}
|
||||
writeVertexStride(duu, current, &vduu, duuStride);
|
||||
}
|
||||
if (duv) {
|
||||
struct Vertex vduv;
|
||||
clear(&vduv);
|
||||
for (int i = 0; i < nPoints; ++i) {
|
||||
int index = patchIndexBuffer[indexBase + i];
|
||||
addWithWeight(&vduv, src, index, wDuv[i]);
|
||||
}
|
||||
writeVertexStride(duv, current, &vduv, duvStride);
|
||||
}
|
||||
if (dvv) {
|
||||
struct Vertex vdvv;
|
||||
clear(&vdvv);
|
||||
for (int i = 0; i < nPoints; ++i) {
|
||||
int index = patchIndexBuffer[indexBase + i];
|
||||
addWithWeight(&vdvv, src, index, wDvv[i]);
|
||||
}
|
||||
writeVertexStride(dvv, current, &vdvv, dvvStride);
|
||||
}
|
||||
}
|
||||
170
src/osd/opensubdiv/osd/clPatchTable.cpp
Normal file
170
src/osd/opensubdiv/osd/clPatchTable.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../osd/clPatchTable.h"
|
||||
|
||||
#include "../far/error.h"
|
||||
#include "../far/patchTable.h"
|
||||
#include "../osd/opencl.h"
|
||||
#include "../osd/cpuPatchTable.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
CLPatchTable::CLPatchTable() :
|
||||
_patchArrays(NULL), _indexBuffer(NULL), _patchParamBuffer(NULL) {
|
||||
}
|
||||
|
||||
CLPatchTable::~CLPatchTable() {
|
||||
if (_patchArrays) clReleaseMemObject(_patchArrays);
|
||||
if (_indexBuffer) clReleaseMemObject(_indexBuffer);
|
||||
if (_patchParamBuffer) clReleaseMemObject(_patchParamBuffer);
|
||||
if (_varyingPatchArrays) clReleaseMemObject(_varyingPatchArrays);
|
||||
if (_varyingIndexBuffer) clReleaseMemObject(_varyingIndexBuffer);
|
||||
for (int fvc=0; fvc<(int)_fvarPatchArrays.size(); ++fvc) {
|
||||
if (_fvarPatchArrays[fvc]) clReleaseMemObject(_fvarPatchArrays[fvc]);
|
||||
}
|
||||
for (int fvc=0; fvc<(int)_fvarIndexBuffers.size(); ++fvc) {
|
||||
if (_fvarIndexBuffers[fvc]) clReleaseMemObject(_fvarIndexBuffers[fvc]);
|
||||
}
|
||||
for (int fvc=0; fvc<(int)_fvarParamBuffers.size(); ++fvc) {
|
||||
if (_fvarParamBuffers[fvc]) clReleaseMemObject(_fvarParamBuffers[fvc]);
|
||||
}
|
||||
}
|
||||
|
||||
CLPatchTable *
|
||||
CLPatchTable::Create(Far::PatchTable const *farPatchTable,
|
||||
cl_context clContext) {
|
||||
CLPatchTable *instance = new CLPatchTable();
|
||||
if (instance->allocate(farPatchTable, clContext)) return instance;
|
||||
delete instance;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
CLPatchTable::allocate(Far::PatchTable const *farPatchTable, cl_context clContext) {
|
||||
CpuPatchTable patchTable(farPatchTable);
|
||||
|
||||
size_t numPatchArrays = patchTable.GetNumPatchArrays();
|
||||
size_t indexSize = patchTable.GetPatchIndexSize();
|
||||
size_t patchParamSize = patchTable.GetPatchParamSize();
|
||||
|
||||
cl_int err = 0;
|
||||
_patchArrays = clCreateBuffer(clContext,
|
||||
CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR,
|
||||
numPatchArrays * sizeof(Osd::PatchArray),
|
||||
(void*)patchTable.GetPatchArrayBuffer(),
|
||||
&err);
|
||||
if (err != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "clCreateBuffer: %d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
_indexBuffer = clCreateBuffer(clContext,
|
||||
CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR,
|
||||
indexSize * sizeof(int),
|
||||
(void*)patchTable.GetPatchIndexBuffer(),
|
||||
&err);
|
||||
if (err != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "clCreateBuffer: %d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
_patchParamBuffer = clCreateBuffer(clContext,
|
||||
CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR,
|
||||
patchParamSize * sizeof(Osd::PatchParam),
|
||||
(void*)patchTable.GetPatchParamBuffer(),
|
||||
&err);
|
||||
if (err != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "clCreateBuffer: %d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
_varyingPatchArrays = clCreateBuffer(clContext,
|
||||
CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR,
|
||||
numPatchArrays * sizeof(Osd::PatchArray),
|
||||
(void*)patchTable.GetVaryingPatchArrayBuffer(),
|
||||
&err);
|
||||
if (err != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "clCreateBuffer: %d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
_varyingIndexBuffer = clCreateBuffer(clContext,
|
||||
CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR,
|
||||
patchTable.GetVaryingPatchIndexSize() * sizeof(int),
|
||||
(void*)patchTable.GetVaryingPatchIndexBuffer(),
|
||||
&err);
|
||||
if (err != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "clCreateBuffer: %d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t numFVarChannels = patchTable.GetNumFVarChannels();
|
||||
_fvarPatchArrays.resize(numFVarChannels, 0);
|
||||
_fvarIndexBuffers.resize(numFVarChannels, 0);
|
||||
_fvarParamBuffers.resize(numFVarChannels, 0);
|
||||
for (int fvc=0; fvc<(int)numFVarChannels; ++fvc) {
|
||||
_fvarPatchArrays[fvc] = clCreateBuffer(clContext,
|
||||
CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR,
|
||||
numPatchArrays * sizeof(Osd::PatchArray),
|
||||
(void*)patchTable.GetFVarPatchArrayBuffer(fvc),
|
||||
&err);
|
||||
if (err != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "clCreateBuffer: %d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
_fvarIndexBuffers[fvc] = clCreateBuffer(clContext,
|
||||
CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR,
|
||||
patchTable.GetFVarPatchIndexSize(fvc) * sizeof(int),
|
||||
(void*)patchTable.GetFVarPatchIndexBuffer(fvc),
|
||||
&err);
|
||||
if (err != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "clCreateBuffer: %d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
_fvarParamBuffers[fvc] = clCreateBuffer(clContext,
|
||||
CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR,
|
||||
patchTable.GetFVarPatchParamSize(fvc) * sizeof(Osd::PatchParam),
|
||||
(void*)patchTable.GetFVarPatchParamBuffer(fvc),
|
||||
&err);
|
||||
if (err != CL_SUCCESS) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "clCreateBuffer: %d", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
119
src/osd/opensubdiv/osd/clPatchTable.h
Normal file
119
src/osd/opensubdiv/osd/clPatchTable.h
Normal file
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_OSD_CL_PATCH_TABLE_H
|
||||
#define OPENSUBDIV3_OSD_CL_PATCH_TABLE_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../osd/opencl.h"
|
||||
#include "../osd/nonCopyable.h"
|
||||
#include "../osd/types.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far{
|
||||
class PatchTable;
|
||||
};
|
||||
|
||||
namespace Osd {
|
||||
|
||||
/// \brief CL patch table
|
||||
///
|
||||
/// This class is a CL buffer representation of Far::PatchTable.
|
||||
///
|
||||
/// CLEvaluator consumes this table to evaluate on the patches.
|
||||
///
|
||||
///
|
||||
class CLPatchTable : private NonCopyable<CLPatchTable> {
|
||||
public:
|
||||
/// Creator. Returns NULL if error
|
||||
static CLPatchTable *Create(Far::PatchTable const *patchTable,
|
||||
cl_context clContext);
|
||||
|
||||
template <typename DEVICE_CONTEXT>
|
||||
static CLPatchTable * Create(Far::PatchTable const *patchTable,
|
||||
DEVICE_CONTEXT context) {
|
||||
return Create(patchTable, context->GetContext());
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
~CLPatchTable();
|
||||
|
||||
/// Returns the CL memory of the array of Osd::PatchArray buffer
|
||||
cl_mem GetPatchArrayBuffer() const { return _patchArrays; }
|
||||
|
||||
/// Returns the CL memory of the patch control vertices
|
||||
cl_mem GetPatchIndexBuffer() const { return _indexBuffer; }
|
||||
|
||||
/// Returns the CL memory of the array of Osd::PatchParam buffer
|
||||
cl_mem GetPatchParamBuffer() const { return _patchParamBuffer; }
|
||||
|
||||
/// Returns the CL memory of the array of Osd::PatchArray buffer
|
||||
cl_mem GetVaryingPatchArrayBuffer() const { return _varyingPatchArrays; }
|
||||
|
||||
/// Returns the CL memory of the varying control vertices
|
||||
cl_mem GetVaryingPatchIndexBuffer() const { return _varyingIndexBuffer; }
|
||||
|
||||
/// Returns the number of face-varying channel buffers
|
||||
int GetNumFVarChannels() const { return (int)_fvarPatchArrays.size(); }
|
||||
|
||||
/// Returns the CL memory of the array of Osd::PatchArray buffer
|
||||
cl_mem GetFVarPatchArrayBuffer(int fvarChannel = 0) const { return _fvarPatchArrays[fvarChannel]; }
|
||||
|
||||
/// Returns the CL memory of the face-varying control vertices
|
||||
cl_mem GetFVarPatchIndexBuffer(int fvarChannel = 0) const { return _fvarIndexBuffers[fvarChannel]; }
|
||||
|
||||
/// Returns the CL memory of the array of Osd::PatchParam buffer
|
||||
cl_mem GetFVarPatchParamBuffer(int fvarChannel = 0) const { return _fvarParamBuffers[fvarChannel]; }
|
||||
|
||||
protected:
|
||||
CLPatchTable();
|
||||
|
||||
bool allocate(Far::PatchTable const *patchTable, cl_context clContext);
|
||||
|
||||
cl_mem _patchArrays;
|
||||
cl_mem _indexBuffer;
|
||||
cl_mem _patchParamBuffer;
|
||||
|
||||
cl_mem _varyingPatchArrays;
|
||||
cl_mem _varyingIndexBuffer;
|
||||
|
||||
std::vector<cl_mem> _fvarPatchArrays;
|
||||
std::vector<cl_mem> _fvarIndexBuffers;
|
||||
std::vector<cl_mem> _fvarParamBuffers;
|
||||
|
||||
};
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_OSD_CL_PATCH_TABLE_H
|
||||
102
src/osd/opensubdiv/osd/clVertexBuffer.cpp
Normal file
102
src/osd/opensubdiv/osd/clVertexBuffer.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../osd/clVertexBuffer.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
CLVertexBuffer::CLVertexBuffer(int numElements, int numVertices,
|
||||
cl_context /* clContext */)
|
||||
: _numElements(numElements), _numVertices(numVertices), _clMemory(NULL) {
|
||||
|
||||
}
|
||||
|
||||
CLVertexBuffer::~CLVertexBuffer() {
|
||||
|
||||
clReleaseMemObject(_clMemory);
|
||||
}
|
||||
|
||||
CLVertexBuffer *
|
||||
CLVertexBuffer::Create(int numElements, int numVertices,
|
||||
cl_context clContext) {
|
||||
CLVertexBuffer *instance =
|
||||
new CLVertexBuffer(numElements, numVertices, clContext);
|
||||
if (instance->allocate(clContext)) return instance;
|
||||
delete instance;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CLVertexBuffer::UpdateData(const float *src, int startVertex, int numVertices, cl_command_queue queue,
|
||||
cl_event* startEvents, unsigned int numStartEvents, cl_event* endEvent) {
|
||||
|
||||
size_t size = _numElements * numVertices * sizeof(float);
|
||||
size_t offset = startVertex * _numElements * sizeof(float);
|
||||
|
||||
cl_bool blocking = (endEvent == NULL) ? CL_TRUE : CL_FALSE;
|
||||
cl_int err = clEnqueueWriteBuffer(queue, _clMemory, blocking, offset, size, src, numStartEvents, startEvents, endEvent);
|
||||
assert(err == CL_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
CLVertexBuffer::GetNumElements() const {
|
||||
|
||||
return _numElements;
|
||||
}
|
||||
|
||||
int
|
||||
CLVertexBuffer::GetNumVertices() const {
|
||||
|
||||
return _numVertices;
|
||||
}
|
||||
|
||||
cl_mem
|
||||
CLVertexBuffer::BindCLBuffer(cl_command_queue /* queue */) {
|
||||
|
||||
return _clMemory;
|
||||
}
|
||||
|
||||
bool
|
||||
CLVertexBuffer::allocate(cl_context clContext) {
|
||||
assert(clContext);
|
||||
int size = _numVertices * _numElements * sizeof(float);
|
||||
cl_int err;
|
||||
|
||||
_clMemory = clCreateBuffer(clContext, CL_MEM_READ_WRITE, size, NULL, &err);
|
||||
|
||||
if (err != CL_SUCCESS) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
99
src/osd/opensubdiv/osd/clVertexBuffer.h
Normal file
99
src/osd/opensubdiv/osd/clVertexBuffer.h
Normal file
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_OSD_CL_VERTEX_BUFFER_H
|
||||
#define OPENSUBDIV3_OSD_CL_VERTEX_BUFFER_H
|
||||
|
||||
#include "../version.h"
|
||||
#include "../osd/opencl.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
///
|
||||
/// \brief Concrete vertex buffer class for OpenCL subdivision.
|
||||
///
|
||||
/// CLVertexBuffer implements CLVertexBufferInterface. An instance of this
|
||||
/// buffer class can be passed to CLEvaluator
|
||||
///
|
||||
class CLVertexBuffer {
|
||||
|
||||
public:
|
||||
/// Creator. Returns NULL if error.
|
||||
static CLVertexBuffer * Create(int numElements, int numVertices, cl_context clContext);
|
||||
|
||||
template <typename DEVICE_CONTEXT>
|
||||
static CLVertexBuffer * Create(int numElements, int numVertices,
|
||||
DEVICE_CONTEXT context) {
|
||||
return Create(numElements, numVertices, context->GetContext());
|
||||
}
|
||||
|
||||
/// Destructor.
|
||||
~CLVertexBuffer();
|
||||
|
||||
/// This method is meant to be used in client code in order to provide coarse
|
||||
/// vertices data to Osd.
|
||||
void UpdateData(const float *src, int startVertex, int numVertices, cl_command_queue clQueue,
|
||||
cl_event* startEvents = NULL, unsigned int numStartEvents = 0, cl_event* endEvent = NULL);
|
||||
|
||||
template<typename DEVICE_CONTEXT>
|
||||
void UpdateData(const float *src, int startVertex, int numVertices,
|
||||
DEVICE_CONTEXT context,
|
||||
cl_event* startEvents = NULL, unsigned int numStartEvents = 0, cl_event* endEvent = NULL) {
|
||||
UpdateData(src, startVertex, numVertices, context->GetCommandQueue(), startEvents, numStartEvents, endEvent);
|
||||
}
|
||||
|
||||
/// Returns how many elements defined in this vertex buffer.
|
||||
int GetNumElements() const;
|
||||
|
||||
/// Returns how many vertices allocated in this vertex buffer.
|
||||
int GetNumVertices() const;
|
||||
|
||||
/// Returns the CL memory object.
|
||||
cl_mem BindCLBuffer(cl_command_queue queue);
|
||||
|
||||
protected:
|
||||
/// Constructor.
|
||||
CLVertexBuffer(int numElements, int numVertices, cl_context clContext);
|
||||
|
||||
/// Allocates CL memory for this buffer.
|
||||
/// Returns true if success.
|
||||
bool allocate(cl_context clContext);
|
||||
|
||||
private:
|
||||
int _numElements;
|
||||
int _numVertices;
|
||||
cl_mem _clMemory;
|
||||
};
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_OSD_CL_VERTEX_BUFFER_H
|
||||
140
src/osd/opensubdiv/osd/cpuD3D11VertexBuffer.cpp
Normal file
140
src/osd/opensubdiv/osd/cpuD3D11VertexBuffer.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../osd/cpuD3D11VertexBuffer.h"
|
||||
#include "../far/error.h"
|
||||
|
||||
#include <D3D11.h>
|
||||
#include <cassert>
|
||||
#include <string.h>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
CpuD3D11VertexBuffer::CpuD3D11VertexBuffer(int numElements, int numVertices)
|
||||
: _numElements(numElements), _numVertices(numVertices),
|
||||
_d3d11Buffer(NULL), _cpuBuffer(NULL) {
|
||||
}
|
||||
|
||||
CpuD3D11VertexBuffer::~CpuD3D11VertexBuffer() {
|
||||
|
||||
delete[] _cpuBuffer;
|
||||
|
||||
if (_d3d11Buffer) _d3d11Buffer->Release();
|
||||
}
|
||||
|
||||
CpuD3D11VertexBuffer *
|
||||
CpuD3D11VertexBuffer::Create(int numElements, int numVertices,
|
||||
ID3D11DeviceContext *deviceContext) {
|
||||
|
||||
CpuD3D11VertexBuffer *instance =
|
||||
new CpuD3D11VertexBuffer(numElements, numVertices);
|
||||
ID3D11Device *device;
|
||||
deviceContext->GetDevice(&device);
|
||||
if (instance->allocate(device)) return instance;
|
||||
delete instance;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CpuD3D11VertexBuffer::UpdateData(const float *src, int startVertex,
|
||||
int numVertices,
|
||||
void * /*deviceContext*/) {
|
||||
|
||||
memcpy(_cpuBuffer + startVertex * _numElements, src,
|
||||
_numElements * numVertices * sizeof(float));
|
||||
}
|
||||
|
||||
int
|
||||
CpuD3D11VertexBuffer::GetNumElements() const {
|
||||
|
||||
return _numElements;
|
||||
}
|
||||
|
||||
int
|
||||
CpuD3D11VertexBuffer::GetNumVertices() const {
|
||||
|
||||
return _numVertices;
|
||||
}
|
||||
|
||||
float*
|
||||
CpuD3D11VertexBuffer::BindCpuBuffer() {
|
||||
|
||||
return _cpuBuffer;
|
||||
}
|
||||
|
||||
ID3D11Buffer *
|
||||
CpuD3D11VertexBuffer::BindD3D11Buffer(ID3D11DeviceContext *deviceContext) {
|
||||
|
||||
assert(deviceContext);
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE resource;
|
||||
HRESULT hr = deviceContext->Map(_d3d11Buffer, 0,
|
||||
D3D11_MAP_WRITE_DISCARD, 0, &resource);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "Fail to map buffer\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int size = _numElements * _numVertices * sizeof(float);
|
||||
|
||||
memcpy(resource.pData, _cpuBuffer, size);
|
||||
|
||||
deviceContext->Unmap(_d3d11Buffer, 0);
|
||||
|
||||
return _d3d11Buffer;
|
||||
}
|
||||
|
||||
bool
|
||||
CpuD3D11VertexBuffer::allocate(ID3D11Device *device) {
|
||||
|
||||
_cpuBuffer = new float[_numElements * _numVertices];
|
||||
|
||||
// XXX: should move this constructor to factory for error handling
|
||||
D3D11_BUFFER_DESC hBufferDesc;
|
||||
hBufferDesc.ByteWidth = _numElements * _numVertices * sizeof(float);
|
||||
hBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
hBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_SHADER_RESOURCE;
|
||||
hBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
hBufferDesc.MiscFlags = 0;
|
||||
hBufferDesc.StructureByteStride = sizeof(float); // XXX ?
|
||||
|
||||
HRESULT hr;
|
||||
hr = device->CreateBuffer(&hBufferDesc, NULL, &_d3d11Buffer);
|
||||
if (FAILED(hr)) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR,
|
||||
"Fail in CreateBuffer\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
99
src/osd/opensubdiv/osd/cpuD3D11VertexBuffer.h
Normal file
99
src/osd/opensubdiv/osd/cpuD3D11VertexBuffer.h
Normal file
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_OSD_CPU_D3D11_VERTEX_BUFFER_H
|
||||
#define OPENSUBDIV3_OSD_CPU_D3D11_VERTEX_BUFFER_H
|
||||
|
||||
#include "../version.h"
|
||||
#include <cstddef>
|
||||
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11Device;
|
||||
struct ID3D11DeviceContext;
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
///
|
||||
/// \brief Concrete vertex buffer class for Cpu subdivision and DirectX drawing.
|
||||
///
|
||||
/// CpuD3D11VertexBuffer implements CpuVertexBufferInterface and
|
||||
/// D3D11VertexBufferInterface.
|
||||
///
|
||||
/// An instance of this buffer class can be passed to CpuEvaluator.
|
||||
///
|
||||
class CpuD3D11VertexBuffer {
|
||||
public:
|
||||
/// Creator. Returns NULL if error.
|
||||
static CpuD3D11VertexBuffer * Create(int numElements, int numVertices,
|
||||
ID3D11DeviceContext *deviceContext);
|
||||
|
||||
/// Destructor.
|
||||
virtual ~CpuD3D11VertexBuffer();
|
||||
|
||||
/// This method is meant to be used in client code in order to provide coarse
|
||||
/// vertices data to Osd.
|
||||
void UpdateData(const float *src, int startVertex, int numVertices,
|
||||
void *deviceContext = NULL);
|
||||
|
||||
/// Returns how many elements defined in this vertex buffer.
|
||||
int GetNumElements() const;
|
||||
|
||||
/// Returns how many vertices allocated in this vertex buffer.
|
||||
int GetNumVertices() const;
|
||||
|
||||
/// Returns the address of CPU buffer.
|
||||
float * BindCpuBuffer();
|
||||
|
||||
/// Returns the D3D11 buffer object.
|
||||
ID3D11Buffer *BindD3D11Buffer(ID3D11DeviceContext *deviceContext);
|
||||
|
||||
/// Returns the D3D11 buffer object (for Osd::Mesh interface)
|
||||
ID3D11Buffer *BindVBO(ID3D11DeviceContext *deviceContext) {
|
||||
return BindD3D11Buffer(deviceContext);
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Constructor.
|
||||
CpuD3D11VertexBuffer(int numElements, int numVertices);
|
||||
|
||||
bool allocate(ID3D11Device *device);
|
||||
|
||||
private:
|
||||
int _numElements;
|
||||
int _numVertices;
|
||||
ID3D11Buffer *_d3d11Buffer;
|
||||
float *_cpuBuffer;
|
||||
};
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_OSD_CPU_D3D11_VERTEX_BUFFER_H
|
||||
389
src/osd/opensubdiv/osd/cpuEvaluator.cpp
Normal file
389
src/osd/opensubdiv/osd/cpuEvaluator.cpp
Normal file
@@ -0,0 +1,389 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../osd/cpuEvaluator.h"
|
||||
#include "../osd/cpuKernel.h"
|
||||
#include "../osd/patchBasisCommonTypes.h"
|
||||
#include "../osd/patchBasisCommon.h"
|
||||
#include "../osd/patchBasisCommonEval.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CpuEvaluator::EvalStencils(const float *src, BufferDescriptor const &srcDesc,
|
||||
float *dst, BufferDescriptor const &dstDesc,
|
||||
const int * sizes,
|
||||
const int * offsets,
|
||||
const int * indices,
|
||||
const float * weights,
|
||||
int start, int end) {
|
||||
|
||||
if (end <= start) return true;
|
||||
if (srcDesc.length != dstDesc.length) return false;
|
||||
|
||||
// XXX: we can probably expand cpuKernel.cpp to here.
|
||||
CpuEvalStencils(src, srcDesc, dst, dstDesc,
|
||||
sizes, offsets, indices, weights, start, end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CpuEvaluator::EvalStencils(const float *src, BufferDescriptor const &srcDesc,
|
||||
float *dst, BufferDescriptor const &dstDesc,
|
||||
float *du, BufferDescriptor const &duDesc,
|
||||
float *dv, BufferDescriptor const &dvDesc,
|
||||
const int * sizes,
|
||||
const int * offsets,
|
||||
const int * indices,
|
||||
const float * weights,
|
||||
const float * duWeights,
|
||||
const float * dvWeights,
|
||||
int start, int end) {
|
||||
if (end <= start) return true;
|
||||
if (srcDesc.length != dstDesc.length) return false;
|
||||
if (srcDesc.length != duDesc.length) return false;
|
||||
if (srcDesc.length != dvDesc.length) return false;
|
||||
|
||||
CpuEvalStencils(src, srcDesc,
|
||||
dst, dstDesc,
|
||||
du, duDesc,
|
||||
dv, dvDesc,
|
||||
sizes, offsets, indices,
|
||||
weights, duWeights, dvWeights,
|
||||
start, end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CpuEvaluator::EvalStencils(const float *src, BufferDescriptor const &srcDesc,
|
||||
float *dst, BufferDescriptor const &dstDesc,
|
||||
float *du, BufferDescriptor const &duDesc,
|
||||
float *dv, BufferDescriptor const &dvDesc,
|
||||
float *duu, BufferDescriptor const &duuDesc,
|
||||
float *duv, BufferDescriptor const &duvDesc,
|
||||
float *dvv, BufferDescriptor const &dvvDesc,
|
||||
const int * sizes,
|
||||
const int * offsets,
|
||||
const int * indices,
|
||||
const float * weights,
|
||||
const float * duWeights,
|
||||
const float * dvWeights,
|
||||
const float * duuWeights,
|
||||
const float * duvWeights,
|
||||
const float * dvvWeights,
|
||||
int start, int end) {
|
||||
if (end <= start) return true;
|
||||
if (srcDesc.length != dstDesc.length) return false;
|
||||
if (srcDesc.length != duDesc.length) return false;
|
||||
if (srcDesc.length != dvDesc.length) return false;
|
||||
if (srcDesc.length != duuDesc.length) return false;
|
||||
if (srcDesc.length != duvDesc.length) return false;
|
||||
if (srcDesc.length != dvvDesc.length) return false;
|
||||
|
||||
CpuEvalStencils(src, srcDesc,
|
||||
dst, dstDesc,
|
||||
du, duDesc,
|
||||
dv, dvDesc,
|
||||
duu, duuDesc,
|
||||
duv, duvDesc,
|
||||
dvv, dvvDesc,
|
||||
sizes, offsets, indices,
|
||||
weights, duWeights, dvWeights,
|
||||
duuWeights, duvWeights, dvvWeights,
|
||||
start, end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct BufferAdapter {
|
||||
BufferAdapter(T *p, int length, int stride) :
|
||||
_p(p), _length(length), _stride(stride) { }
|
||||
void Clear() {
|
||||
for (int i = 0; i < _length; ++i) _p[i] = 0;
|
||||
}
|
||||
void AddWithWeight(T const *src, float w) {
|
||||
if (_p) {
|
||||
for (int i = 0; i < _length; ++i) {
|
||||
_p[i] += src[i] * w;
|
||||
}
|
||||
}
|
||||
}
|
||||
const T *operator[] (int index) const {
|
||||
return _p + _stride * index;
|
||||
}
|
||||
BufferAdapter<T> & operator ++() {
|
||||
if (_p) {
|
||||
_p += _stride;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
T *_p;
|
||||
int _length;
|
||||
int _stride;
|
||||
};
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CpuEvaluator::EvalPatches(const float *src, BufferDescriptor const &srcDesc,
|
||||
float *dst, BufferDescriptor const &dstDesc,
|
||||
int numPatchCoords,
|
||||
const PatchCoord *patchCoords,
|
||||
const PatchArray *patchArrays,
|
||||
const int *patchIndexBuffer,
|
||||
const PatchParam *patchParamBuffer) {
|
||||
if (src) {
|
||||
src += srcDesc.offset;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (dst) {
|
||||
dst += dstDesc.offset;
|
||||
if (srcDesc.length != dstDesc.length) return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
BufferAdapter<const float> srcT(src, srcDesc.length, srcDesc.stride);
|
||||
BufferAdapter<float> dstT(dst, dstDesc.length, dstDesc.stride);
|
||||
|
||||
float wP[20];
|
||||
|
||||
for (int i = 0; i < numPatchCoords; ++i) {
|
||||
PatchCoord const &coord = patchCoords[i];
|
||||
PatchArray const &array = patchArrays[coord.handle.arrayIndex];
|
||||
|
||||
Osd::PatchParam const & paramStruct =
|
||||
patchParamBuffer[coord.handle.patchIndex];
|
||||
OsdPatchParam param = OsdPatchParamInit(
|
||||
paramStruct.field0, paramStruct.field1, paramStruct.sharpness);
|
||||
|
||||
int patchType = OsdPatchParamIsRegular(param)
|
||||
? array.GetPatchTypeRegular()
|
||||
: array.GetPatchTypeIrregular();
|
||||
|
||||
int nPoints = OsdEvaluatePatchBasis(patchType, param,
|
||||
coord.s, coord.t, wP, 0, 0, 0, 0, 0);
|
||||
|
||||
int indexBase = array.GetIndexBase() + array.GetStride() *
|
||||
(coord.handle.patchIndex - array.GetPrimitiveIdBase());
|
||||
|
||||
const int *cvs = &patchIndexBuffer[indexBase];
|
||||
|
||||
dstT.Clear();
|
||||
for (int j = 0; j < nPoints; ++j) {
|
||||
dstT.AddWithWeight(srcT[cvs[j]], wP[j]);
|
||||
}
|
||||
++dstT;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CpuEvaluator::EvalPatches(const float *src, BufferDescriptor const &srcDesc,
|
||||
float *dst, BufferDescriptor const &dstDesc,
|
||||
float *du, BufferDescriptor const &duDesc,
|
||||
float *dv, BufferDescriptor const &dvDesc,
|
||||
int numPatchCoords,
|
||||
const PatchCoord *patchCoords,
|
||||
const PatchArray *patchArrays,
|
||||
const int *patchIndexBuffer,
|
||||
const PatchParam *patchParamBuffer) {
|
||||
if (src) {
|
||||
src += srcDesc.offset;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (dst) {
|
||||
if (srcDesc.length != dstDesc.length) return false;
|
||||
dst += dstDesc.offset;
|
||||
}
|
||||
if (du) {
|
||||
du += duDesc.offset;
|
||||
if (srcDesc.length != duDesc.length) return false;
|
||||
}
|
||||
if (dv) {
|
||||
dv += dvDesc.offset;
|
||||
if (srcDesc.length != dvDesc.length) return false;
|
||||
}
|
||||
|
||||
BufferAdapter<const float> srcT(src, srcDesc.length, srcDesc.stride);
|
||||
BufferAdapter<float> dstT(dst, dstDesc.length, dstDesc.stride);
|
||||
BufferAdapter<float> duT(du, duDesc.length, duDesc.stride);
|
||||
BufferAdapter<float> dvT(dv, dvDesc.length, dvDesc.stride);
|
||||
|
||||
float wP[20], wDs[20], wDt[20];
|
||||
|
||||
for (int i = 0; i < numPatchCoords; ++i) {
|
||||
PatchCoord const &coord = patchCoords[i];
|
||||
PatchArray const &array = patchArrays[coord.handle.arrayIndex];
|
||||
|
||||
Osd::PatchParam const & paramStruct =
|
||||
patchParamBuffer[coord.handle.patchIndex];
|
||||
OsdPatchParam param = OsdPatchParamInit(
|
||||
paramStruct.field0, paramStruct.field1, paramStruct.sharpness);
|
||||
|
||||
int patchType = OsdPatchParamIsRegular(param)
|
||||
? array.GetPatchTypeRegular()
|
||||
: array.GetPatchTypeIrregular();
|
||||
|
||||
int nPoints = OsdEvaluatePatchBasis(patchType, param,
|
||||
coord.s, coord.t, wP, wDs, wDt, 0, 0, 0);
|
||||
|
||||
int indexBase = array.GetIndexBase() + array.GetStride() *
|
||||
(coord.handle.patchIndex - array.GetPrimitiveIdBase());
|
||||
|
||||
const int *cvs = &patchIndexBuffer[indexBase];
|
||||
|
||||
dstT.Clear();
|
||||
duT.Clear();
|
||||
dvT.Clear();
|
||||
for (int j = 0; j < nPoints; ++j) {
|
||||
dstT.AddWithWeight(srcT[cvs[j]], wP[j]);
|
||||
duT.AddWithWeight (srcT[cvs[j]], wDs[j]);
|
||||
dvT.AddWithWeight (srcT[cvs[j]], wDt[j]);
|
||||
}
|
||||
++dstT;
|
||||
++duT;
|
||||
++dvT;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CpuEvaluator::EvalPatches(const float *src, BufferDescriptor const &srcDesc,
|
||||
float *dst, BufferDescriptor const &dstDesc,
|
||||
float *du, BufferDescriptor const &duDesc,
|
||||
float *dv, BufferDescriptor const &dvDesc,
|
||||
float *duu, BufferDescriptor const &duuDesc,
|
||||
float *duv, BufferDescriptor const &duvDesc,
|
||||
float *dvv, BufferDescriptor const &dvvDesc,
|
||||
int numPatchCoords,
|
||||
const PatchCoord *patchCoords,
|
||||
const PatchArray *patchArrays,
|
||||
const int *patchIndexBuffer,
|
||||
const PatchParam *patchParamBuffer) {
|
||||
if (src) {
|
||||
src += srcDesc.offset;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (dst) {
|
||||
if (srcDesc.length != dstDesc.length) return false;
|
||||
dst += dstDesc.offset;
|
||||
}
|
||||
if (du) {
|
||||
du += duDesc.offset;
|
||||
if (srcDesc.length != duDesc.length) return false;
|
||||
}
|
||||
if (dv) {
|
||||
dv += dvDesc.offset;
|
||||
if (srcDesc.length != dvDesc.length) return false;
|
||||
}
|
||||
if (duu) {
|
||||
duu += duuDesc.offset;
|
||||
if (srcDesc.length != duuDesc.length) return false;
|
||||
}
|
||||
if (duv) {
|
||||
duv += duvDesc.offset;
|
||||
if (srcDesc.length != duvDesc.length) return false;
|
||||
}
|
||||
if (dvv) {
|
||||
dvv += dvvDesc.offset;
|
||||
if (srcDesc.length != dvvDesc.length) return false;
|
||||
}
|
||||
|
||||
BufferAdapter<const float> srcT(src, srcDesc.length, srcDesc.stride);
|
||||
BufferAdapter<float> dstT(dst, dstDesc.length, dstDesc.stride);
|
||||
BufferAdapter<float> duT(du, duDesc.length, duDesc.stride);
|
||||
BufferAdapter<float> dvT(dv, dvDesc.length, dvDesc.stride);
|
||||
BufferAdapter<float> duuT(duu, duuDesc.length, duuDesc.stride);
|
||||
BufferAdapter<float> duvT(duv, duvDesc.length, duvDesc.stride);
|
||||
BufferAdapter<float> dvvT(dvv, dvvDesc.length, dvvDesc.stride);
|
||||
|
||||
float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
|
||||
|
||||
for (int i = 0; i < numPatchCoords; ++i) {
|
||||
PatchCoord const &coord = patchCoords[i];
|
||||
PatchArray const &array = patchArrays[coord.handle.arrayIndex];
|
||||
|
||||
Osd::PatchParam const & paramStruct =
|
||||
patchParamBuffer[coord.handle.patchIndex];
|
||||
OsdPatchParam param = OsdPatchParamInit(
|
||||
paramStruct.field0, paramStruct.field1, paramStruct.sharpness);
|
||||
|
||||
int patchType = OsdPatchParamIsRegular(param)
|
||||
? array.GetPatchTypeRegular()
|
||||
: array.GetPatchTypeIrregular();
|
||||
|
||||
int nPoints = OsdEvaluatePatchBasis(patchType, param,
|
||||
coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
|
||||
|
||||
int indexBase = array.GetIndexBase() + array.GetStride() *
|
||||
(coord.handle.patchIndex - array.GetPrimitiveIdBase());
|
||||
|
||||
const int *cvs = &patchIndexBuffer[indexBase];
|
||||
|
||||
dstT.Clear();
|
||||
duT.Clear();
|
||||
dvT.Clear();
|
||||
duuT.Clear();
|
||||
duvT.Clear();
|
||||
dvvT.Clear();
|
||||
for (int j = 0; j < nPoints; ++j) {
|
||||
dstT.AddWithWeight(srcT[cvs[j]], wP[j]);
|
||||
duT.AddWithWeight (srcT[cvs[j]], wDu[j]);
|
||||
dvT.AddWithWeight (srcT[cvs[j]], wDv[j]);
|
||||
duuT.AddWithWeight (srcT[cvs[j]], wDuu[j]);
|
||||
duvT.AddWithWeight (srcT[cvs[j]], wDuv[j]);
|
||||
dvvT.AddWithWeight (srcT[cvs[j]], wDvv[j]);
|
||||
}
|
||||
++dstT;
|
||||
++duT;
|
||||
++dvT;
|
||||
++duuT;
|
||||
++duvT;
|
||||
++dvvT;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
1241
src/osd/opensubdiv/osd/cpuEvaluator.h
Normal file
1241
src/osd/opensubdiv/osd/cpuEvaluator.h
Normal file
File diff suppressed because it is too large
Load Diff
123
src/osd/opensubdiv/osd/cpuGLVertexBuffer.cpp
Normal file
123
src/osd/opensubdiv/osd/cpuGLVertexBuffer.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "glLoader.h"
|
||||
|
||||
#include "../osd/cpuGLVertexBuffer.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
CpuGLVertexBuffer::CpuGLVertexBuffer(int numElements, int numVertices)
|
||||
: _numElements(numElements), _numVertices(numVertices),
|
||||
_vbo(0), _cpuBuffer(0), _dataDirty(true) {
|
||||
|
||||
// Initialize internal OpenGL loader library if necessary
|
||||
OpenSubdiv::internal::GLLoader::libraryInitializeGL();
|
||||
}
|
||||
|
||||
CpuGLVertexBuffer::~CpuGLVertexBuffer() {
|
||||
|
||||
delete[] _cpuBuffer;
|
||||
|
||||
if (_vbo) {
|
||||
glDeleteBuffers(1, &_vbo);
|
||||
}
|
||||
}
|
||||
|
||||
CpuGLVertexBuffer *
|
||||
CpuGLVertexBuffer::Create(int numElements, int numVertices, void *) {
|
||||
CpuGLVertexBuffer *instance =
|
||||
new CpuGLVertexBuffer(numElements, numVertices);
|
||||
if (instance->allocate()) return instance;
|
||||
delete instance;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CpuGLVertexBuffer::UpdateData(const float *src,
|
||||
int startVertex, int numVertices,
|
||||
void * /*deviceContext*/) {
|
||||
|
||||
memcpy(_cpuBuffer + startVertex * GetNumElements(), src,
|
||||
GetNumElements() * numVertices * sizeof(float));
|
||||
_dataDirty = true;
|
||||
}
|
||||
|
||||
int
|
||||
CpuGLVertexBuffer::GetNumElements() const {
|
||||
|
||||
return _numElements;
|
||||
}
|
||||
|
||||
int
|
||||
CpuGLVertexBuffer::GetNumVertices() const {
|
||||
|
||||
return _numVertices;
|
||||
}
|
||||
|
||||
float*
|
||||
CpuGLVertexBuffer::BindCpuBuffer() {
|
||||
|
||||
_dataDirty = true; // caller might modify data
|
||||
return _cpuBuffer;
|
||||
}
|
||||
|
||||
GLuint
|
||||
CpuGLVertexBuffer::BindVBO(void * /*deviceContext*/) {
|
||||
|
||||
if (! _dataDirty)
|
||||
return _vbo;
|
||||
|
||||
int size = GetNumElements() * GetNumVertices() * sizeof(float);
|
||||
|
||||
if (! _vbo) {
|
||||
glGenBuffers(1, &_vbo);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, size, _cpuBuffer, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
_dataDirty = false;
|
||||
return _vbo;
|
||||
}
|
||||
|
||||
bool
|
||||
CpuGLVertexBuffer::allocate() {
|
||||
|
||||
_cpuBuffer = new float[GetNumElements() * GetNumVertices()];
|
||||
_dataDirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
97
src/osd/opensubdiv/osd/cpuGLVertexBuffer.h
Normal file
97
src/osd/opensubdiv/osd/cpuGLVertexBuffer.h
Normal file
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_OSD_CPU_GL_VERTEX_BUFFER_H
|
||||
#define OPENSUBDIV3_OSD_CPU_GL_VERTEX_BUFFER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include "../osd/opengl.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
///
|
||||
/// \brief Concrete vertex buffer class for cpu subdivision and OpenGL drawing.
|
||||
///
|
||||
/// CpuGLVertexBuffer implements CpuVertexBufferInterface and
|
||||
/// GLVertexBufferInterface.
|
||||
///
|
||||
/// The buffer interop between Cpu and GL is handled automatically when a
|
||||
/// client calls BindCpuBuffer and BindVBO methods.
|
||||
///
|
||||
class CpuGLVertexBuffer {
|
||||
public:
|
||||
/// Creator. Returns NULL if error.
|
||||
static CpuGLVertexBuffer * Create(int numElements, int numVertices,
|
||||
void *deviceContext = NULL);
|
||||
|
||||
/// Destructor.
|
||||
~CpuGLVertexBuffer();
|
||||
|
||||
/// This method is meant to be used in client code in order to provide
|
||||
/// coarse vertices data to Osd.
|
||||
void UpdateData(const float *src, int startVertex, int numVertices,
|
||||
void *deviceContext = NULL);
|
||||
|
||||
/// Returns how many elements defined in this vertex buffer.
|
||||
int GetNumElements() const;
|
||||
|
||||
/// Returns how many vertices allocated in this vertex buffer.
|
||||
int GetNumVertices() const;
|
||||
|
||||
/// Returns cpu memory. GL buffer will be mapped to cpu address
|
||||
/// if necessary.
|
||||
float * BindCpuBuffer();
|
||||
|
||||
/// Returns the name of GL buffer object. If the buffer is mapped
|
||||
/// to cpu address, it will be unmapped back to GL.
|
||||
GLuint BindVBO(void *deviceContext = NULL);
|
||||
|
||||
protected:
|
||||
/// Constructor.
|
||||
CpuGLVertexBuffer(int numElements, int numVertices);
|
||||
|
||||
/// Allocates VBO for this buffer. Returns true if success.
|
||||
bool allocate();
|
||||
|
||||
private:
|
||||
int _numElements;
|
||||
int _numVertices;
|
||||
GLuint _vbo;
|
||||
float *_cpuBuffer;
|
||||
bool _dataDirty;
|
||||
};
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_OSD_CPU_GL_VERTEX_BUFFER_H
|
||||
245
src/osd/opensubdiv/osd/cpuKernel.cpp
Normal file
245
src/osd/opensubdiv/osd/cpuKernel.cpp
Normal file
@@ -0,0 +1,245 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../osd/cpuKernel.h"
|
||||
#include "../osd/bufferDescriptor.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
template <class T> T *
|
||||
elementAtIndex(T * src, int index, BufferDescriptor const &desc) {
|
||||
|
||||
return src + index * desc.stride;
|
||||
}
|
||||
|
||||
static inline void
|
||||
clear(float *dst, BufferDescriptor const &desc) {
|
||||
|
||||
assert(dst);
|
||||
memset(dst, 0, desc.length*sizeof(float));
|
||||
}
|
||||
|
||||
static inline void
|
||||
addWithWeight(float *dst, const float *src, int srcIndex, float weight,
|
||||
BufferDescriptor const &desc) {
|
||||
|
||||
assert(src && dst);
|
||||
src = elementAtIndex(src, srcIndex, desc);
|
||||
for (int k = 0; k < desc.length; ++k) {
|
||||
dst[k] += src[k] * weight;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
copy(float *dst, int dstIndex, const float *src, BufferDescriptor const &desc) {
|
||||
|
||||
assert(src && dst);
|
||||
|
||||
dst = elementAtIndex(dst, dstIndex, desc);
|
||||
memcpy(dst, src, desc.length*sizeof(float));
|
||||
}
|
||||
|
||||
void
|
||||
CpuEvalStencils(float const * src, BufferDescriptor const &srcDesc,
|
||||
float * dst, BufferDescriptor const &dstDesc,
|
||||
int const * sizes,
|
||||
int const * offsets,
|
||||
int const * indices,
|
||||
float const * weights,
|
||||
int start, int end) {
|
||||
|
||||
assert(start>=0 && start<end);
|
||||
|
||||
if (start>0) {
|
||||
sizes += start;
|
||||
indices += offsets[start];
|
||||
weights += offsets[start];
|
||||
}
|
||||
|
||||
src += srcDesc.offset;
|
||||
dst += dstDesc.offset;
|
||||
|
||||
if (srcDesc.length == 4 && dstDesc.length == 4 &&
|
||||
srcDesc.stride == 4 && dstDesc.stride == 4) {
|
||||
|
||||
// SIMD fast path for aligned primvar data (4 floats)
|
||||
ComputeStencilKernel<4>(src, dst,
|
||||
sizes, indices, weights, start, end);
|
||||
|
||||
} else if (srcDesc.length == 8 && dstDesc.length == 8 &&
|
||||
srcDesc.stride == 8 && dstDesc.stride == 8) {
|
||||
|
||||
// SIMD fast path for aligned primvar data (8 floats)
|
||||
ComputeStencilKernel<8>(src, dst,
|
||||
sizes, indices, weights, start, end);
|
||||
} else {
|
||||
|
||||
// Slow path for non-aligned data
|
||||
|
||||
float * result = (float*)alloca(srcDesc.length * sizeof(float));
|
||||
|
||||
int nstencils = end-start;
|
||||
for (int i=0; i<nstencils; ++i, ++sizes) {
|
||||
|
||||
clear(result, srcDesc);
|
||||
|
||||
for (int j=0; j<*sizes; ++j) {
|
||||
addWithWeight(result, src, *indices++, *weights++, srcDesc);
|
||||
}
|
||||
|
||||
copy(dst, i, result, dstDesc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CpuEvalStencils(float const * src, BufferDescriptor const &srcDesc,
|
||||
float * dst, BufferDescriptor const &dstDesc,
|
||||
float * dstDu, BufferDescriptor const &dstDuDesc,
|
||||
float * dstDv, BufferDescriptor const &dstDvDesc,
|
||||
int const * sizes,
|
||||
int const * offsets,
|
||||
int const * indices,
|
||||
float const * weights,
|
||||
float const * duWeights,
|
||||
float const * dvWeights,
|
||||
int start, int end) {
|
||||
if (start > 0) {
|
||||
sizes += start;
|
||||
indices += offsets[start];
|
||||
weights += offsets[start];
|
||||
duWeights += offsets[start];
|
||||
dvWeights += offsets[start];
|
||||
}
|
||||
|
||||
src += srcDesc.offset;
|
||||
dst += dstDesc.offset;
|
||||
dstDu += dstDuDesc.offset;
|
||||
dstDv += dstDvDesc.offset;
|
||||
|
||||
int nOutLength = dstDesc.length + dstDuDesc.length + dstDvDesc.length;
|
||||
float * result = (float*)alloca(nOutLength * sizeof(float));
|
||||
float * resultDu = result + dstDesc.length;
|
||||
float * resultDv = resultDu + dstDuDesc.length;
|
||||
|
||||
int nStencils = end - start;
|
||||
for (int i = 0; i < nStencils; ++i, ++sizes) {
|
||||
|
||||
// clear
|
||||
memset(result, 0, nOutLength * sizeof(float));
|
||||
|
||||
for (int j=0; j<*sizes; ++j) {
|
||||
addWithWeight(result, src, *indices, *weights++, srcDesc);
|
||||
addWithWeight(resultDu, src, *indices, *duWeights++, srcDesc);
|
||||
addWithWeight(resultDv, src, *indices, *dvWeights++, srcDesc);
|
||||
++indices;
|
||||
}
|
||||
copy(dst, i, result, dstDesc);
|
||||
copy(dstDu, i, resultDu, dstDuDesc);
|
||||
copy(dstDv, i, resultDv, dstDvDesc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CpuEvalStencils(float const * src, BufferDescriptor const &srcDesc,
|
||||
float * dst, BufferDescriptor const &dstDesc,
|
||||
float * dstDu, BufferDescriptor const &dstDuDesc,
|
||||
float * dstDv, BufferDescriptor const &dstDvDesc,
|
||||
float * dstDuu, BufferDescriptor const &dstDuuDesc,
|
||||
float * dstDuv, BufferDescriptor const &dstDuvDesc,
|
||||
float * dstDvv, BufferDescriptor const &dstDvvDesc,
|
||||
int const * sizes,
|
||||
int const * offsets,
|
||||
int const * indices,
|
||||
float const * weights,
|
||||
float const * duWeights,
|
||||
float const * dvWeights,
|
||||
float const * duuWeights,
|
||||
float const * duvWeights,
|
||||
float const * dvvWeights,
|
||||
int start, int end) {
|
||||
if (start > 0) {
|
||||
sizes += start;
|
||||
indices += offsets[start];
|
||||
weights += offsets[start];
|
||||
duWeights += offsets[start];
|
||||
dvWeights += offsets[start];
|
||||
duuWeights += offsets[start];
|
||||
duvWeights += offsets[start];
|
||||
dvvWeights += offsets[start];
|
||||
}
|
||||
|
||||
src += srcDesc.offset;
|
||||
dst += dstDesc.offset;
|
||||
dstDu += dstDuDesc.offset;
|
||||
dstDv += dstDvDesc.offset;
|
||||
dstDuu += dstDuuDesc.offset;
|
||||
dstDuv += dstDuvDesc.offset;
|
||||
dstDvv += dstDvvDesc.offset;
|
||||
|
||||
int nOutLength = dstDesc.length + dstDuDesc.length + dstDvDesc.length
|
||||
+ dstDuuDesc.length + dstDuvDesc.length + dstDvvDesc.length;
|
||||
float * result = (float*)alloca(nOutLength * sizeof(float));
|
||||
float * resultDu = result + dstDesc.length;
|
||||
float * resultDv = resultDu + dstDuDesc.length;
|
||||
float * resultDuu = resultDv + dstDvDesc.length;
|
||||
float * resultDuv = resultDuu + dstDuuDesc.length;
|
||||
float * resultDvv = resultDuv + dstDuvDesc.length;
|
||||
|
||||
int nStencils = end - start;
|
||||
for (int i = 0; i < nStencils; ++i, ++sizes) {
|
||||
|
||||
// clear
|
||||
memset(result, 0, nOutLength * sizeof(float));
|
||||
|
||||
for (int j=0; j<*sizes; ++j) {
|
||||
addWithWeight(result, src, *indices, *weights++, srcDesc);
|
||||
addWithWeight(resultDu, src, *indices, *duWeights++, srcDesc);
|
||||
addWithWeight(resultDv, src, *indices, *dvWeights++, srcDesc);
|
||||
addWithWeight(resultDuu, src, *indices, *duuWeights++, srcDesc);
|
||||
addWithWeight(resultDuv, src, *indices, *duvWeights++, srcDesc);
|
||||
addWithWeight(resultDvv, src, *indices, *dvvWeights++, srcDesc);
|
||||
++indices;
|
||||
}
|
||||
copy(dst, i, result, dstDesc);
|
||||
copy(dstDu, i, resultDu, dstDuDesc);
|
||||
copy(dstDv, i, resultDv, dstDvDesc);
|
||||
copy(dstDuu, i, resultDuu, dstDuuDesc);
|
||||
copy(dstDuv, i, resultDuv, dstDuvDesc);
|
||||
copy(dstDvv, i, resultDvv, dstDvvDesc);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
150
src/osd/opensubdiv/osd/cpuKernel.h
Normal file
150
src/osd/opensubdiv/osd/cpuKernel.h
Normal file
@@ -0,0 +1,150 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_OSD_CPU_KERNEL_H
|
||||
#define OPENSUBDIV3_OSD_CPU_KERNEL_H
|
||||
|
||||
#include "../version.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
struct BufferDescriptor;
|
||||
|
||||
void
|
||||
CpuEvalStencils(float const * src, BufferDescriptor const &srcDesc,
|
||||
float * dst, BufferDescriptor const &dstDesc,
|
||||
int const * sizes,
|
||||
int const * offsets,
|
||||
int const * indices,
|
||||
float const * weights,
|
||||
int start, int end);
|
||||
|
||||
void
|
||||
CpuEvalStencils(float const * src, BufferDescriptor const &srcDesc,
|
||||
float * dst, BufferDescriptor const &dstDesc,
|
||||
float * dstDu, BufferDescriptor const &dstDuDesc,
|
||||
float * dstDv, BufferDescriptor const &dstDvDesc,
|
||||
int const * sizes,
|
||||
int const * offsets,
|
||||
int const * indices,
|
||||
float const * weights,
|
||||
float const * duWeights,
|
||||
float const * dvWeights,
|
||||
int start, int end);
|
||||
|
||||
void
|
||||
CpuEvalStencils(float const * src, BufferDescriptor const &srcDesc,
|
||||
float * dst, BufferDescriptor const &dstDesc,
|
||||
float * dstDu, BufferDescriptor const &dstDuDesc,
|
||||
float * dstDv, BufferDescriptor const &dstDvDesc,
|
||||
float * dstDuu, BufferDescriptor const &dstDuuDesc,
|
||||
float * dstDuv, BufferDescriptor const &dstDuvDesc,
|
||||
float * dstDvv, BufferDescriptor const &dstDvvDesc,
|
||||
int const * sizes,
|
||||
int const * offsets,
|
||||
int const * indices,
|
||||
float const * weights,
|
||||
float const * duWeights,
|
||||
float const * dvWeights,
|
||||
float const * duuWeights,
|
||||
float const * duvWeights,
|
||||
float const * dvvWeights,
|
||||
int start, int end);
|
||||
|
||||
//
|
||||
// SIMD ICC optimization of the stencil kernel
|
||||
//
|
||||
|
||||
#if defined ( __INTEL_COMPILER ) || defined ( __ICC )
|
||||
#define __ALIGN_DATA __declspec(align(32))
|
||||
#else
|
||||
#define __ALIGN_DATA
|
||||
#endif
|
||||
|
||||
// Note : this function is re-used in the TBB Compute kernel
|
||||
template <int numElems> void
|
||||
ComputeStencilKernel(float const * vertexSrc,
|
||||
float * vertexDst,
|
||||
int const * sizes,
|
||||
int const * indices,
|
||||
float const * weights,
|
||||
int start,
|
||||
int end) {
|
||||
|
||||
__ALIGN_DATA float result[numElems],
|
||||
result1[numElems];
|
||||
|
||||
float const * src;
|
||||
float * dst, weight;
|
||||
|
||||
for (int i=start; i<end; ++i) {
|
||||
|
||||
// Clear
|
||||
#if defined ( __INTEL_COMPILER ) || defined ( __ICC )
|
||||
#pragma simd
|
||||
#pragma vector aligned
|
||||
#endif
|
||||
for (int k = 0; k<numElems; ++k)
|
||||
result[k] = 0.0f;
|
||||
|
||||
for (int j=0; j<sizes[i]; ++j, ++indices, ++weights) {
|
||||
|
||||
src = vertexSrc + (*indices)*numElems;
|
||||
weight = *weights;
|
||||
|
||||
// AddWithWeight
|
||||
#if defined ( __INTEL_COMPILER ) || defined ( __ICC )
|
||||
#pragma simd
|
||||
#pragma vector aligned
|
||||
#endif
|
||||
for (int k=0; k<numElems; ++k) {
|
||||
result[k] += src[k] * weight;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined ( __INTEL_COMPILER ) || defined ( __ICC )
|
||||
#pragma simd
|
||||
#pragma vector aligned
|
||||
#endif
|
||||
for (int k=0; k<numElems; ++k) {
|
||||
result1[k] = result[k];
|
||||
}
|
||||
|
||||
dst = vertexDst + i*numElems;
|
||||
memcpy(dst, result1, numElems*sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_OSD_CPU_KERNEL_H
|
||||
164
src/osd/opensubdiv/osd/cpuPatchTable.cpp
Normal file
164
src/osd/opensubdiv/osd/cpuPatchTable.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../osd/cpuPatchTable.h"
|
||||
#include "../far/patchDescriptor.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
CpuPatchTable::CpuPatchTable(const Far::PatchTable *farPatchTable) {
|
||||
int nPatchArrays = farPatchTable->GetNumPatchArrays();
|
||||
|
||||
// count
|
||||
int numPatches = 0;
|
||||
int numIndices = 0;
|
||||
for (int j = 0; j < nPatchArrays; ++j) {
|
||||
int nPatch = farPatchTable->GetNumPatches(j);
|
||||
int nCV = farPatchTable->GetPatchArrayDescriptor(j).GetNumControlVertices();
|
||||
numPatches += nPatch;
|
||||
numIndices += nPatch * nCV;
|
||||
}
|
||||
_patchArrays.reserve(nPatchArrays);
|
||||
_indexBuffer.reserve(numIndices);
|
||||
|
||||
_varyingPatchArrays.reserve(nPatchArrays);
|
||||
_varyingIndexBuffer.reserve(
|
||||
numPatches*farPatchTable->GetVaryingPatchDescriptor().GetNumControlVertices());
|
||||
|
||||
_fvarPatchArrays.resize(farPatchTable->GetNumFVarChannels());
|
||||
_fvarIndexBuffers.resize(farPatchTable->GetNumFVarChannels());
|
||||
_fvarParamBuffers.resize(farPatchTable->GetNumFVarChannels());
|
||||
for (int fvc=0; fvc<farPatchTable->GetNumFVarChannels(); ++fvc) {
|
||||
_fvarPatchArrays[fvc].reserve(nPatchArrays);
|
||||
_fvarIndexBuffers[fvc].reserve(
|
||||
numPatches * farPatchTable->GetFVarValueStride(fvc));
|
||||
_fvarParamBuffers[fvc].reserve(numPatches);
|
||||
}
|
||||
_patchParamBuffer.reserve(numPatches);
|
||||
|
||||
// for each patchArray
|
||||
for (int j = 0; j < nPatchArrays; ++j) {
|
||||
int numPatchesThisArray = farPatchTable->GetNumPatches(j);
|
||||
|
||||
// create vertex array and append indices to buffer:
|
||||
PatchArray patchArray(
|
||||
farPatchTable->GetPatchArrayDescriptor(j),
|
||||
numPatchesThisArray,
|
||||
(int)_indexBuffer.size(), (int)_patchParamBuffer.size());
|
||||
_patchArrays.push_back(patchArray);
|
||||
|
||||
Far::ConstIndexArray indices = farPatchTable->GetPatchArrayVertices(j);
|
||||
_indexBuffer.insert(_indexBuffer.end(), indices.begin(), indices.end());
|
||||
|
||||
// create varying array and append indices to buffer:
|
||||
PatchArray varyingPatchArray(
|
||||
farPatchTable->GetVaryingPatchDescriptor(),
|
||||
numPatchesThisArray,
|
||||
(int)_varyingIndexBuffer.size(), (int)_patchParamBuffer.size());
|
||||
_varyingPatchArrays.push_back(varyingPatchArray);
|
||||
|
||||
Far::ConstIndexArray
|
||||
varyingIndices = farPatchTable->GetPatchArrayVaryingVertices(j);
|
||||
_varyingIndexBuffer.insert(_varyingIndexBuffer.end(),
|
||||
varyingIndices.begin(), varyingIndices.end());
|
||||
|
||||
// create face-varying arrays for each channel:
|
||||
for (int fvc=0; fvc<farPatchTable->GetNumFVarChannels(); ++fvc) {
|
||||
// create face-varying array and append indices to buffer:
|
||||
PatchArray fvarPatchArray(
|
||||
farPatchTable->GetFVarPatchDescriptorRegular(fvc),
|
||||
farPatchTable->GetFVarPatchDescriptorIrregular(fvc),
|
||||
numPatchesThisArray,
|
||||
(int)_fvarIndexBuffers[fvc].size(), (int)_fvarParamBuffers[fvc].size());
|
||||
_fvarPatchArrays[fvc].push_back(fvarPatchArray);
|
||||
|
||||
Far::ConstIndexArray
|
||||
fvarIndices = farPatchTable->GetPatchArrayFVarValues(j, fvc);
|
||||
_fvarIndexBuffers[fvc].insert(_fvarIndexBuffers[fvc].end(),
|
||||
fvarIndices.begin(), fvarIndices.end());
|
||||
|
||||
// append face-varying patch params (converting Far PatchParams to Osd)
|
||||
Far::ConstPatchParamArray
|
||||
fvarParam = farPatchTable->GetPatchArrayFVarPatchParams(j, fvc);
|
||||
|
||||
for (int k = 0; k < numPatchesThisArray; ++k) {
|
||||
PatchParam param;
|
||||
//param.patchParam = patchParamTable[patchIndex];
|
||||
param.field0 = fvarParam[k].field0;
|
||||
param.field1 = fvarParam[k].field1;
|
||||
param.sharpness = 0.0f;
|
||||
_fvarParamBuffers[fvc].push_back(param);
|
||||
}
|
||||
}
|
||||
|
||||
// patchParams bundling
|
||||
// XXX: this process won't be needed if Far::PatchParam includes
|
||||
// sharpness.
|
||||
#if 0
|
||||
// XXX: we need sharpness interface for patcharray or put sharpness
|
||||
// into patchParam.
|
||||
Far::ConstPatchParamArray patchParams =
|
||||
farPatchTable->GetPatchParams(j);
|
||||
for (int k = 0; k < patchParams.size(); ++k) {
|
||||
float sharpness = 0.0;
|
||||
_patchParamBuffer.push_back(patchParams[k].field0);
|
||||
_patchParamBuffer.push_back(patchParams[k].field1);
|
||||
_patchParamBuffer.push_back(*((unsigned int *)&sharpness));
|
||||
}
|
||||
#else
|
||||
// XXX: workaround. GetPatchParamTable() will be deprecated though.
|
||||
Far::PatchParamTable const & patchParamTable =
|
||||
farPatchTable->GetPatchParamTable();
|
||||
std::vector<Far::Index> const &sharpnessIndexTable =
|
||||
farPatchTable->GetSharpnessIndexTable();
|
||||
int numPatchesJ = farPatchTable->GetNumPatches(j);
|
||||
for (int k = 0; k < numPatchesJ; ++k) {
|
||||
float sharpness = 0.0;
|
||||
int patchIndex = (int)_patchParamBuffer.size();
|
||||
if (patchIndex < (int)sharpnessIndexTable.size()) {
|
||||
int sharpnessIndex = sharpnessIndexTable[patchIndex];
|
||||
if (sharpnessIndex >= 0)
|
||||
sharpness = farPatchTable->GetSharpnessValues()[sharpnessIndex];
|
||||
}
|
||||
PatchParam param;
|
||||
//param.patchParam = patchParamTable[patchIndex];
|
||||
param.field0 = patchParamTable[patchIndex].field0;
|
||||
param.field1 = patchParamTable[patchIndex].field1;
|
||||
param.sharpness = sharpness;
|
||||
_patchParamBuffer.push_back(param);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
145
src/osd/opensubdiv/osd/cpuPatchTable.h
Normal file
145
src/osd/opensubdiv/osd/cpuPatchTable.h
Normal file
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_OSD_CPU_PATCH_TABLE_H
|
||||
#define OPENSUBDIV3_OSD_CPU_PATCH_TABLE_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include <vector>
|
||||
#include "../far/patchDescriptor.h"
|
||||
#include "../osd/nonCopyable.h"
|
||||
#include "../osd/types.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far{
|
||||
class PatchTable;
|
||||
};
|
||||
|
||||
namespace Osd {
|
||||
|
||||
/// \brief Cpu patch table
|
||||
///
|
||||
/// XXX: We can use just Far::PatchTable for typical CpuEval use cases.
|
||||
///
|
||||
/// Currently this class exists because of the template resolution
|
||||
/// for the CpuEvaluator's generic interface functions
|
||||
/// (glEvalLimit example uses), and
|
||||
/// device-specific patch tables such as GLPatchTables internally use
|
||||
/// as a staging buffer to splice patcharray and interleave sharpnesses.
|
||||
///
|
||||
/// Ideally Far::PatchTables should have the same data representation
|
||||
/// and accessors so that we don't have to copy data unnecessarily.
|
||||
///
|
||||
class CpuPatchTable {
|
||||
public:
|
||||
static CpuPatchTable *Create(const Far::PatchTable *patchTable,
|
||||
void *deviceContext = NULL) {
|
||||
(void)deviceContext; // unused
|
||||
return new CpuPatchTable(patchTable);
|
||||
}
|
||||
|
||||
explicit CpuPatchTable(const Far::PatchTable *patchTable);
|
||||
~CpuPatchTable() {}
|
||||
|
||||
const PatchArray *GetPatchArrayBuffer() const {
|
||||
return &_patchArrays[0];
|
||||
}
|
||||
const int *GetPatchIndexBuffer() const {
|
||||
return &_indexBuffer[0];
|
||||
}
|
||||
const PatchParam *GetPatchParamBuffer() const {
|
||||
return &_patchParamBuffer[0];
|
||||
}
|
||||
|
||||
size_t GetNumPatchArrays() const {
|
||||
return _patchArrays.size();
|
||||
}
|
||||
size_t GetPatchIndexSize() const {
|
||||
return _indexBuffer.size();
|
||||
}
|
||||
size_t GetPatchParamSize() const {
|
||||
return _patchParamBuffer.size();
|
||||
}
|
||||
|
||||
const PatchArray *GetVaryingPatchArrayBuffer() const {
|
||||
if (_varyingPatchArrays.empty()) {
|
||||
return NULL;
|
||||
}
|
||||
return &_varyingPatchArrays[0];
|
||||
}
|
||||
const int *GetVaryingPatchIndexBuffer() const {
|
||||
if (_varyingIndexBuffer.empty()) {
|
||||
return NULL;
|
||||
}
|
||||
return &_varyingIndexBuffer[0];
|
||||
}
|
||||
size_t GetVaryingPatchIndexSize() const {
|
||||
return _varyingIndexBuffer.size();
|
||||
}
|
||||
|
||||
int GetNumFVarChannels() const {
|
||||
return (int)_fvarPatchArrays.size();
|
||||
}
|
||||
const PatchArray *GetFVarPatchArrayBuffer(int fvarChannel = 0) const {
|
||||
return &_fvarPatchArrays[fvarChannel][0];
|
||||
}
|
||||
const int *GetFVarPatchIndexBuffer(int fvarChannel = 0) const {
|
||||
return &_fvarIndexBuffers[fvarChannel][0];
|
||||
}
|
||||
size_t GetFVarPatchIndexSize(int fvarChannel = 0) const {
|
||||
return _fvarIndexBuffers[fvarChannel].size();
|
||||
}
|
||||
const PatchParam *GetFVarPatchParamBuffer(int fvarChannel= 0) const {
|
||||
return &_fvarParamBuffers[fvarChannel][0];
|
||||
}
|
||||
size_t GetFVarPatchParamSize(int fvarChannel = 0) const {
|
||||
return _fvarParamBuffers[fvarChannel].size();
|
||||
}
|
||||
|
||||
protected:
|
||||
PatchArrayVector _patchArrays;
|
||||
std::vector<int> _indexBuffer;
|
||||
PatchParamVector _patchParamBuffer;
|
||||
|
||||
PatchArrayVector _varyingPatchArrays;
|
||||
std::vector<int> _varyingIndexBuffer;
|
||||
|
||||
std::vector< PatchArrayVector > _fvarPatchArrays;
|
||||
std::vector< std::vector<int> > _fvarIndexBuffers;
|
||||
std::vector< PatchParamVector > _fvarParamBuffers;
|
||||
};
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_OSD_CPU_PATCH_TABLE_H
|
||||
84
src/osd/opensubdiv/osd/cpuVertexBuffer.cpp
Normal file
84
src/osd/opensubdiv/osd/cpuVertexBuffer.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../osd/cpuVertexBuffer.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
CpuVertexBuffer::CpuVertexBuffer(int numElements, int numVertices)
|
||||
: _numElements(numElements),
|
||||
_numVertices(numVertices),
|
||||
_cpuBuffer(NULL) {
|
||||
|
||||
_cpuBuffer = new float[numElements * numVertices];
|
||||
}
|
||||
|
||||
CpuVertexBuffer::~CpuVertexBuffer() {
|
||||
|
||||
delete[] _cpuBuffer;
|
||||
}
|
||||
|
||||
CpuVertexBuffer *
|
||||
CpuVertexBuffer::Create(int numElements, int numVertices,
|
||||
void * /*deviceContext*/) {
|
||||
|
||||
return new CpuVertexBuffer(numElements, numVertices);
|
||||
}
|
||||
|
||||
void
|
||||
CpuVertexBuffer::UpdateData(const float *src, int startVertex, int numVertices,
|
||||
void * /*deviceContext*/) {
|
||||
|
||||
memcpy(_cpuBuffer + startVertex * _numElements,
|
||||
src, GetNumElements() * numVertices * sizeof(float));
|
||||
}
|
||||
|
||||
int
|
||||
CpuVertexBuffer::GetNumElements() const {
|
||||
|
||||
return _numElements;
|
||||
}
|
||||
|
||||
int
|
||||
CpuVertexBuffer::GetNumVertices() const {
|
||||
|
||||
return _numVertices;
|
||||
}
|
||||
|
||||
float*
|
||||
CpuVertexBuffer::BindCpuBuffer() {
|
||||
|
||||
return _cpuBuffer;
|
||||
}
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
83
src/osd/opensubdiv/osd/cpuVertexBuffer.h
Normal file
83
src/osd/opensubdiv/osd/cpuVertexBuffer.h
Normal file
@@ -0,0 +1,83 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_OSD_CPU_VERTEX_BUFFER_H
|
||||
#define OPENSUBDIV3_OSD_CPU_VERTEX_BUFFER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
/// \brief Concrete vertex buffer class for CPU subdivision.
|
||||
///
|
||||
/// CpuVertexBuffer implements the VertexBufferInterface. An instance
|
||||
/// of this buffer class can be passed to CpuEvaluator
|
||||
///
|
||||
class CpuVertexBuffer {
|
||||
public:
|
||||
/// Creator. Returns NULL if error.
|
||||
static CpuVertexBuffer * Create(int numElements, int numVertices,
|
||||
void *deviceContext = NULL);
|
||||
|
||||
/// Destructor.
|
||||
~CpuVertexBuffer();
|
||||
|
||||
/// This method is meant to be used in client code in order to provide
|
||||
/// coarse vertices data to Osd.
|
||||
void UpdateData(const float *src, int startVertex, int numVertices,
|
||||
void *deviceContext = NULL);
|
||||
|
||||
/// Returns how many elements defined in this vertex buffer.
|
||||
int GetNumElements() const;
|
||||
|
||||
/// Returns how many vertices allocated in this vertex buffer.
|
||||
int GetNumVertices() const;
|
||||
|
||||
/// Returns the address of CPU buffer
|
||||
float * BindCpuBuffer();
|
||||
|
||||
protected:
|
||||
/// Constructor.
|
||||
CpuVertexBuffer(int numElements, int numVertices);
|
||||
|
||||
private:
|
||||
int _numElements;
|
||||
int _numVertices;
|
||||
float *_cpuBuffer;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_OSD_CPU_VERTEX_BUFFER_H
|
||||
151
src/osd/opensubdiv/osd/cudaD3D11VertexBuffer.cpp
Normal file
151
src/osd/opensubdiv/osd/cudaD3D11VertexBuffer.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../osd/cudaD3D11VertexBuffer.h"
|
||||
#include "../far/error.h"
|
||||
|
||||
#include <D3D11.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <cuda_d3d11_interop.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
CudaD3D11VertexBuffer::CudaD3D11VertexBuffer(int numElements, int numVertices)
|
||||
: _numElements(numElements), _numVertices(numVertices),
|
||||
_d3d11Buffer(NULL), _cudaBuffer(NULL), _cudaResource(NULL) {
|
||||
}
|
||||
|
||||
CudaD3D11VertexBuffer::~CudaD3D11VertexBuffer() {
|
||||
|
||||
unmap();
|
||||
cudaGraphicsUnregisterResource(_cudaResource);
|
||||
_d3d11Buffer->Release();
|
||||
}
|
||||
|
||||
CudaD3D11VertexBuffer *
|
||||
CudaD3D11VertexBuffer::Create(int numElements, int numVertices,
|
||||
ID3D11DeviceContext *deviceContext) {
|
||||
CudaD3D11VertexBuffer *instance =
|
||||
new CudaD3D11VertexBuffer(numElements, numVertices);
|
||||
|
||||
ID3D11Device *device;
|
||||
deviceContext->GetDevice(&device);
|
||||
if (instance->allocate(device)) return instance;
|
||||
delete instance;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CudaD3D11VertexBuffer::UpdateData(const float *src,
|
||||
int startVertex, int numVertices,
|
||||
void * /*deviceContext*/) {
|
||||
|
||||
map();
|
||||
cudaMemcpy((float*)_cudaBuffer + _numElements * startVertex,
|
||||
src, _numElements * numVertices * sizeof(float),
|
||||
cudaMemcpyHostToDevice);
|
||||
}
|
||||
|
||||
int
|
||||
CudaD3D11VertexBuffer::GetNumElements() const {
|
||||
|
||||
return _numElements;
|
||||
}
|
||||
|
||||
int
|
||||
CudaD3D11VertexBuffer::GetNumVertices() const {
|
||||
|
||||
return _numVertices;
|
||||
}
|
||||
|
||||
float *
|
||||
CudaD3D11VertexBuffer::BindCudaBuffer() {
|
||||
|
||||
map();
|
||||
return (float*)_cudaBuffer;
|
||||
}
|
||||
|
||||
ID3D11Buffer *
|
||||
CudaD3D11VertexBuffer::BindD3D11Buffer(ID3D11DeviceContext *deviceContext) {
|
||||
|
||||
unmap();
|
||||
return _d3d11Buffer;
|
||||
}
|
||||
|
||||
bool
|
||||
CudaD3D11VertexBuffer::allocate(ID3D11Device *device) {
|
||||
|
||||
D3D11_BUFFER_DESC hBufferDesc;
|
||||
hBufferDesc.ByteWidth = _numElements * _numVertices * sizeof(float);
|
||||
hBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
hBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_SHADER_RESOURCE;
|
||||
hBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
hBufferDesc.MiscFlags = 0;
|
||||
hBufferDesc.StructureByteStride = sizeof(float);
|
||||
|
||||
HRESULT hr;
|
||||
hr = device->CreateBuffer(&hBufferDesc, NULL, &_d3d11Buffer);
|
||||
if(FAILED(hr)) {
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR,
|
||||
"Fail in CreateBuffer\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// register d3d11buffer as cuda resource
|
||||
cudaError_t err = cudaGraphicsD3D11RegisterResource(
|
||||
&_cudaResource, _d3d11Buffer, cudaGraphicsRegisterFlagsNone);
|
||||
|
||||
if (err != cudaSuccess) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CudaD3D11VertexBuffer::map() {
|
||||
|
||||
if (_cudaBuffer) return;
|
||||
size_t num_bytes;
|
||||
void *ptr;
|
||||
|
||||
cudaGraphicsMapResources(1, &_cudaResource, 0);
|
||||
cudaGraphicsResourceGetMappedPointer(&ptr, &num_bytes, _cudaResource);
|
||||
_cudaBuffer = ptr;
|
||||
}
|
||||
|
||||
void
|
||||
CudaD3D11VertexBuffer::unmap() {
|
||||
|
||||
if (_cudaBuffer == NULL) return;
|
||||
cudaGraphicsUnmapResources(1, &_cudaResource, 0);
|
||||
_cudaBuffer = NULL;
|
||||
}
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
109
src/osd/opensubdiv/osd/cudaD3D11VertexBuffer.h
Normal file
109
src/osd/opensubdiv/osd/cudaD3D11VertexBuffer.h
Normal file
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_OSD_CUDA_D3D11_VERTEX_BUFFER_H
|
||||
#define OPENSUBDIV3_OSD_CUDA_D3D11_VERTEX_BUFFER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
struct cudaGraphicsResource;
|
||||
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11Device;
|
||||
struct ID3D11DeviceContext;
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
/// \brief Concrete vertex buffer class for cuda subdivision and D3D11 drawing.
|
||||
///
|
||||
/// CudaD3D11VertexBuffer implements CudaVertexBufferInterface and
|
||||
/// D3D11VertexBufferInterface.
|
||||
///
|
||||
/// The buffer interop between Cuda and D3D is handled automatically when a
|
||||
/// client calls BindCudaBuffer and BindVBO methods.
|
||||
///
|
||||
class CudaD3D11VertexBuffer {
|
||||
public:
|
||||
/// Creator. Returns NULL if error.
|
||||
static CudaD3D11VertexBuffer * Create(int numElements,
|
||||
int numVertices,
|
||||
ID3D11DeviceContext *deviceContext);
|
||||
|
||||
/// Destructor.
|
||||
virtual ~CudaD3D11VertexBuffer();
|
||||
|
||||
/// This method is meant to be used in client code in order to provide coarse
|
||||
/// vertices data to Osd.
|
||||
void UpdateData(const float *src, int startVertex, int numVertices,
|
||||
void * /*deviceContext*/);
|
||||
|
||||
/// Returns how many elements defined in this vertex buffer.
|
||||
int GetNumElements() const;
|
||||
|
||||
/// Returns how many vertices allocated in this vertex buffer.
|
||||
int GetNumVertices() const;
|
||||
|
||||
/// Returns cuda memory. DX buffer will be mapped to cuda resource
|
||||
/// if necessary.
|
||||
float * BindCudaBuffer();
|
||||
|
||||
/// Returns the D3D11 buffer object.
|
||||
ID3D11Buffer *BindD3D11Buffer(ID3D11DeviceContext *deviceContext);
|
||||
|
||||
/// Returns the D3D11 buffer object (for Osd::Mesh interface)
|
||||
ID3D11Buffer *BindVBO(ID3D11DeviceContext *deviceContext) {
|
||||
return BindD3D11Buffer(deviceContext);
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Constructor.
|
||||
CudaD3D11VertexBuffer(int numElements, int numVertices);
|
||||
|
||||
bool allocate(ID3D11Device *device);
|
||||
|
||||
// Acquires a cuda resource from DX11
|
||||
void map();
|
||||
|
||||
// Releases a cuda resource to DX11
|
||||
void unmap();
|
||||
|
||||
private:
|
||||
int _numElements;
|
||||
int _numVertices;
|
||||
ID3D11Buffer *_d3d11Buffer;
|
||||
void *_cudaBuffer;
|
||||
cudaGraphicsResource *_cudaResource;
|
||||
};
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_OSD_CUDA_D3D11_VERTEX_BUFFER_H
|
||||
385
src/osd/opensubdiv/osd/cudaEvaluator.cpp
Normal file
385
src/osd/opensubdiv/osd/cudaEvaluator.cpp
Normal file
@@ -0,0 +1,385 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../osd/cudaEvaluator.h"
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
#include <vector>
|
||||
|
||||
#include "../far/stencilTable.h"
|
||||
#include "../osd/types.h"
|
||||
|
||||
extern "C" {
|
||||
void CudaEvalStencils(const float *src,
|
||||
float *dst,
|
||||
int length,
|
||||
int srcStride,
|
||||
int dstStride,
|
||||
const int * sizes,
|
||||
const int * offsets,
|
||||
const int * indices,
|
||||
const float * weights,
|
||||
int start,
|
||||
int end);
|
||||
|
||||
void CudaEvalPatches(
|
||||
const float *src, float *dst,
|
||||
int length, int srcStride, int dstStride,
|
||||
int numPatchCoords,
|
||||
const void *patchCoords,
|
||||
const void *patchArrays,
|
||||
const int *patchIndices,
|
||||
const void *patchParams);
|
||||
|
||||
void CudaEvalPatchesWithDerivatives(
|
||||
const float *src, float *dst,
|
||||
float *du, float *dv,
|
||||
float *duu, float *duv, float *dvv,
|
||||
int length, int srcStride, int dstStride,
|
||||
int duStride, int dvStride,
|
||||
int duuStride, int duvStride, int dvvStride,
|
||||
int numPatchCoords,
|
||||
const void *patchCoords,
|
||||
const void *patchArrays,
|
||||
const int *patchIndices,
|
||||
const void *patchParams);
|
||||
|
||||
}
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
template <class T> void *
|
||||
createCudaBuffer(std::vector<T> const & src) {
|
||||
if (src.empty()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void * devicePtr = 0;
|
||||
|
||||
size_t size = src.size()*sizeof(T);
|
||||
|
||||
cudaError_t err = cudaMalloc(&devicePtr, size);
|
||||
if (err != cudaSuccess) {
|
||||
return devicePtr;
|
||||
}
|
||||
|
||||
err = cudaMemcpy(devicePtr, &src.at(0), size, cudaMemcpyHostToDevice);
|
||||
if (err != cudaSuccess) {
|
||||
cudaFree(devicePtr);
|
||||
return 0;
|
||||
}
|
||||
return devicePtr;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
CudaStencilTable::CudaStencilTable(Far::StencilTable const *stencilTable) {
|
||||
_numStencils = stencilTable->GetNumStencils();
|
||||
if (_numStencils > 0) {
|
||||
_sizes = createCudaBuffer(stencilTable->GetSizes());
|
||||
_offsets = createCudaBuffer(stencilTable->GetOffsets());
|
||||
_indices = createCudaBuffer(stencilTable->GetControlIndices());
|
||||
_weights = createCudaBuffer(stencilTable->GetWeights());
|
||||
_duWeights = _dvWeights = NULL;
|
||||
_duuWeights = _duvWeights = _dvvWeights = NULL;
|
||||
} else {
|
||||
_sizes = _offsets = _indices = _weights = NULL;
|
||||
_duWeights = _dvWeights = NULL;
|
||||
_duuWeights = _duvWeights = _dvvWeights = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CudaStencilTable::CudaStencilTable(Far::LimitStencilTable const *limitStencilTable) {
|
||||
_numStencils = limitStencilTable->GetNumStencils();
|
||||
if (_numStencils > 0) {
|
||||
_sizes = createCudaBuffer(limitStencilTable->GetSizes());
|
||||
_offsets = createCudaBuffer(limitStencilTable->GetOffsets());
|
||||
_indices = createCudaBuffer(limitStencilTable->GetControlIndices());
|
||||
_weights = createCudaBuffer(limitStencilTable->GetWeights());
|
||||
_duWeights = createCudaBuffer(limitStencilTable->GetDuWeights());
|
||||
_dvWeights = createCudaBuffer(limitStencilTable->GetDvWeights());
|
||||
_duuWeights = createCudaBuffer(limitStencilTable->GetDuuWeights());
|
||||
_duvWeights = createCudaBuffer(limitStencilTable->GetDuvWeights());
|
||||
_dvvWeights = createCudaBuffer(limitStencilTable->GetDvvWeights());
|
||||
} else {
|
||||
_sizes = _offsets = _indices = _weights = NULL;
|
||||
_duWeights = _dvWeights = NULL;
|
||||
_duuWeights = _duvWeights = _dvvWeights = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CudaStencilTable::~CudaStencilTable() {
|
||||
if (_sizes) cudaFree(_sizes);
|
||||
if (_offsets) cudaFree(_offsets);
|
||||
if (_indices) cudaFree(_indices);
|
||||
if (_weights) cudaFree(_weights);
|
||||
if (_duWeights) cudaFree(_duWeights);
|
||||
if (_dvWeights) cudaFree(_dvWeights);
|
||||
if (_duuWeights) cudaFree(_duuWeights);
|
||||
if (_duvWeights) cudaFree(_duvWeights);
|
||||
if (_dvvWeights) cudaFree(_dvvWeights);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CudaEvaluator::EvalStencils(const float *src, BufferDescriptor const &srcDesc,
|
||||
float *dst, BufferDescriptor const &dstDesc,
|
||||
const int * sizes,
|
||||
const int * offsets,
|
||||
const int * indices,
|
||||
const float * weights,
|
||||
int start,
|
||||
int end) {
|
||||
if (dst == NULL) return false;
|
||||
|
||||
CudaEvalStencils(src + srcDesc.offset,
|
||||
dst + dstDesc.offset,
|
||||
srcDesc.length,
|
||||
srcDesc.stride,
|
||||
dstDesc.stride,
|
||||
sizes, offsets, indices, weights,
|
||||
start, end);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CudaEvaluator::EvalStencils(const float *src, BufferDescriptor const &srcDesc,
|
||||
float *dst, BufferDescriptor const &dstDesc,
|
||||
float *du, BufferDescriptor const &duDesc,
|
||||
float *dv, BufferDescriptor const &dvDesc,
|
||||
const int * sizes,
|
||||
const int * offsets,
|
||||
const int * indices,
|
||||
const float * weights,
|
||||
const float * duWeights,
|
||||
const float * dvWeights,
|
||||
int start,
|
||||
int end) {
|
||||
// PERFORMANCE: need to combine 3 launches together
|
||||
if (dst) {
|
||||
CudaEvalStencils(src + srcDesc.offset,
|
||||
dst + dstDesc.offset,
|
||||
srcDesc.length,
|
||||
srcDesc.stride,
|
||||
dstDesc.stride,
|
||||
sizes, offsets, indices, weights,
|
||||
start, end);
|
||||
}
|
||||
if (du) {
|
||||
CudaEvalStencils(src + srcDesc.offset,
|
||||
du + duDesc.offset,
|
||||
srcDesc.length,
|
||||
srcDesc.stride,
|
||||
duDesc.stride,
|
||||
sizes, offsets, indices, duWeights,
|
||||
start, end);
|
||||
}
|
||||
if (dv) {
|
||||
CudaEvalStencils(src + srcDesc.offset,
|
||||
dv + dvDesc.offset,
|
||||
srcDesc.length,
|
||||
srcDesc.stride,
|
||||
dvDesc.stride,
|
||||
sizes, offsets, indices, dvWeights,
|
||||
start, end);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CudaEvaluator::EvalStencils(const float *src, BufferDescriptor const &srcDesc,
|
||||
float *dst, BufferDescriptor const &dstDesc,
|
||||
float *du, BufferDescriptor const &duDesc,
|
||||
float *dv, BufferDescriptor const &dvDesc,
|
||||
float *duu, BufferDescriptor const &duuDesc,
|
||||
float *duv, BufferDescriptor const &duvDesc,
|
||||
float *dvv, BufferDescriptor const &dvvDesc,
|
||||
const int * sizes,
|
||||
const int * offsets,
|
||||
const int * indices,
|
||||
const float * weights,
|
||||
const float * duWeights,
|
||||
const float * dvWeights,
|
||||
const float * duuWeights,
|
||||
const float * duvWeights,
|
||||
const float * dvvWeights,
|
||||
int start,
|
||||
int end) {
|
||||
// PERFORMANCE: need to combine 3 launches together
|
||||
if (dst) {
|
||||
CudaEvalStencils(src + srcDesc.offset,
|
||||
dst + dstDesc.offset,
|
||||
srcDesc.length,
|
||||
srcDesc.stride,
|
||||
dstDesc.stride,
|
||||
sizes, offsets, indices, weights,
|
||||
start, end);
|
||||
}
|
||||
if (du) {
|
||||
CudaEvalStencils(src + srcDesc.offset,
|
||||
du + duDesc.offset,
|
||||
srcDesc.length,
|
||||
srcDesc.stride,
|
||||
duDesc.stride,
|
||||
sizes, offsets, indices, duWeights,
|
||||
start, end);
|
||||
}
|
||||
if (dv) {
|
||||
CudaEvalStencils(src + srcDesc.offset,
|
||||
dv + dvDesc.offset,
|
||||
srcDesc.length,
|
||||
srcDesc.stride,
|
||||
dvDesc.stride,
|
||||
sizes, offsets, indices, dvWeights,
|
||||
start, end);
|
||||
}
|
||||
if (duu) {
|
||||
CudaEvalStencils(src + srcDesc.offset,
|
||||
duu + duuDesc.offset,
|
||||
srcDesc.length,
|
||||
srcDesc.stride,
|
||||
duuDesc.stride,
|
||||
sizes, offsets, indices, duuWeights,
|
||||
start, end);
|
||||
}
|
||||
if (duv) {
|
||||
CudaEvalStencils(src + srcDesc.offset,
|
||||
duv + duvDesc.offset,
|
||||
srcDesc.length,
|
||||
srcDesc.stride,
|
||||
duvDesc.stride,
|
||||
sizes, offsets, indices, duvWeights,
|
||||
start, end);
|
||||
}
|
||||
if (dvv) {
|
||||
CudaEvalStencils(src + srcDesc.offset,
|
||||
dvv + dvvDesc.offset,
|
||||
srcDesc.length,
|
||||
srcDesc.stride,
|
||||
dvvDesc.stride,
|
||||
sizes, offsets, indices, dvvWeights,
|
||||
start, end);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CudaEvaluator::EvalPatches(const float *src,
|
||||
BufferDescriptor const &srcDesc,
|
||||
float *dst,
|
||||
BufferDescriptor const &dstDesc,
|
||||
int numPatchCoords,
|
||||
const PatchCoord *patchCoords,
|
||||
const PatchArray *patchArrays,
|
||||
const int *patchIndices,
|
||||
const PatchParam *patchParams) {
|
||||
if (src) src += srcDesc.offset;
|
||||
if (dst) dst += dstDesc.offset;
|
||||
|
||||
CudaEvalPatches(src, dst,
|
||||
srcDesc.length, srcDesc.stride, dstDesc.stride,
|
||||
numPatchCoords, patchCoords, patchArrays, patchIndices, patchParams);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CudaEvaluator::EvalPatches(
|
||||
const float *src, BufferDescriptor const &srcDesc,
|
||||
float *dst, BufferDescriptor const &dstDesc,
|
||||
float *du, BufferDescriptor const &duDesc,
|
||||
float *dv, BufferDescriptor const &dvDesc,
|
||||
int numPatchCoords,
|
||||
const PatchCoord *patchCoords,
|
||||
const PatchArray *patchArrays,
|
||||
const int *patchIndices,
|
||||
const PatchParam *patchParams) {
|
||||
|
||||
if (src) src += srcDesc.offset;
|
||||
if (dst) dst += dstDesc.offset;
|
||||
if (du) du += duDesc.offset;
|
||||
if (dv) dv += dvDesc.offset;
|
||||
|
||||
CudaEvalPatchesWithDerivatives(
|
||||
src, dst, du, dv, NULL, NULL, NULL,
|
||||
srcDesc.length, srcDesc.stride, dstDesc.stride,
|
||||
duDesc.stride, dvDesc.stride, 0, 0, 0,
|
||||
numPatchCoords, patchCoords, patchArrays, patchIndices, patchParams);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CudaEvaluator::EvalPatches(
|
||||
const float *src, BufferDescriptor const &srcDesc,
|
||||
float *dst, BufferDescriptor const &dstDesc,
|
||||
float *du, BufferDescriptor const &duDesc,
|
||||
float *dv, BufferDescriptor const &dvDesc,
|
||||
float *duu, BufferDescriptor const &duuDesc,
|
||||
float *duv, BufferDescriptor const &duvDesc,
|
||||
float *dvv, BufferDescriptor const &dvvDesc,
|
||||
int numPatchCoords,
|
||||
const PatchCoord *patchCoords,
|
||||
const PatchArray *patchArrays,
|
||||
const int *patchIndices,
|
||||
const PatchParam *patchParams) {
|
||||
|
||||
if (src) src += srcDesc.offset;
|
||||
if (dst) dst += dstDesc.offset;
|
||||
if (du) du += duDesc.offset;
|
||||
if (dv) dv += dvDesc.offset;
|
||||
if (duu) duu += duuDesc.offset;
|
||||
if (duv) duv += duvDesc.offset;
|
||||
if (dvv) dvv += dvvDesc.offset;
|
||||
|
||||
CudaEvalPatchesWithDerivatives(
|
||||
src, dst, du, dv, duu, duv, dvv,
|
||||
srcDesc.length, srcDesc.stride, dstDesc.stride,
|
||||
duDesc.stride, dvDesc.stride,
|
||||
duuDesc.stride, duvDesc.stride, dvvDesc.stride,
|
||||
numPatchCoords, patchCoords, patchArrays, patchIndices, patchParams);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* static */
|
||||
void
|
||||
CudaEvaluator::Synchronize(void * /*deviceContext*/) {
|
||||
cudaThreadSynchronize();
|
||||
}
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
1273
src/osd/opensubdiv/osd/cudaEvaluator.h
Normal file
1273
src/osd/opensubdiv/osd/cudaEvaluator.h
Normal file
File diff suppressed because it is too large
Load Diff
173
src/osd/opensubdiv/osd/cudaGLVertexBuffer.cpp
Normal file
173
src/osd/opensubdiv/osd/cudaGLVertexBuffer.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "glLoader.h"
|
||||
|
||||
#include "../osd/cudaGLVertexBuffer.h"
|
||||
#include "../far/error.h"
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
#include <cuda_gl_interop.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
CudaGLVertexBuffer::CudaGLVertexBuffer(int numElements, int numVertices)
|
||||
: _numElements(numElements), _numVertices(numVertices),
|
||||
_vbo(0), _devicePtr(0), _cudaResource(0) {
|
||||
|
||||
// Initialize internal OpenGL loader library if necessary
|
||||
OpenSubdiv::internal::GLLoader::libraryInitializeGL();
|
||||
}
|
||||
|
||||
CudaGLVertexBuffer::~CudaGLVertexBuffer() {
|
||||
|
||||
unmap();
|
||||
cudaGraphicsUnregisterResource(_cudaResource);
|
||||
glDeleteBuffers(1, &_vbo);
|
||||
}
|
||||
|
||||
CudaGLVertexBuffer *
|
||||
CudaGLVertexBuffer::Create(int numElements, int numVertices, void *) {
|
||||
CudaGLVertexBuffer *instance =
|
||||
new CudaGLVertexBuffer(numElements, numVertices);
|
||||
if (instance->allocate()) return instance;
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR, "CudaGLVertexBuffer::Create failed.\n");
|
||||
delete instance;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CudaGLVertexBuffer::UpdateData(const float *src,
|
||||
int startVertex, int numVertices,
|
||||
void * /*deviceContext*/) {
|
||||
|
||||
map();
|
||||
cudaError_t err = cudaMemcpy((float*)_devicePtr + _numElements * startVertex,
|
||||
src,
|
||||
_numElements * numVertices * sizeof(float),
|
||||
cudaMemcpyHostToDevice);
|
||||
if (err != cudaSuccess)
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR,
|
||||
"CudaGLVertexBuffer::UpdateData failed. : %s\n",
|
||||
cudaGetErrorString(err));
|
||||
}
|
||||
|
||||
int
|
||||
CudaGLVertexBuffer::GetNumElements() const {
|
||||
|
||||
return _numElements;
|
||||
}
|
||||
|
||||
int
|
||||
CudaGLVertexBuffer::GetNumVertices() const {
|
||||
|
||||
return _numVertices;
|
||||
}
|
||||
|
||||
float *
|
||||
CudaGLVertexBuffer::BindCudaBuffer() {
|
||||
|
||||
map();
|
||||
return static_cast<float*>(_devicePtr);
|
||||
}
|
||||
|
||||
GLuint
|
||||
CudaGLVertexBuffer::BindVBO(void * /*deviceContext*/) {
|
||||
|
||||
unmap();
|
||||
return _vbo;
|
||||
}
|
||||
|
||||
bool
|
||||
CudaGLVertexBuffer::allocate() {
|
||||
|
||||
int size = _numElements * _numVertices * sizeof(float);
|
||||
|
||||
|
||||
#if defined(GL_ARB_direct_state_access)
|
||||
if (OSD_OPENGL_HAS(ARB_direct_state_access)) {
|
||||
glCreateBuffers(1, &_vbo);
|
||||
glNamedBufferData(_vbo, size, 0, GL_DYNAMIC_DRAW);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
GLint prev = 0;
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &prev);
|
||||
glGenBuffers(1, &_vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, prev);
|
||||
}
|
||||
|
||||
// register vbo as cuda resource
|
||||
cudaError_t err = cudaGraphicsGLRegisterBuffer(
|
||||
&_cudaResource, _vbo, cudaGraphicsMapFlagsWriteDiscard);
|
||||
|
||||
if (err != cudaSuccess) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CudaGLVertexBuffer::map() {
|
||||
|
||||
if (_devicePtr) return;
|
||||
size_t num_bytes;
|
||||
void *ptr;
|
||||
|
||||
cudaError_t err = cudaGraphicsMapResources(1, &_cudaResource, 0);
|
||||
if (err != cudaSuccess)
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR,
|
||||
"CudaGLVertexBuffer::map failed.\n%s\n",
|
||||
cudaGetErrorString(err));
|
||||
err = cudaGraphicsResourceGetMappedPointer(&ptr, &num_bytes, _cudaResource);
|
||||
if (err != cudaSuccess)
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR,
|
||||
"CudaGLVertexBuffer::map failed.\n%s\n",
|
||||
cudaGetErrorString(err));
|
||||
_devicePtr = ptr;
|
||||
}
|
||||
|
||||
void
|
||||
CudaGLVertexBuffer::unmap() {
|
||||
|
||||
if (_devicePtr == NULL) return;
|
||||
cudaError_t err = cudaGraphicsUnmapResources(1, &_cudaResource, 0);
|
||||
if (err != cudaSuccess)
|
||||
Far::Error(Far::FAR_RUNTIME_ERROR,
|
||||
"CudaGLVertexBuffer::unmap failed.\n%s\n",
|
||||
cudaGetErrorString(err));
|
||||
_devicePtr = NULL;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
108
src/osd/opensubdiv/osd/cudaGLVertexBuffer.h
Normal file
108
src/osd/opensubdiv/osd/cudaGLVertexBuffer.h
Normal file
@@ -0,0 +1,108 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_OSD_CUDA_GL_VERTEX_BUFFER_H
|
||||
#define OPENSUBDIV3_OSD_CUDA_GL_VERTEX_BUFFER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#include "../osd/opengl.h" // needed before cuda_gl_interop.h
|
||||
|
||||
#include <cuda_gl_interop.h>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
/// \brief Concrete vertex buffer class for cuda subdivision and OpenGL drawing.
|
||||
///
|
||||
/// CudaGLVertexBuffer implements CudaVertexBufferInterface and
|
||||
/// GLVertexBufferInterface.
|
||||
///
|
||||
/// The buffer interop between Cuda and GL is handled automatically when a
|
||||
/// client calls BindCudaBuffer and BindVBO methods.
|
||||
///
|
||||
class CudaGLVertexBuffer {
|
||||
public:
|
||||
/// Creator. Returns NULL if error.
|
||||
static CudaGLVertexBuffer * Create(int numElements, int numVertices,
|
||||
void *deviceContext = NULL);
|
||||
|
||||
/// Destructor.
|
||||
~CudaGLVertexBuffer();
|
||||
|
||||
/// This method is meant to be used in client code in order to provide
|
||||
/// coarse vertices data to Osd.
|
||||
void UpdateData(const float *src, int startVertex, int numVertices,
|
||||
void *deviceContext = NULL);
|
||||
|
||||
/// Returns how many elements defined in this vertex buffer.
|
||||
int GetNumElements() const;
|
||||
|
||||
/// Returns how many vertices allocated in this vertex buffer.
|
||||
int GetNumVertices() const;
|
||||
|
||||
/// Returns cuda memory. GL buffer will be mapped to cuda resource
|
||||
/// if necessary.
|
||||
float * BindCudaBuffer();
|
||||
|
||||
/// Returns the GL buffer object. If the buffer is mapped as a cuda
|
||||
/// resource, it will be unmapped back to GL.
|
||||
GLuint BindVBO(void *deviceContext = NULL);
|
||||
|
||||
protected:
|
||||
/// Constructor.
|
||||
CudaGLVertexBuffer(int numElements, int numVertices);
|
||||
|
||||
/// Allocates VBO for this buffer and register as a cuda resource.
|
||||
/// Returns true if success.
|
||||
bool allocate();
|
||||
|
||||
/// Acquire a cuda resource from GL.
|
||||
void map();
|
||||
|
||||
/// Release a cuda resource to GL.
|
||||
void unmap();
|
||||
|
||||
private:
|
||||
int _numElements;
|
||||
int _numVertices;
|
||||
GLuint _vbo;
|
||||
void *_devicePtr;
|
||||
struct cudaGraphicsResource *_cudaResource;
|
||||
};
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_OSD_CUDA_GL_VERTEX_BUFFER_H
|
||||
427
src/osd/opensubdiv/osd/cudaKernel.cu
Normal file
427
src/osd/opensubdiv/osd/cudaKernel.cu
Normal file
@@ -0,0 +1,427 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#define OSD_PATCH_BASIS_CUDA
|
||||
#include "../osd/patchBasisCommonTypes.h"
|
||||
#include "../osd/patchBasisCommon.h"
|
||||
#include "../osd/patchBasisCommonEval.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
template<int N> struct DeviceVertex {
|
||||
|
||||
float v[N];
|
||||
|
||||
__device__ void addWithWeight(DeviceVertex<N> const & src, float weight) {
|
||||
#pragma unroll
|
||||
for(int i = 0; i < N; ++i){
|
||||
v[i] += src.v[i] * weight;
|
||||
}
|
||||
}
|
||||
|
||||
__device__ void clear() {
|
||||
#pragma unroll
|
||||
for(int i = 0; i < N; ++i){
|
||||
v[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Specialize DeviceVertex for N=0 to avoid compile error:
|
||||
// "flexible array member in otherwise empty struct"
|
||||
template<> struct DeviceVertex<0> {
|
||||
__device__ void addWithWeight(DeviceVertex<0> &src, float weight) {}
|
||||
__device__ void clear() {}
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
__device__ void clear(float *dst, int count)
|
||||
{
|
||||
for(int i = 0; i < count; ++i) dst[i] = 0;
|
||||
}
|
||||
|
||||
__device__ void addWithWeight(float *dst, float const *src, float weight, int count)
|
||||
{
|
||||
for(int i = 0; i < count; ++i) dst[i] += src[i] * weight;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
template <int NUM_ELEMENTS> __global__ void
|
||||
computeStencils(float const * cvs, float * vbuffer,
|
||||
int const * sizes,
|
||||
int const * offsets,
|
||||
int const * indices,
|
||||
float const * weights,
|
||||
int start, int end) {
|
||||
|
||||
DeviceVertex<NUM_ELEMENTS> const * src =
|
||||
(DeviceVertex<NUM_ELEMENTS> const *)cvs;
|
||||
|
||||
DeviceVertex<NUM_ELEMENTS> * verts =
|
||||
(DeviceVertex<NUM_ELEMENTS> *)vbuffer;
|
||||
|
||||
int first = start + threadIdx.x + blockIdx.x*blockDim.x;
|
||||
|
||||
for (int i=first; i<end; i += blockDim.x * gridDim.x) {
|
||||
|
||||
int const * lindices = indices + offsets[i];
|
||||
float const * lweights = weights + offsets[i];
|
||||
|
||||
DeviceVertex<NUM_ELEMENTS> dst;
|
||||
dst.clear();
|
||||
|
||||
for (int j=0; j<sizes[i]; ++j) {
|
||||
dst.addWithWeight(src[lindices[j]], lweights[j]);
|
||||
}
|
||||
verts[i] = dst;
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void
|
||||
computeStencils(float const * cvs, float * dst,
|
||||
int length,
|
||||
int srcStride,
|
||||
int dstStride,
|
||||
int const * sizes,
|
||||
int const * offsets,
|
||||
int const * indices,
|
||||
float const * weights,
|
||||
int start, int end) {
|
||||
|
||||
int first = start + threadIdx.x + blockIdx.x*blockDim.x;
|
||||
|
||||
for (int i=first; i<end; i += blockDim.x * gridDim.x) {
|
||||
|
||||
int const * lindices = indices + offsets[i];
|
||||
float const * lweights = weights + offsets[i];
|
||||
|
||||
float * dstVert = dst + i*dstStride;
|
||||
clear(dstVert, length);
|
||||
|
||||
for (int j=0; j<sizes[i]; ++j) {
|
||||
|
||||
float const * srcVert = cvs + lindices[j]*srcStride;
|
||||
|
||||
addWithWeight(dstVert, srcVert, lweights[j], length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define USE_NVIDIA_OPTIMIZATION
|
||||
#ifdef USE_NVIDIA_OPTIMIZATION
|
||||
|
||||
template< int NUM_ELEMENTS, int NUM_THREADS_PER_BLOCK >
|
||||
__global__ void computeStencilsNv(float const *__restrict cvs,
|
||||
float * vbuffer,
|
||||
int const *__restrict sizes,
|
||||
int const *__restrict offsets,
|
||||
int const *__restrict indices,
|
||||
float const *__restrict weights,
|
||||
int start,
|
||||
int end)
|
||||
{
|
||||
// Shared memory to stage indices/weights.
|
||||
__shared__ int smem_indices_buffer[NUM_THREADS_PER_BLOCK];
|
||||
__shared__ float smem_weights_buffer[NUM_THREADS_PER_BLOCK];
|
||||
|
||||
// The size of a single warp.
|
||||
const int WARP_SIZE = 32;
|
||||
// The number of warps per block.
|
||||
const int NUM_WARPS_PER_BLOCK = NUM_THREADS_PER_BLOCK / WARP_SIZE;
|
||||
// The number of outputs computed by a single warp.
|
||||
const int NUM_OUTPUTS_PER_WARP = WARP_SIZE / NUM_ELEMENTS;
|
||||
// The number of outputs computed by a block of threads.
|
||||
const int NUM_OUTPUTS_PER_BLOCK = NUM_OUTPUTS_PER_WARP*NUM_WARPS_PER_BLOCK;
|
||||
// The number of active threads in a warp.
|
||||
const int NUM_ACTIVE_THREADS_PER_WARP = NUM_OUTPUTS_PER_WARP * NUM_ELEMENTS;
|
||||
|
||||
// The number of the warp inside the block.
|
||||
const int warpId = threadIdx.x / WARP_SIZE;
|
||||
const int laneId = threadIdx.x % WARP_SIZE;
|
||||
|
||||
// We use NUM_ELEMENTS threads per output. Find which output/element a thread works on.
|
||||
int outputIdx = warpId*NUM_OUTPUTS_PER_WARP + laneId/NUM_ELEMENTS, elementIdx = laneId%NUM_ELEMENTS;
|
||||
|
||||
// Each output corresponds to a section of shared memory.
|
||||
volatile int *smem_indices = &smem_indices_buffer[warpId*WARP_SIZE + (laneId/NUM_ELEMENTS)*NUM_ELEMENTS];
|
||||
volatile float *smem_weights = &smem_weights_buffer[warpId*WARP_SIZE + (laneId/NUM_ELEMENTS)*NUM_ELEMENTS];
|
||||
|
||||
// Disable threads that have nothing to do inside the warp.
|
||||
int i = end;
|
||||
if( laneId < NUM_ACTIVE_THREADS_PER_WARP )
|
||||
i = start + blockIdx.x*NUM_OUTPUTS_PER_BLOCK + outputIdx;
|
||||
|
||||
// Iterate over the vertices.
|
||||
for( ; i < end ; i += gridDim.x*NUM_OUTPUTS_PER_BLOCK )
|
||||
{
|
||||
// Each thread computes an element of the final vertex.
|
||||
float x = 0.f;
|
||||
|
||||
// Load the offset and the size for each vertex. We have NUM_THREADS_PER_VERTEX threads loading the same value.
|
||||
const int offset_i = offsets[i], size_i = sizes[i];
|
||||
|
||||
// Iterate over the stencil.
|
||||
for( int j = offset_i, j_end = offset_i+size_i ; j < j_end ; )
|
||||
{
|
||||
int j_it = j + elementIdx;
|
||||
|
||||
// Load some indices and some weights. The transaction is coalesced.
|
||||
smem_indices[elementIdx] = j_it < j_end ? indices[j_it] : 0;
|
||||
smem_weights[elementIdx] = j_it < j_end ? weights[j_it] : 0.f;
|
||||
|
||||
// Thread now collaborates to load the vertices.
|
||||
#pragma unroll
|
||||
for( int k = 0 ; k < NUM_ELEMENTS ; ++k, ++j )
|
||||
if( j < j_end )
|
||||
x += smem_weights[k] * cvs[smem_indices[k]*NUM_ELEMENTS + elementIdx];
|
||||
}
|
||||
|
||||
// Store the vertex.
|
||||
vbuffer[NUM_ELEMENTS*i + elementIdx] = x;
|
||||
}
|
||||
}
|
||||
|
||||
template< int NUM_THREADS_PER_BLOCK >
|
||||
__global__ void computeStencilsNv_v4(float const *__restrict cvs,
|
||||
float * vbuffer,
|
||||
int const *__restrict sizes,
|
||||
int const *__restrict offsets,
|
||||
int const *__restrict indices,
|
||||
float const *__restrict weights,
|
||||
int start,
|
||||
int end)
|
||||
{
|
||||
// Iterate over the vertices.
|
||||
for( int i = start + blockIdx.x*NUM_THREADS_PER_BLOCK + threadIdx.x ; i < end ; i += gridDim.x*NUM_THREADS_PER_BLOCK )
|
||||
{
|
||||
// Each thread computes an element of the final vertex.
|
||||
float4 x = make_float4(0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
// Iterate over the stencil.
|
||||
for( int j = offsets[i], j_end = offsets[i]+sizes[i] ; j < j_end ; ++j )
|
||||
{
|
||||
float w = weights[j];
|
||||
float4 tmp = reinterpret_cast<const float4 *>(cvs)[indices[j]];
|
||||
x.x += w*tmp.x;
|
||||
x.y += w*tmp.y;
|
||||
x.z += w*tmp.z;
|
||||
x.w += w*tmp.w;
|
||||
}
|
||||
|
||||
// Store the vertex.
|
||||
reinterpret_cast<float4*>(vbuffer)[i] = x;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // USE_NVIDIA_OPTIMIZATION
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
__global__ void
|
||||
computePatches(const float *src, float *dst,
|
||||
float *dstDu, float *dstDv,
|
||||
float *dstDuu, float *dstDuv, float *dstDvv,
|
||||
int length, int srcStride, int dstStride,
|
||||
int dstDuStride, int dstDvStride,
|
||||
int dstDuuStride, int dstDuvStride, int dstDvvStride,
|
||||
int numPatchCoords, const OsdPatchCoord *patchCoords,
|
||||
const OsdPatchArray *patchArrayBuffer,
|
||||
const int *patchIndexBuffer,
|
||||
const OsdPatchParam *patchParamBuffer) {
|
||||
|
||||
int first = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
|
||||
// PERFORMANCE: not yet optimized
|
||||
|
||||
for (int i = first; i < numPatchCoords; i += blockDim.x * gridDim.x) {
|
||||
|
||||
OsdPatchCoord const &coord = patchCoords[i];
|
||||
int arrayIndex = coord.arrayIndex;
|
||||
int patchIndex = coord.patchIndex;
|
||||
|
||||
OsdPatchArray const &array = patchArrayBuffer[arrayIndex];
|
||||
OsdPatchParam const ¶m = patchParamBuffer[patchIndex];
|
||||
|
||||
int patchType = OsdPatchParamIsRegular(param)
|
||||
? array.regDesc : array.desc;
|
||||
|
||||
float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
|
||||
int nPoints = OsdEvaluatePatchBasis(patchType, param,
|
||||
coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
|
||||
|
||||
int indexBase = array.indexBase + array.stride *
|
||||
(patchIndex - array.primitiveIdBase);
|
||||
|
||||
const int *cvs = patchIndexBuffer + indexBase;
|
||||
|
||||
float * dstVert = dst + i * dstStride;
|
||||
clear(dstVert, length);
|
||||
for (int j = 0; j < nPoints; ++j) {
|
||||
const float * srcVert = src + cvs[j] * srcStride;
|
||||
addWithWeight(dstVert, srcVert, wP[j], length);
|
||||
}
|
||||
if (dstDu) {
|
||||
float *d = dstDu + i * dstDuStride;
|
||||
clear(d, length);
|
||||
for (int j = 0; j < nPoints; ++j) {
|
||||
const float * srcVert = src + cvs[j] * srcStride;
|
||||
addWithWeight(d, srcVert, wDu[j], length);
|
||||
}
|
||||
}
|
||||
if (dstDv) {
|
||||
float *d = dstDv + i * dstDvStride;
|
||||
clear(d, length);
|
||||
for (int j = 0; j < nPoints; ++j) {
|
||||
const float * srcVert = src + cvs[j] * srcStride;
|
||||
addWithWeight(d, srcVert, wDv[j], length);
|
||||
}
|
||||
}
|
||||
if (dstDuu) {
|
||||
float *d = dstDuu + i * dstDuuStride;
|
||||
clear(d, length);
|
||||
for (int j = 0; j < nPoints; ++j) {
|
||||
const float * srcVert = src + cvs[j] * srcStride;
|
||||
addWithWeight(d, srcVert, wDuu[j], length);
|
||||
}
|
||||
}
|
||||
if (dstDuv) {
|
||||
float *d = dstDuv + i * dstDuvStride;
|
||||
clear(d, length);
|
||||
for (int j = 0; j < nPoints; ++j) {
|
||||
const float * srcVert = src + cvs[j] * srcStride;
|
||||
addWithWeight(d, srcVert, wDuv[j], length);
|
||||
}
|
||||
}
|
||||
if (dstDvv) {
|
||||
float *d = dstDvv + i * dstDvvStride;
|
||||
clear(d, length);
|
||||
for (int j = 0; j < nPoints; ++j) {
|
||||
const float * srcVert = src + cvs[j] * srcStride;
|
||||
addWithWeight(d, srcVert, wDvv[j], length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#define OPT_KERNEL(NUM_ELEMENTS, KERNEL, X, Y, ARG) \
|
||||
if (length==NUM_ELEMENTS && srcStride==length && dstStride==length) { \
|
||||
KERNEL<NUM_ELEMENTS><<<X,Y>>>ARG; \
|
||||
return; \
|
||||
}
|
||||
|
||||
#ifdef USE_NVIDIA_OPTIMIZATION
|
||||
#define OPT_KERNEL_NVIDIA(NUM_ELEMENTS, KERNEL, X, Y, ARG) \
|
||||
if (length==NUM_ELEMENTS && srcStride==length && dstStride==length) { \
|
||||
int gridDim = min(X, (end-start+Y-1)/Y); \
|
||||
KERNEL<NUM_ELEMENTS, Y><<<gridDim, Y>>>ARG; \
|
||||
return; \
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
void CudaEvalStencils(
|
||||
const float *src, float *dst,
|
||||
int length, int srcStride, int dstStride,
|
||||
const int * sizes, const int * offsets, const int * indices,
|
||||
const float * weights,
|
||||
int start, int end) {
|
||||
if (length == 0 || srcStride == 0 || dstStride == 0 || (end <= start)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USE_NVIDIA_OPTIMIZATION
|
||||
OPT_KERNEL_NVIDIA(3, computeStencilsNv, 2048, 256,
|
||||
(src, dst, sizes, offsets, indices, weights, start, end));
|
||||
//OPT_KERNEL_NVIDIA(4, computeStencilsNv, 2048, 256,
|
||||
// (cvs, dst, sizes, offsets, indices, weights, start, end));
|
||||
if (length == 4 && srcStride == length && dstStride == length) {
|
||||
int gridDim = min(2048, (end-start+256-1)/256);
|
||||
computeStencilsNv_v4<256><<<gridDim, 256>>>(
|
||||
src, dst, sizes, offsets, indices, weights, start, end);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
OPT_KERNEL(3, computeStencils, 512, 32,
|
||||
(src, dst, sizes, offsets, indices, weights, start, end));
|
||||
OPT_KERNEL(4, computeStencils, 512, 32,
|
||||
(src, dst, sizes, offsets, indices, weights, start, end));
|
||||
#endif
|
||||
|
||||
// generic case (slow)
|
||||
computeStencils <<<512, 32>>>(
|
||||
src, dst, length, srcStride, dstStride,
|
||||
sizes, offsets, indices, weights, start, end);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void CudaEvalPatches(
|
||||
const float *src, float *dst,
|
||||
int length, int srcStride, int dstStride,
|
||||
int numPatchCoords, const OsdPatchCoord *patchCoords,
|
||||
const OsdPatchArray *patchArrayBuffer,
|
||||
const int *patchIndexBuffer,
|
||||
const OsdPatchParam *patchParamBuffer) {
|
||||
|
||||
// PERFORMANCE: not optimized at all
|
||||
|
||||
computePatches <<<512, 32>>>(
|
||||
src, dst, NULL, NULL, NULL, NULL, NULL,
|
||||
length, srcStride, dstStride, 0, 0, 0, 0, 0,
|
||||
numPatchCoords, patchCoords,
|
||||
patchArrayBuffer, patchIndexBuffer, patchParamBuffer);
|
||||
}
|
||||
|
||||
void CudaEvalPatchesWithDerivatives(
|
||||
const float *src, float *dst,
|
||||
float *dstDu, float *dstDv,
|
||||
float *dstDuu, float *dstDuv, float *dstDvv,
|
||||
int length, int srcStride, int dstStride,
|
||||
int dstDuStride, int dstDvStride,
|
||||
int dstDuuStride, int dstDuvStride, int dstDvvStride,
|
||||
int numPatchCoords, const OsdPatchCoord *patchCoords,
|
||||
const OsdPatchArray *patchArrayBuffer,
|
||||
const int *patchIndexBuffer,
|
||||
const OsdPatchParam *patchParamBuffer) {
|
||||
|
||||
// PERFORMANCE: not optimized at all
|
||||
|
||||
computePatches <<<512, 32>>>(
|
||||
src, dst, dstDu, dstDv, dstDuu, dstDuv, dstDvv,
|
||||
length, srcStride, dstStride,
|
||||
dstDuStride, dstDvStride, dstDuuStride, dstDuvStride, dstDvvStride,
|
||||
numPatchCoords, patchCoords,
|
||||
patchArrayBuffer, patchIndexBuffer, patchParamBuffer);
|
||||
}
|
||||
|
||||
} /* extern "C" */
|
||||
169
src/osd/opensubdiv/osd/cudaPatchTable.cpp
Normal file
169
src/osd/opensubdiv/osd/cudaPatchTable.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#include "../osd/cudaPatchTable.h"
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#include "../far/patchTable.h"
|
||||
#include "../osd/cpuPatchTable.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Osd {
|
||||
|
||||
CudaPatchTable::CudaPatchTable() :
|
||||
_patchArrays(NULL), _indexBuffer(NULL), _patchParamBuffer(NULL),
|
||||
_varyingPatchArrays(NULL), _varyingIndexBuffer(NULL) {
|
||||
}
|
||||
|
||||
CudaPatchTable::~CudaPatchTable() {
|
||||
if (_patchArrays) cudaFree(_patchArrays);
|
||||
if (_indexBuffer) cudaFree(_indexBuffer);
|
||||
if (_patchParamBuffer) cudaFree(_patchParamBuffer);
|
||||
if (_varyingPatchArrays) cudaFree(_varyingPatchArrays);
|
||||
if (_varyingIndexBuffer) cudaFree(_varyingIndexBuffer);
|
||||
for (int fvc=0; fvc<(int)_fvarPatchArrays.size(); ++fvc) {
|
||||
if (_fvarPatchArrays[fvc]) cudaFree(_fvarPatchArrays[fvc]);
|
||||
}
|
||||
for (int fvc=0; fvc<(int)_fvarIndexBuffers.size(); ++fvc) {
|
||||
if (_fvarIndexBuffers[fvc]) cudaFree(_fvarIndexBuffers[fvc]);
|
||||
}
|
||||
for (int fvc=0; fvc<(int)_fvarParamBuffers.size(); ++fvc) {
|
||||
if (_fvarParamBuffers[fvc]) cudaFree(_fvarParamBuffers[fvc]);
|
||||
}
|
||||
}
|
||||
|
||||
CudaPatchTable *
|
||||
CudaPatchTable::Create(Far::PatchTable const *farPatchTable,
|
||||
void * /*deviceContext*/) {
|
||||
CudaPatchTable *instance = new CudaPatchTable();
|
||||
if (instance->allocate(farPatchTable)) return instance;
|
||||
delete instance;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
CudaPatchTable::allocate(Far::PatchTable const *farPatchTable) {
|
||||
CpuPatchTable patchTable(farPatchTable);
|
||||
|
||||
size_t numPatchArrays = patchTable.GetNumPatchArrays();
|
||||
size_t indexSize = patchTable.GetPatchIndexSize();
|
||||
size_t patchParamSize = patchTable.GetPatchParamSize();
|
||||
|
||||
cudaError_t err;
|
||||
err = cudaMalloc(&_patchArrays, numPatchArrays * sizeof(Osd::PatchArray));
|
||||
if (err != cudaSuccess) return false;
|
||||
|
||||
err = cudaMalloc(&_indexBuffer, indexSize * sizeof(int));
|
||||
if (err != cudaSuccess) return false;
|
||||
|
||||
err = cudaMalloc(&_patchParamBuffer, patchParamSize * sizeof(Osd::PatchParam));
|
||||
if (err != cudaSuccess) return false;
|
||||
|
||||
err = cudaMalloc(&_varyingPatchArrays, numPatchArrays * sizeof(Osd::PatchArray));
|
||||
if (err != cudaSuccess) return false;
|
||||
|
||||
size_t varyingIndexSize = patchTable.GetVaryingPatchIndexSize();
|
||||
err = cudaMalloc(&_varyingIndexBuffer, varyingIndexSize * sizeof(int));
|
||||
if (err != cudaSuccess) return false;
|
||||
|
||||
size_t numFVarChannels = patchTable.GetNumFVarChannels();
|
||||
_fvarPatchArrays.resize(numFVarChannels, 0);
|
||||
_fvarIndexBuffers.resize(numFVarChannels, 0);
|
||||
_fvarParamBuffers.resize(numFVarChannels, 0);
|
||||
for (int fvc=0; fvc<(int)numFVarChannels; ++fvc) {
|
||||
err = cudaMalloc(&_fvarPatchArrays[fvc], numPatchArrays * sizeof(Osd::PatchArray));
|
||||
if (err != cudaSuccess) return false;
|
||||
|
||||
err = cudaMemcpy(_fvarPatchArrays[fvc],
|
||||
patchTable.GetFVarPatchArrayBuffer(fvc),
|
||||
numPatchArrays * sizeof(Osd::PatchArray),
|
||||
cudaMemcpyHostToDevice);
|
||||
if (err != cudaSuccess) return false;
|
||||
|
||||
size_t fvarIndexSize = patchTable.GetFVarPatchIndexSize(fvc);
|
||||
err = cudaMalloc(&_fvarIndexBuffers[fvc], fvarIndexSize * sizeof(int));
|
||||
if (err != cudaSuccess) return false;
|
||||
|
||||
err = cudaMemcpy(_fvarIndexBuffers[fvc],
|
||||
patchTable.GetFVarPatchIndexBuffer(fvc),
|
||||
fvarIndexSize * sizeof(int),
|
||||
cudaMemcpyHostToDevice);
|
||||
if (err != cudaSuccess) return false;
|
||||
|
||||
size_t fvarParamSize = patchTable.GetFVarPatchParamSize(fvc);
|
||||
err = cudaMalloc(&_fvarParamBuffers[fvc], fvarParamSize * sizeof(Osd::PatchParam));
|
||||
if (err != cudaSuccess) return false;
|
||||
|
||||
err = cudaMemcpy(_fvarParamBuffers[fvc],
|
||||
patchTable.GetFVarPatchParamBuffer(fvc),
|
||||
patchParamSize * sizeof(PatchParam),
|
||||
cudaMemcpyHostToDevice);
|
||||
if (err != cudaSuccess) return false;
|
||||
}
|
||||
|
||||
// copy patch array
|
||||
err = cudaMemcpy(_patchArrays,
|
||||
patchTable.GetPatchArrayBuffer(),
|
||||
numPatchArrays * sizeof(Osd::PatchArray),
|
||||
cudaMemcpyHostToDevice);
|
||||
if (err != cudaSuccess) return false;
|
||||
|
||||
// copy index buffer
|
||||
err = cudaMemcpy(_indexBuffer,
|
||||
patchTable.GetPatchIndexBuffer(),
|
||||
indexSize * sizeof(int),
|
||||
cudaMemcpyHostToDevice);
|
||||
if (err != cudaSuccess) return false;
|
||||
|
||||
// patch param buffer
|
||||
err = cudaMemcpy(_patchParamBuffer,
|
||||
patchTable.GetPatchParamBuffer(),
|
||||
patchParamSize * sizeof(Osd::PatchParam),
|
||||
cudaMemcpyHostToDevice);
|
||||
if (err != cudaSuccess) return false;
|
||||
|
||||
// copy varying patch arrays and index buffer
|
||||
err = cudaMemcpy(_varyingPatchArrays,
|
||||
patchTable.GetVaryingPatchArrayBuffer(),
|
||||
numPatchArrays * sizeof(Osd::PatchArray),
|
||||
cudaMemcpyHostToDevice);
|
||||
if (err != cudaSuccess) return false;
|
||||
err = cudaMemcpy(_varyingIndexBuffer,
|
||||
patchTable.GetVaryingPatchIndexBuffer(),
|
||||
varyingIndexSize * sizeof(int),
|
||||
cudaMemcpyHostToDevice);
|
||||
if (err != cudaSuccess) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
119
src/osd/opensubdiv/osd/cudaPatchTable.h
Normal file
119
src/osd/opensubdiv/osd/cudaPatchTable.h
Normal file
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_OSD_CUDA_PATCH_TABLE_H
|
||||
#define OPENSUBDIV3_OSD_CUDA_PATCH_TABLE_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../osd/nonCopyable.h"
|
||||
#include "../osd/types.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far{
|
||||
class PatchTable;
|
||||
};
|
||||
|
||||
namespace Osd {
|
||||
|
||||
/// \brief CUDA patch table
|
||||
///
|
||||
/// This class is a cuda buffer representation of Far::PatchTable.
|
||||
///
|
||||
/// CudaEvaluator consumes this table to evaluate on the patches.
|
||||
///
|
||||
///
|
||||
class CudaPatchTable : private NonCopyable<CudaPatchTable> {
|
||||
public:
|
||||
/// Creator. Returns NULL if error
|
||||
static CudaPatchTable *Create(Far::PatchTable const *patchTable,
|
||||
void *deviceContext = NULL);
|
||||
/// Destructor
|
||||
~CudaPatchTable();
|
||||
|
||||
/// Returns the cuda memory of the array of Osd::PatchArray buffer
|
||||
void *GetPatchArrayBuffer() const { return _patchArrays; }
|
||||
|
||||
/// Returns the cuda memory of the patch control vertices
|
||||
void *GetPatchIndexBuffer() const { return _indexBuffer; }
|
||||
|
||||
/// Returns the cuda memory of the array of Osd::PatchParam buffer
|
||||
void *GetPatchParamBuffer() const { return _patchParamBuffer; }
|
||||
|
||||
/// Returns the cuda memory of the array of Osd::PatchArray buffer
|
||||
void *GetVaryingPatchArrayBuffer() const {
|
||||
return _varyingPatchArrays;
|
||||
}
|
||||
/// Returns the cuda memory of the array of varying control vertices
|
||||
void *GetVaryingPatchIndexBuffer() const {
|
||||
return _varyingIndexBuffer;
|
||||
}
|
||||
|
||||
/// Returns the number of face-varying channels buffers
|
||||
int GetNumFVarChannels() const { return (int)_fvarPatchArrays.size(); }
|
||||
|
||||
/// Returns the cuda memory of the array of Osd::PatchArray buffer
|
||||
void *GetFVarPatchArrayBuffer(int fvarChannel) const {
|
||||
return _fvarPatchArrays[fvarChannel];
|
||||
}
|
||||
|
||||
/// Returns the cuda memory of the array of face-varying control vertices
|
||||
void *GetFVarPatchIndexBuffer(int fvarChannel = 0) const {
|
||||
return _fvarIndexBuffers[fvarChannel];
|
||||
}
|
||||
|
||||
/// Returns the cuda memory of the array of face-varying param
|
||||
void *GetFVarPatchParamBuffer(int fvarChannel = 0) const {
|
||||
return _fvarParamBuffers[fvarChannel];
|
||||
}
|
||||
|
||||
protected:
|
||||
CudaPatchTable();
|
||||
|
||||
bool allocate(Far::PatchTable const *patchTable);
|
||||
|
||||
void *_patchArrays;
|
||||
void *_indexBuffer;
|
||||
void *_patchParamBuffer;
|
||||
|
||||
void *_varyingPatchArrays;
|
||||
void *_varyingIndexBuffer;
|
||||
|
||||
std::vector<void *> _fvarPatchArrays;
|
||||
std::vector<void *> _fvarIndexBuffers;
|
||||
std::vector<void *> _fvarParamBuffers;
|
||||
};
|
||||
|
||||
} // end namespace Osd
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_OSD_CUDA_PATCH_TABLE_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user