Merge remote-tracking branch 'upstream/dev' into dev

This commit is contained in:
asluk 2015-04-23 21:23:29 -07:00
commit ed07ed6a8f
117 changed files with 6933 additions and 10585 deletions

View File

@ -682,6 +682,10 @@ endmacro()
#-------------------------------------------------------------------------------
# Build targets
if (NOT NO_TEST)
enable_testing()
endif()
add_subdirectory(opensubdiv)
if (NOT ANDROID AND NOT IOS) # XXXdyu

126
README.md
View File

@ -12,131 +12,19 @@ For more details about OpenSubdiv, see [Pixar Graphics Technologies](http://grap
We have adopted the git flow branching model. It is not necessary to use the git-flow extensions, though you may find them useful! But it will be helpful to read about the git flow branching model in order to understand the organization of branches and tags that you will find in the repository.
* [Getting Started](http://graphics.pixar.com/opensubdiv/docs/getting_started.html)
* [git-flow extensions](https://github.com/nvie/gitflow)
## Quickstart
Basic instructions to get started with the code.
* Clone
* Make a subdirectory "build" and cd into it
* Run cmake .. followed up with your build tool of choice (make or an IDE).
### Dependencies
Cmake will adapt the build based on which dependencies have been successfully discovered and will disable certain features and code examples accordingly.
Please refer to the documentation of each of the dependency packages for specific build and installation instructions.
Required:
* [cmake](http://www.cmake.org/cmake/resources/software.html)
Optional:
* [GLEW](http://sourceforge.net/projects/glew/) (Windows/Linux only)
* [CUDA](http://developer.nvidia.com/category/zone/cuda-zone)
* [TBB] (https://www.threadingbuildingblocks.org/)
* [OpenCL](http://www.khronos.org/opencl/)
* [GLFW](http://www.glfw.org/)
* [Ptex](https://github.com/wdas/ptex)
* [Zlib](http://www.zlib.net) (required for Ptex under Windows)
* [Maya SDK](http://www.autodesk.com/maya/) (sample code for Maya viewport 2.0 primitive)
* [DX11 SDK](http://www.microsoft.com/en-us/download/details.aspx?id=6812)
* [Docutils](http://docutils.sourceforge.net/)
* [Doxygen](file://www.doxygen.org/)
### Useful cmake options and environment variables
````
-DCMAKE_BUILD_TYPE=[Debug|Release]
-DCMAKE_INSTALL_PREFIX=[base path to install OpenSubdiv (default: Current directory)]
-DCMAKE_LIBDIR_BASE=[library directory basename (default: lib)]
-DCUDA_TOOLKIT_ROOT_DIR=[path to CUDA]
-DPTEX_LOCATION=[path to Ptex]
-DGLEW_LOCATION=[path to GLEW]
-DGLFW_LOCATION=[path to GLFW]
-DMAYA_LOCATION=[path to Maya]
-DNO_LIB=1 // disable the opensubdiv libs build (caveat emptor)
-DNO_EXAMPLES=1 // disable examples build
-DNO_TUTORIALS=1 // disable tutorials build
-DNO_REGRESSION=1 // disable regression tests build
-DNO_MAYA=1 // disable Maya plugin build
-DNO_PTEX=1 // disable PTex support
-DNO_DOC=1 // disable documentation build
-DNO_OMP=1 // disable OpenMP
-DNO_TBB=1 // disable TBB
-DNO_CUDA=1 // disable CUDA
-DNO_OPENCL=1 // disable OpenCL
-DNO_OPENGL=1 // disable OpenGL
-DNO_CLEW=1 // disable CLEW wrapper library
````
The paths to Maya, Ptex, GLFW, and GLEW can also be specified through the
following environment variables: `MAYA_LOCATION`, `PTEX_LOCATION`, `GLFW_LOCATION`,
and `GLEW_LOCATION`.
### Build instructions (Linux/OSX/Windows):
__Clone the repository:__
From the GitShell, Cygwin or the CLI :
````
git clone git://github.com/PixarAnimationStudios/OpenSubdiv.git
````
Alternatively, on Windows, GIT also provides a GUI to perform this operation.
__Generate Makefiles:__
Assuming that we want the binaries installed into a "build" directory at the root of the OpenSubdiv tree :
````
cd OpenSubdiv
mkdir build
cd build
````
Here is an example cmake configuration script for a full typical windows-based build that can be run in GitShell :
````
#/bin/tcsh
# Replace the ".." with a full path to the root of the OpenSubdiv source tree if necessary
"c:/Program Files (x86)/CMake 2.8/bin/cmake.exe" \
-G "Visual Studio 10 Win64" \
-D "GLEW_LOCATION:string=c:/Program Files/glew-1.9.0" \
-D "GLFW_LOCATION:string=c:/Program Files/glfw-2.7.7.bin.WIN64" \
-D "OPENCL_INCLUDE_DIRS:string=c:/ProgramData/NVIDIA Corporation/NVIDIA GPU Computing SDK 4.2/OpenCL/common/inc" \
-D "_OPENCL_CPP_INCLUDE_DIRS:string=c:/ProgramData/NVIDIA Corporation/NVIDIA GPU Computing SDK 4.2/OpenCL/common/inc" \
-D "OPENCL_LIBRARIES:string=c:/ProgramData/NVIDIA Corporation/NVIDIA GPU Computing SDK 4.2/OpenCL/common/lib/x64/OpenCL.lib" \
-D "MAYA_LOCATION:string=c:/Program Files/Autodesk/Maya2013.5" \
-D "PTEX_LOCATION:string=c:/Users/opensubdiv/demo/src/ptex/x64" \
..
# copy Ptex dependencies (Windows only)
mkdir -p bin/{Debug,Release}
\cp -f c:/Users/opensubdiv/demo/src/zlib-1.2.7/contrib/vstudio/vc10/x64/ZlibDllRelease/zlibwapi.dll bin/Debug/
\cp -f c:/Users/opensubdiv/demo/src/zlib-1.2.7/contrib/vstudio/vc10/x64/ZlibDllRelease/zlibwapi.dll bin/Release/
\cp -f c:/Users/opensubdiv/demo/src/ptex/x64/lib/Ptex.dll bin/Debug/
\cp -f c:/Users/opensubdiv/demo/src/ptex/x64/lib/Ptex.dll bin/Release/
````
Alternatively, you can use the cmake GUI or run the commands from the CLI.
Note : the OSX generator in cmake for Xcode is -G "Xcode". However we recommend against using it, as we have noticed problems with dependency tracking.
__Build the project:__
CMake provides a cross-platform command-line build:
````
cmake --build . --target install --config Release
````
Windows : launch VC++ with the solution generated by cmake in your build directory.
OSX : with the Xcode generator, run xcodebuild in your build directory, otherwise make.
*Nix : run make in your build directory
Additional detailed instructions can be found in the documentation:
* [Getting Started](http://graphics.pixar.com/opensubdiv/docs/getting_started.html)
* [Building OpenSubdiv](http://graphics.pixar.com/opensubdiv/docs/cmake_build.html)
## Standalone viewers

View File

@ -32,7 +32,6 @@
find_path( GLFW_INCLUDE_DIR
NAMES
GL/glfw.h
GLFW/glfw3.h
HINTS
"${GLFW_LOCATION}/include"
@ -49,6 +48,31 @@ find_path( GLFW_INCLUDE_DIR
/usr/local/include
/usr/include/GL
/usr/include
DOC
"The directory where GLFW/glfw3.h resides"
)
#
# XXX: Do we still need to search for GL/glfw.h?
#
find_path( GLFW_INCLUDE_DIR
NAMES
GL/glfw.h
HINTS
"${GLFW_LOCATION}/include"
"$ENV{GLFW_LOCATION}/include"
PATHS
"$ENV{PROGRAMFILES}/GLFW/include"
"${OPENGL_INCLUDE_DIR}"
/usr/openwin/share/include
/usr/openwin/include
/usr/X11R6/include
/usr/include/X11
/opt/graphics/OpenGL/include
/opt/graphics/OpenGL/contrib/libglfw
/usr/local/include
/usr/include/GL
/usr/include
DOC
"The directory where GL/glfw.h resides"
)

View File

@ -122,7 +122,7 @@ Since a client' mesh representation knows best how to identify the topological
neighborhoods required, no generic implementation would provide the most
direct means of conversion possible, and so we rely on specialization. For
situations where mesh data is not defined in a boundary representation, a
simple container for raw mesh data is provided (TopologyDescriptro) along
simple container for raw mesh data is provided (TopologyDescriptor) along
with a Factory specialized to construct TopologyRefiners from it.
So there are two ways to create TopologyRefiners:

View File

@ -40,6 +40,7 @@ if (NOT NO_OPENGL)
add_subdirectory(glShareTopology)
add_subdirectory(glFVarViewer)
add_subdirectory(glStencilViewer)
add_subdirectory(glImaging)
if (CMAKE_COMPILER_IS_CLANGCC)
# This code is intended for debugging only

View File

@ -24,57 +24,25 @@
#include "patchColors.h"
static float _colors[5][7][4] = {{{1.0f, 1.0f, 1.0f, 1.0f}, // regular
{1.0f, 0.5f, 0.5f, 1.0f}, // single crease
{0.8f, 0.0f, 0.0f, 1.0f}, // boundary
{0.0f, 1.0f, 0.0f, 1.0f}, // corner
{1.0f, 1.0f, 0.0f, 1.0f}, // gregory
{1.0f, 0.5f, 0.0f, 1.0f}, // gregory boundary
{1.0f, 0.7f, 0.3f, 1.0f}}, // gregory basis
{{0.0f, 1.0f, 1.0f, 1.0f}, // regular pattern 0
{0.0f, 0.5f, 1.0f, 1.0f}, // regular pattern 1
{0.0f, 0.5f, 0.5f, 1.0f}, // regular pattern 2
{0.5f, 0.0f, 1.0f, 1.0f}, // regular pattern 3
{1.0f, 0.5f, 1.0f, 1.0f}}, // regular pattern 4
{{1.0f, 0.70f, 0.6f, 1.0f}, // single crease pattern 0
{1.0f, 0.65f, 0.6f, 1.0f}, // single crease pattern 1
{1.0f, 0.60f, 0.6f, 1.0f}, // single crease pattern 2
{1.0f, 0.55f, 0.6f, 1.0f}, // single crease pattern 3
{1.0f, 0.50f, 0.6f, 1.0f}}, // single crease pattern 4
{{0.0f, 0.0f, 0.75f, 1.0f}, // boundary pattern 0
{0.0f, 0.2f, 0.75f, 1.0f}, // boundary pattern 1
{0.0f, 0.4f, 0.75f, 1.0f}, // boundary pattern 2
{0.0f, 0.6f, 0.75f, 1.0f}, // boundary pattern 3
{0.0f, 0.8f, 0.75f, 1.0f}}, // boundary pattern 4
{{0.25f, 0.25f, 0.25f, 1.0f}, // corner pattern 0
{0.25f, 0.25f, 0.25f, 1.0f}, // corner pattern 1
{0.25f, 0.25f, 0.25f, 1.0f}, // corner pattern 2
{0.25f, 0.25f, 0.25f, 1.0f}, // corner pattern 3
{0.25f, 0.25f, 0.25f, 1.0f}}}; // corner pattern 4
static float _colors[7][4] = {{1.0f, 1.0f, 1.0f, 1.0f}, // regular
{1.0f, 0.5f, 0.5f, 1.0f}, // single crease
{0.8f, 0.0f, 0.0f, 1.0f}, // boundary
{0.0f, 1.0f, 0.0f, 1.0f}, // corner
{1.0f, 1.0f, 0.0f, 1.0f}, // gregory
{1.0f, 0.5f, 0.0f, 1.0f}, // gregory boundary
{1.0f, 0.7f, 0.3f, 1.0f}}; // gregory basis
typedef OpenSubdiv::Far::PatchDescriptor Descriptor;
float const *
getAdaptivePatchColor(Descriptor const & desc) {
if (desc.GetPattern()==Descriptor::NON_TRANSITION) {
return _colors[0][(int)(desc.GetType()-Descriptor::REGULAR)];
} else {
return _colors[(int)(desc.GetType()-Descriptor::REGULAR)+1][(int)desc.GetPattern()-1];
}
return _colors[(int)(desc.GetType()-Descriptor::REGULAR)];
}
float const *
getAdaptivePatchColor(OpenSubdiv::Osd::DrawContext::PatchDescriptor const & desc) {
if (desc.GetPattern()==Descriptor::NON_TRANSITION) {
return _colors[0][(int)(desc.GetType()-Descriptor::REGULAR)];
} else {
return _colors[(int)(desc.GetType()-Descriptor::REGULAR)+1][(int)desc.GetPattern()-1];
}
return _colors[(int)(desc.GetType()-Descriptor::REGULAR)];
}

View File

@ -832,7 +832,7 @@ display() {
#endif
// patch drawing
int patchCount[12][6][4]; // [Type][Pattern][Rotation] (see far/patchTables.h)
int patchCount[12]; // [Type] (see far/patchTables.h)
int numTotalPatches = 0;
int numDrawCalls = 0;
@ -841,13 +841,8 @@ display() {
OpenSubdiv::Osd::DrawContext::PatchDescriptor desc = patch.GetDescriptor();
OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType();
int patchPattern = desc.GetPattern();
int patchRotation = desc.GetRotation();
int subPatch = desc.GetSubPatch();
if (subPatch == 0) {
patchCount[patchType][patchPattern][patchRotation] += patch.GetNumPatches();
}
patchCount[patchType] += patch.GetNumPatches();
numTotalPatches += patch.GetNumPatches();
D3D11_PRIMITIVE_TOPOLOGY topology;
@ -901,48 +896,21 @@ display() {
if (g_displayPatchCounts) {
int x = -280;
int y = -480;
int y = -180;
g_hud->DrawString(x, y, "NonPatch : %d",
patchCount[Descriptor::QUADS][0][0]); y += 20;
patchCount[Descriptor::QUADS]); y += 20;
g_hud->DrawString(x, y, "Regular : %d",
patchCount[Descriptor::REGULAR][0][0]); y+= 20;
patchCount[Descriptor::REGULAR]); y+= 20;
g_hud->DrawString(x, y, "Boundary : %d",
patchCount[Descriptor::BOUNDARY][0][0]); y+= 20;
patchCount[Descriptor::BOUNDARY]); y+= 20;
g_hud->DrawString(x, y, "Corner : %d",
patchCount[Descriptor::CORNER][0][0]); y+= 20;
g_hud->DrawString(x, y, "Single Crease : %d",
patchCount[Descriptor::SINGLE_CREASE][0][0]); y+= 20;
patchCount[Descriptor::CORNER]); y+= 20;
g_hud->DrawString(x, y, "Gregory : %d",
patchCount[Descriptor::GREGORY][0][0]); y+= 20;
patchCount[Descriptor::GREGORY]); y+= 20;
g_hud->DrawString(x, y, "Boundary Gregory : %d",
patchCount[Descriptor::GREGORY_BOUNDARY][0][0]); y+= 20;
g_hud->DrawString(x, y, "Trans. Regular : %d %d %d %d %d",
patchCount[Descriptor::REGULAR][Descriptor::PATTERN0][0],
patchCount[Descriptor::REGULAR][Descriptor::PATTERN1][0],
patchCount[Descriptor::REGULAR][Descriptor::PATTERN2][0],
patchCount[Descriptor::REGULAR][Descriptor::PATTERN3][0],
patchCount[Descriptor::REGULAR][Descriptor::PATTERN4][0]); y+= 20;
for (int i=0; i < 5; i++) {
g_hud->DrawString(x, y, "Trans. Boundary%d : %d %d %d %d", i,
patchCount[Descriptor::BOUNDARY][i+1][0],
patchCount[Descriptor::BOUNDARY][i+1][1],
patchCount[Descriptor::BOUNDARY][i+1][2],
patchCount[Descriptor::BOUNDARY][i+1][3]); y+= 20;
}
for (int i=0; i < 5; i++) {
g_hud->DrawString(x, y, "Trans. Corner%d : %d %d %d %d", i,
patchCount[Descriptor::CORNER][i+1][0],
patchCount[Descriptor::CORNER][i+1][1],
patchCount[Descriptor::CORNER][i+1][2],
patchCount[Descriptor::CORNER][i+1][3]); y+= 20;
}
for (int i=0; i < 5; i++) {
g_hud->DrawString(x, y, "Trans. Single Crease%d : %d %d %d %d", i,
patchCount[Descriptor::SINGLE_CREASE][i+1][0],
patchCount[Descriptor::SINGLE_CREASE][i+1][1],
patchCount[Descriptor::SINGLE_CREASE][i+1][2],
patchCount[Descriptor::SINGLE_CREASE][i+1][3]); y+= 20;
}
patchCount[Descriptor::GREGORY_BOUNDARY]); y+= 20;
g_hud->DrawString(x, y, "Gregory Basis : %d",
patchCount[Descriptor::GREGORY_BASIS]); y+= 20;
}
g_hud->DrawString(10, -120, "Tess level : %d", g_tessLevel);
@ -1504,7 +1472,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmd
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;

65
examples/glEvalLimit/glEvalLimit.cpp Normal file → Executable file
View File

@ -51,6 +51,12 @@ GLFWmonitor* g_primary=0;
#include <osd/drawContext.h>
#include <osd/mesh.h>
#include <osd/vertex.h>
#include <far/gregoryBasis.h>
#include <far/endCapGregoryBasisPatchFactory.h>
#include <far/topologyRefiner.h>
#include <far/stencilTablesFactory.h>
#include <far/patchTablesFactory.h>
#include <far/error.h>
#include <common/vtr_utils.h>
@ -197,8 +203,6 @@ Osd::CpuComputeContext * g_computeCtx = 0;
Osd::CpuComputeController g_computeCtrl;
Far::KernelBatchVector g_kernelBatches;
Osd::CpuEvalLimitContext * g_evalCtx = 0;
Osd::CpuEvalLimitController g_evalCtrl;
@ -242,7 +246,7 @@ updateGeom() {
g_vertexData->UpdateData( &g_positions[0], 0, nverts);
g_computeCtrl.Compute(g_computeCtx, g_kernelBatches, g_vertexData, g_varyingData);
g_computeCtrl.Compute(g_computeCtx, g_vertexData, g_varyingData);
s.Stop();
g_computeTime = float(s.GetElapsed() * 1000.0f);
@ -360,8 +364,6 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) {
Far::TopologyRefiner::AdaptiveOptions options(level);
g_topologyRefiner->RefineAdaptive(options);
nverts = g_topologyRefiner->GetNumVerticesTotal();
// Generate stencil tables to update the bi-cubic patches control
// vertices after they have been re-posed (both for vertex & varying
// interpolation)
@ -378,48 +380,42 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) {
// Generate bi-cubic patch tables for the limit surface
Far::PatchTablesFactory::Options poptions;
// optional : pass the vertex stencils so that the factory can generate gregory basis
// stencils (faster evaluation)
poptions.adaptiveStencilTables = vertexStencils;
poptions.adaptiveVaryingStencilTables = varyingStencils;
Far::EndCapGregoryBasisPatchFactory *gregoryBasisFactory = new
Far::EndCapGregoryBasisPatchFactory(*g_topologyRefiner);
Far::PatchTables const * patchTables =
Far::PatchTablesFactory::Create(*g_topologyRefiner, poptions);
Far::PatchTablesFactoryT<Far::EndCapGregoryBasisPatchFactory>::Create(
*g_topologyRefiner, poptions, gregoryBasisFactory);
Far::StencilTables const *inStencils[] = {
vertexStencils, patchTables->GetEndCapVertexStencilTables()
};
Far::StencilTables const *concatStencils =
Far::StencilTablesFactory::Create(2, inStencils);
// add gregory basis vertices FIXME:
if (patchTables->GetEndCapVertexStencilTables()) {
nverts += patchTables->GetEndCapVertexStencilTables()->GetNumStencils();
if (Far::StencilTables const * vertexStencilsWithGregoryBasis =
gregoryBasisFactory->CreateVertexStencilTables(vertexStencils, true)) {
delete vertexStencils;
vertexStencils = vertexStencilsWithGregoryBasis;
}
Far::StencilTables const *concatVaryingStencils = varyingStencils;
if (varyingStencils and patchTables->GetEndCapVaryingStencilTables()) {
Far::StencilTables const *inVaryingStencils[] = {
varyingStencils, patchTables->GetEndCapVaryingStencilTables()
};
concatVaryingStencils =
Far::StencilTablesFactory::Create(2, inVaryingStencils);
if (Far::StencilTables const *varyingStencilsWithGregoryBasis =
gregoryBasisFactory->CreateVaryingStencilTables(varyingStencils, true)) {
delete varyingStencils;
varyingStencils = varyingStencilsWithGregoryBasis;
}
delete gregoryBasisFactory;
// total number of vertices = coarse verts + refined verts + gregory basis verts
nverts = vertexStencils->GetNumControlVertices() +
vertexStencils->GetNumStencils();
// Create an Osd Compute context, used to "pose" the vertices with
// the stencils tables
delete g_computeCtx;
g_computeCtx = Osd::CpuComputeContext::Create(concatStencils, concatVaryingStencils);
g_computeCtx = Osd::CpuComputeContext::Create(vertexStencils,
varyingStencils);
// Create a limit Eval context with the patch tables
delete g_evalCtx;
g_evalCtx = Osd::CpuEvalLimitContext::Create(*patchTables);
g_kernelBatches.clear();
g_kernelBatches.push_back(Far::StencilTablesFactory::Create(*concatStencils));
delete vertexStencils;
delete varyingStencils;
}
{ // Create vertex primvar buffer for the CVs
@ -431,7 +427,8 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) {
delete g_varyingData; g_varyingData = 0;
if (g_drawMode==kVARYING) {
g_varyingData = Osd::CpuVertexBuffer::Create(3, nverts);
g_varyingData->UpdateData( &g_varyingColors[0], 0, nverts);
g_varyingData->UpdateData(
&g_varyingColors[0], 0, (int)g_varyingColors.size()/3 );
}
// Create output buffers for the limit samples (position & tangents)

View File

@ -24,12 +24,16 @@
#include "particles.h"
#include <far/ptexIndices.h>
#include <cassert>
STParticles::STParticles(Refiner const & refiner, int nparticles, bool centered) :
_speed(1.0f) {
int nptexfaces = refiner.GetNumPtexFaces(),
OpenSubdiv::Far::PtexIndices ptexIndices(refiner);
int nptexfaces = ptexIndices.GetNumFaces(),
nsamples = nptexfaces * nparticles;
srand(static_cast<int>(2147483647));
@ -76,12 +80,12 @@ STParticles::STParticles(Refiner const & refiner, int nparticles, bool centered)
refiner.GetFaceVertices(0, face);
if (fverts.size()==4) {
refiner.GetPtexAdjacency(face, 0, adjfaces, adjedges);
ptexIndices.GetAdjacency(refiner, face, 0, adjfaces, adjedges);
_adjacency[ptexface] = FaceInfo(adjfaces, adjedges, false);
++ptexface;
} else {
for (int vert=0; vert<fverts.size(); ++vert) {
refiner.GetPtexAdjacency(face, vert, adjfaces, adjedges);
ptexIndices.GetAdjacency(refiner, face, vert, adjfaces, adjedges);
_adjacency[ptexface+vert] =
FaceInfo(adjfaces, adjedges, true);
}

View File

@ -1,5 +1,5 @@
#
# Copyright 2013 Pixar
# 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
@ -22,23 +22,56 @@
# language governing permissions and limitations under the Apache License.
#
include_directories("${PROJECT_SOURCE_DIR}/opensubdiv")
include_directories(
"${PROJECT_SOURCE_DIR}/opensubdiv"
"${PROJECT_SOURCE_DIR}/regression"
"${GLFW_INCLUDE_DIR}"
)
set(SHADER_FILES
shader.glsl
)
set(SOURCE_FILES
vtr_regression.cpp
glImaging.cpp
../common/patchColors.cpp
)
set(PLATFORM_LIBRARIES
"${OSD_LINK_TARGET}"
"${OPENGL_LIBRARY}"
"${GLFW_LIBRARIES}"
)
_add_executable(vtr_regression
${SOURCE_FILES}
$<TARGET_OBJECTS:sdc_obj>
$<TARGET_OBJECTS:vtr_obj>
$<TARGET_OBJECTS:far_obj>
if ( GLEW_FOUND )
include_directories("${GLEW_INCLUDE_DIR}")
list(APPEND PLATFORM_LIBRARIES "${GLEW_LIBRARY}")
endif()
if ( OPENCL_FOUND )
list(APPEND PLATFORM_LIBRARIES
"${OPENCL_LIBRARIES}"
)
include_directories( "${OPENCL_INCLUDE_DIRS}" )
endif()
_stringify("${SHADER_FILES}" INC_FILES)
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
_add_possibly_cuda_executable(glImaging
"${SOURCE_FILES}"
"${SHADER_FILES}"
"${INC_FILES}"
$<TARGET_OBJECTS:regression_common_obj>
)
install(TARGETS vtr_regression DESTINATION "${CMAKE_BINDIR_BASE}")
add_dependencies(glImaging blarg )
target_link_libraries(glImaging
${PLATFORM_LIBRARIES}
)
install(TARGETS glImaging DESTINATION "${CMAKE_BINDIR_BASE}")
add_test(glImaging ${EXECUTABLE_OUTPUT_PATH}/glImaging -w test -l 3 -s 256 256 -a)

759
examples/glImaging/glImaging.cpp Executable file
View File

@ -0,0 +1,759 @@
//
// 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.
//
#if defined(__APPLE__)
#if defined(OSD_USES_GLEW)
#include <GL/glew.h>
#else
#include <OpenGL/gl3.h>
#endif
#define GLFW_INCLUDE_GL3
#define GLFW_NO_GLU
#else
#include <stdlib.h>
#include <GL/glew.h>
#if defined(_WIN32)
// XXX Must include windows.h here or GLFW pollutes the global namespace
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#endif
#include <iostream>
#include <fstream>
#include <sstream>
#include <limits>
#include <GLFW/glfw3.h>
#include <osd/cpuGLVertexBuffer.h>
#include <osd/cpuComputeContext.h>
#include <osd/cpuComputeController.h>
OpenSubdiv::Osd::CpuComputeController *g_cpuComputeController = NULL;
#ifdef OPENSUBDIV_HAS_OPENMP
#include <osd/ompComputeController.h>
OpenSubdiv::Osd::OmpComputeController *g_ompComputeController = NULL;
#endif
#ifdef OPENSUBDIV_HAS_TBB
#include <osd/tbbComputeController.h>
OpenSubdiv::Osd::TbbComputeController *g_tbbComputeController = NULL;
#endif
#ifdef OPENSUBDIV_HAS_OPENCL
#include <osd/clGLVertexBuffer.h>
#include <osd/clComputeContext.h>
#include <osd/clComputeController.h>
#include "../common/clInit.h"
cl_context g_clContext;
cl_command_queue g_clQueue;
OpenSubdiv::Osd::CLComputeController *g_clComputeController = NULL;
#endif
#ifdef OPENSUBDIV_HAS_CUDA
#include <osd/cudaGLVertexBuffer.h>
#include <osd/cudaComputeContext.h>
#include <osd/cudaComputeController.h>
#include <cuda_runtime_api.h>
#include <cuda_gl_interop.h>
#include "../common/cudaInit.h"
OpenSubdiv::Osd::CudaComputeController *g_cudaComputeController = NULL;
#endif
#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
#include <osd/glslTransformFeedbackComputeContext.h>
#include <osd/glslTransformFeedbackComputeController.h>
#include <osd/glVertexBuffer.h>
OpenSubdiv::Osd::GLSLTransformFeedbackComputeController *g_glslTransformFeedbackComputeController = NULL;
#endif
#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
#include <osd/glslComputeContext.h>
#include <osd/glslComputeController.h>
#include <osd/glVertexBuffer.h>
OpenSubdiv::Osd::GLSLComputeController *g_glslComputeController = NULL;
#endif
#include <osd/glDrawContext.h>
#include <osd/glDrawRegistry.h>
#include <osd/glMesh.h>
#include <common/vtr_utils.h>
#include "../common/patchColors.h"
#include "init_shapes.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION 1
#include "stb_image_write.h"
using namespace OpenSubdiv;
static const char *shaderSource =
#include "shader.gen.h"
;
static void
setGLCoreProfile() {
#define glfwOpenWindowHint glfwWindowHint
#define GLFW_OPENGL_VERSION_MAJOR GLFW_CONTEXT_VERSION_MAJOR
#define GLFW_OPENGL_VERSION_MINOR GLFW_CONTEXT_VERSION_MINOR
glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#if not defined(__APPLE__)
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 4);
#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 3);
#else
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 2);
#endif
#else
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 4);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 1);
#endif
glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
}
// ---------------------------------------------------------------------------
class DrawRegistry : public Osd::GLDrawRegistry<> {
public:
DrawRegistry(std::string const &displayMode)
: _displayMode(displayMode) { }
protected:
virtual SourceConfigType *
_CreateDrawSourceConfig(DescType const & desc);
virtual ConfigType *
_CreateDrawConfig(DescType const & desc,
SourceConfigType const * sconfig);
private:
std::string _displayMode;
};
DrawRegistry::ConfigType *
DrawRegistry::_CreateDrawConfig(DescType const & desc,
SourceConfigType const * sconfig) {
ConfigType * config = BaseRegistry::_CreateDrawConfig(desc, sconfig);
assert(config);
GLuint uboIndex = glGetUniformBlockIndex(config->program, "Transform");
glUniformBlockBinding(config->program, uboIndex, 0);
GLint loc = glGetUniformLocation(config->program, "OsdPatchParamBuffer");
if (loc != -1) {
glUniform1i(loc, 0); // GL_TEXTURE0
}
return config;
};
DrawRegistry::SourceConfigType *
DrawRegistry::_CreateDrawSourceConfig(DescType const & desc) {
typedef Far::PatchDescriptor Descriptor;
SourceConfigType * sconfig =
BaseRegistry::_CreateDrawSourceConfig(desc);
assert(sconfig);
const char *glslVersion = "#version 410\n";
if (desc.GetType() == Descriptor::QUADS or
desc.GetType() == Descriptor::TRIANGLES) {
sconfig->vertexShader.source = shaderSource;
sconfig->vertexShader.version = glslVersion;
sconfig->vertexShader.AddDefine("VERTEX_SHADER");
} else {
sconfig->geometryShader.AddDefine("SMOOTH_NORMALS");
}
sconfig->geometryShader.source = shaderSource;
sconfig->geometryShader.version = glslVersion;
sconfig->geometryShader.AddDefine("GEOMETRY_SHADER");
sconfig->fragmentShader.source = shaderSource;
sconfig->fragmentShader.version = glslVersion;
sconfig->fragmentShader.AddDefine("FRAGMENT_SHADER");
if (desc.GetType() == Descriptor::QUADS) {
// uniform catmark, bilinear
sconfig->geometryShader.AddDefine("PRIM_QUAD");
sconfig->fragmentShader.AddDefine("PRIM_QUAD");
sconfig->commonShader.AddDefine("UNIFORM_SUBDIVISION");
} else if (desc.GetType() == Descriptor::TRIANGLES) {
// uniform loop
sconfig->geometryShader.AddDefine("PRIM_TRI");
sconfig->fragmentShader.AddDefine("PRIM_TRI");
sconfig->commonShader.AddDefine("LOOP");
sconfig->commonShader.AddDefine("UNIFORM_SUBDIVISION");
} else {
// adaptive
sconfig->vertexShader.source =
shaderSource + sconfig->vertexShader.source;
sconfig->tessControlShader.source =
shaderSource + sconfig->tessControlShader.source;
sconfig->tessEvalShader.source =
shaderSource + sconfig->tessEvalShader.source;
sconfig->geometryShader.AddDefine("PRIM_TRI");
sconfig->fragmentShader.AddDefine("PRIM_TRI");
}
sconfig->commonShader.AddDefine("DISPLAY_MODE_" + _displayMode);
// sconfig->commonShader.AddDefine("OSD_ENABLE_SCREENSPACE_TESSELLATION");
// sconfig->commonShader.AddDefine("OSD_FRACTIONAL_ODD_SPACING");
sconfig->commonShader.AddDefine("OSD_ENABLE_PATCH_CULL");
sconfig->commonShader.AddDefine("GEOMETRY_OUT_LINE");
return sconfig;
}
// ---------------------------------------------------------------------------
static Osd::GLMeshInterface *
createOsdMesh(std::string const &kernel,
Far::TopologyRefiner *refiner,
int numVertexElements,
int numVaryingElements,
int level,
Osd::MeshBitset bits)
{
if (kernel == "CPU") {
if (not g_cpuComputeController) {
g_cpuComputeController = new Osd::CpuComputeController();
}
return new Osd::Mesh<Osd::CpuGLVertexBuffer,
Osd::CpuComputeController,
Osd::GLDrawContext>(
g_cpuComputeController,
refiner,
numVertexElements,
numVaryingElements,
level, bits);
#ifdef OPENSUBDIV_HAS_OPENMP
} else if (kernel == "OPENMP") {
if (not g_ompComputeController) {
g_ompComputeController = new Osd::OmpComputeController();
}
return new Osd::Mesh<Osd::CpuGLVertexBuffer,
Osd::OmpComputeController,
Osd::GLDrawContext>(
g_ompComputeController,
refiner,
numVertexElements,
numVaryingElements,
level, bits);
#endif
#ifdef OPENSUBDIV_HAS_TBB
} else if (kernel == "TBB") {
if (not g_tbbComputeController) {
g_tbbComputeController = new Osd::TbbComputeController();
}
return new Osd::Mesh<Osd::CpuGLVertexBuffer,
Osd::TbbComputeController,
Osd::GLDrawContext>(
g_tbbComputeController,
refiner,
numVertexElements,
numVaryingElements,
level, bits);
#endif
#ifdef OPENSUBDIV_HAS_OPENCL
} else if(kernel == "CL") {
if (not g_clComputeController) {
g_clComputeController = new Osd::CLComputeController(g_clContext, g_clQueue);
}
return new Osd::Mesh<Osd::CLGLVertexBuffer,
Osd::CLComputeController,
Osd::GLDrawContext>(
g_clComputeController,
refiner,
numVertexElements,
numVaryingElements,
level, bits, g_clContext, g_clQueue);
#endif
#ifdef OPENSUBDIV_HAS_CUDA
} else if(kernel == "CUDA") {
if (not g_cudaComputeController) {
g_cudaComputeController = new Osd::CudaComputeController();
}
return new Osd::Mesh<Osd::CudaGLVertexBuffer,
Osd::CudaComputeController,
Osd::GLDrawContext>(
g_cudaComputeController,
refiner,
numVertexElements,
numVaryingElements,
level, bits);
#endif
#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
} else if(kernel == "XFB") {
if (not g_glslTransformFeedbackComputeController) {
g_glslTransformFeedbackComputeController = new Osd::GLSLTransformFeedbackComputeController();
}
return new Osd::Mesh<Osd::GLVertexBuffer,
Osd::GLSLTransformFeedbackComputeController,
Osd::GLDrawContext>(
g_glslTransformFeedbackComputeController,
refiner,
numVertexElements,
numVaryingElements,
level, bits);
#endif
#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
} else if(kernel == "GLSL") {
if (not g_glslComputeController) {
g_glslComputeController = new Osd::GLSLComputeController();
}
return new Osd::Mesh<Osd::GLVertexBuffer,
Osd::GLSLComputeController,
Osd::GLDrawContext>(
g_glslComputeController,
refiner,
numVertexElements,
numVaryingElements,
level, bits);
#endif
}
std::cout << "Specified kernel is not supported in this build.\n";
exit(1);
}
void runTest(ShapeDesc const &shapeDesc, std::string const &kernel,
int level, bool adaptive,
DrawRegistry *drawRegistry) {
std::cout << "Testing " << shapeDesc.name << ", kernel = " << kernel << "\n";
Shape const * shape = Shape::parseObj(shapeDesc.data.c_str(),
shapeDesc.scheme);
// create Vtr mesh (topology)
Sdc::SchemeType sdctype = GetSdcType(*shape);
Sdc::Options sdcoptions = GetSdcOptions(*shape);
// create topology refiner
Far::TopologyRefiner *refiner =
Far::TopologyRefinerFactory<Shape>::Create(
*shape,
Far::TopologyRefinerFactory<Shape>::Options(sdctype, sdcoptions));
// Adaptive refinement currently supported only for catmull-clark scheme
bool doAdaptive = adaptive && (shapeDesc.scheme == kCatmark);
bool interleaveVarying = true;
bool doSingleCreasePatch = true;
Osd::MeshBitset bits;
bits.set(Osd::MeshAdaptive, doAdaptive);
bits.set(Osd::MeshUseSingleCreasePatch, doSingleCreasePatch);
bits.set(Osd::MeshInterleaveVarying, interleaveVarying);
bits.set(Osd::MeshFVarData, false);
bits.set(Osd::MeshEndCapGregoryBasis, true);
int numVertexElements = 3 + 4; // XYZ, RGBA (interleaved)
int numVaryingElements = 0;
Osd::GLMeshInterface *mesh = createOsdMesh(
kernel, refiner, numVertexElements, numVaryingElements, level, bits);
int nverts = shape->GetNumVertices();
// centering
float pmin[3] = { std::numeric_limits<float>::max(),
std::numeric_limits<float>::max(),
std::numeric_limits<float>::max() };
float pmax[3] = { -std::numeric_limits<float>::max(),
-std::numeric_limits<float>::max(),
-std::numeric_limits<float>::max() };
for (int i = 0; i < nverts; ++i) {
for (int j = 0; j < 3; ++j) {
float v = shape->verts[i*3+j];
pmin[j] = std::min(v, pmin[j]);
pmax[j] = std::max(v, pmax[j]);
}
}
float center[3] = { (pmax[0]+pmin[0])*0.5f,
(pmax[1]+pmin[1])*0.5f,
(pmax[2]+pmin[2])*0.5f };
float radius = sqrt((pmax[0]-pmin[0])*(pmax[0]-pmin[0]) +
(pmax[1]-pmin[1])*(pmax[1]-pmin[1]) +
(pmax[2]-pmin[2])*(pmax[2]-pmin[2]));
// prepare coarse vertices
std::vector<float> vertex;
vertex.resize(nverts * numVertexElements);
for (int i = 0; i < nverts; ++i) {
for (int j = 0; j < 3; ++j) {
vertex[i*numVertexElements+j] =
(shape->verts[i*3+j] - center[j])/radius;
}
for (int j = 0; j < 4; ++j) {
vertex[i*numVertexElements+j+3] =
(shape->verts[i*3+j] - pmin[j])*2.0f/radius;
}
}
mesh->UpdateVertexBuffer(&vertex[0], 0, nverts);
// refine
mesh->Refine();
// draw
glClearColor(0.1f, 0.1f, 0.1f, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// bind vertex
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->GetDrawContext()->GetPatchIndexBuffer());
glBindBuffer(GL_ARRAY_BUFFER, mesh->BindVertexBuffer());
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
sizeof (GLfloat) * numVertexElements, 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE,
sizeof (GLfloat) * numVertexElements,
(const void*)(sizeof(GLfloat)*3));
// bind patchparam
if (mesh->GetDrawContext()->GetPatchParamTextureBuffer()) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER,
mesh->GetDrawContext()->GetPatchParamTextureBuffer());
}
Osd::DrawContext::PatchArrayVector const & patches =
mesh->GetDrawContext()->GetPatchArrays();
for (int i=0; i<(int)patches.size(); ++i) {
Osd::DrawContext::PatchArray const & patch = patches[i];
Osd::DrawContext::PatchDescriptor desc = patch.GetDescriptor();
Far::PatchDescriptor::Type patchType = desc.GetType();
GLenum primType;
switch(patchType) {
case Far::PatchDescriptor::QUADS:
primType = GL_LINES_ADJACENCY;
break;
case Far::PatchDescriptor::TRIANGLES:
primType = GL_TRIANGLES;
break;
default:
primType = GL_PATCHES;
glPatchParameteri(GL_PATCH_VERTICES, desc.GetNumControlVertices());
}
GLuint program = drawRegistry->GetDrawConfig(desc)->program;
glUseProgram(program);
GLuint diffuseColor =
glGetUniformLocation(program, "diffuseColor");
GLuint uniformPrimitiveIdBase =
glGetUniformLocation(program, "PrimitiveIdBase");
if (primType == GL_PATCHES) {
float const * color = getAdaptivePatchColor( desc );
glProgramUniform4f(program, diffuseColor,
color[0], color[1], color[2], color[3]);
glProgramUniform1i(program, uniformPrimitiveIdBase,
patch.GetPatchIndex());
} else {
glProgramUniform4f(program, diffuseColor, 0.4f, 0.4f, 0.8f, 1);
}
glDrawElements(primType, patch.GetNumIndices(), GL_UNSIGNED_INT,
(void *)(patch.GetVertIndex() * sizeof(unsigned int)));
}
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
glDeleteVertexArrays(1, &vao);
// cleanup
delete shape;
delete mesh;
// mesh takes an ownership of topologyRefiner. no need to delete it.
}
static void usage(const char *program) {
std::cout
<< "Usage %s : " << program << "\n"
<< " -a : adaptive refinement\n"
<< " -l <isolation level> : isolation level (default = 2)\n"
<< " -t <tess level> : tessellation level (default = 1)\n"
<< " -w <prefix> : write images to PNG as\n"
<< " <prefix>_<kernel>_modelname.png\n"
<< " -s <width> <height> : image size (default = 128 128)\n"
<< " -k <kernel>,<kernel>... : kernel types (default = all)\n"
<< " kernel = [CPU, OPENMP, TBB, CUDA, CL, XFB, GLSL]\n"
<< " -d <displayMode> : display mode\n"
<< " displayMode = [PATCH_TYPE, VARYING, NORMAL]\n";
}
int main(int argc, char ** argv) {
int width = 128;
int height = 128;
int tessLevel = 1;
int isolationLevel = 2;
bool writeToFile = false;
bool adaptive = false;
std::string prefix;
std::string displayMode = "PATCH_TYPE";
std::vector<std::string> kernels;
for (int i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-a")) {
adaptive = true;
} else if (!strcmp(argv[i], "-l")) {
isolationLevel = atoi(argv[++i]);
} else if (!strcmp(argv[i], "-k")) {
std::stringstream ss(argv[++i]);
std::string kernel;
while(std::getline(ss, kernel, ',')) {
kernels.push_back(kernel);
}
} else if (!strcmp(argv[i], "-t")) {
tessLevel = atoi(argv[++i]);
} else if (!strcmp(argv[i], "-w")) {
writeToFile = true;
prefix = argv[++i];
} else if (!strcmp(argv[i], "-s")) {
width = atoi(argv[++i]);
height = atoi(argv[++i]);
} else if (!strcmp(argv[i], "-d")) {
displayMode = argv[++i];
} else {
usage(argv[0]);
return 1;
}
}
// by default, test all available kernels
if (kernels.empty()) {
kernels.push_back("CPU");
#ifdef OPENSUBDIV_HAS_OPENMP
kernels.push_back("OPENMP");
#endif
#ifdef OPENSUBDIV_HAS_TBB
kernels.push_back("TBB");
#endif
#ifdef OPENSUBDIV_HAS_CUDA
kernels.push_back("CUDA");
#endif
#ifdef OPENSUBDIV_HAS_OPENCL
kernels.push_back("CL");
#endif
#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
kernels.push_back("XFB");
#endif
#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
kernels.push_back("GLSL");
#endif
}
if (not glfwInit()) {
std::cout << "Failed to initialize GLFW\n";
return 1;
}
static const char windowTitle[] =
"OpenSubdiv imaging test " OPENSUBDIV_VERSION_STRING;
setGLCoreProfile();
GLFWwindow *window = glfwCreateWindow(width, height, windowTitle, NULL, NULL);
if (not window) {
std::cout << "Failed to open window.\n";
glfwTerminate();
}
glfwMakeContextCurrent(window);
#if defined(OSD_USES_GLEW)
// this is the only way to initialize glew correctly under core profile context.
glewExperimental = true;
if (GLenum r = glewInit() != GLEW_OK) {
std::cout << "Failed to initialize glew. Error = "
<< glewGetErrorString(r) << "\n";
exit(1);
}
// clear GL errors generated during glewInit()
glGetError();
#endif
initShapes();
// initialize GL states
glViewport(0, 0, width, height);
glEnable(GL_DEPTH_TEST);
// some regression shapes are not visible in this camera
// with backface culling.
// glEnable(GL_CULL_FACE);
// transform uniform
float modelview[16] = {
0.945518f, -0.191364f, 0.263390f, 0.000000f,
0.325568f, 0.555762f, -0.764941f, 0.000000f,
0.000000f, 0.809017f, 0.587785f, 0.000000f,
0.000000f, 0.000000f, -1.500000f, 1.000000f };
float projection[16] = {
2.414213f, 0.000000f, 0.000000f, 0.000000f,
0.000000f, 2.414213f, 0.000000f, 0.000000f,
0.000000f, 0.000000f, -1.000000f, -1.000000f,
0.000000f, 0.000000f, -0.000200f, 0.000000f
};
struct Transform {
float ModelViewMatrix[16];
float ProjectionMatrix[16];
float Viewport[4];
float TessLevel;
} transformData;
memcpy(transformData.ModelViewMatrix, modelview, sizeof(modelview));
memcpy(transformData.ProjectionMatrix, projection, sizeof(projection));
transformData.Viewport[0] = 0;
transformData.Viewport[1] = 0;
transformData.Viewport[2] = static_cast<float>(width);
transformData.Viewport[3] = static_cast<float>(height);
transformData.TessLevel = static_cast<float>(1 << tessLevel);
GLuint transformUB = 0;
glGenBuffers(1, &transformUB);
glBindBuffer(GL_UNIFORM_BUFFER, transformUB);
glBufferData(GL_UNIFORM_BUFFER, sizeof(transformData),
&transformData, GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, /*binding=*/0, transformUB);
// create draw registry;
DrawRegistry drawRegistry(displayMode);
// write report html
if (writeToFile) {
std::string reportfile = prefix + ".html";
std::ofstream ofs(reportfile.c_str());
ofs << "<html>\n"
<< "<head><style>\n"
<< "table { border-collapse:collapse; } "
<< "table,th,td {border: 1px solid black} "
<< "</style></head>\n";
ofs << "<body>\n";
ofs << "<h3>OpenSubdiv imaging regression test<h3>\n";
ofs << "<pre>\n";
ofs << "OpenSubdiv : " << OPENSUBDIV_VERSION_STRING << "\n";
ofs << "GL Version : " << glGetString(GL_VERSION)
<< ", " << glGetString(GL_VENDOR)
<< ", " << glGetString(GL_RENDERER)
<< "\n";
ofs << "Isolation Level : " << isolationLevel << "\n";
ofs << "Tess Level : " << tessLevel << "\n";
ofs << "Adaptive : " << adaptive << "\n";
ofs << "Display Mode : " << displayMode << "\n";
ofs << "</pre>\n";
ofs << "<table>\n";
ofs << "<tr>\n";
ofs << "<th>Reference<br>(on github. to be updated)</th>\n";
for (size_t k = 0; k < kernels.size(); ++k) {
ofs << "<th>" << kernels[k] << "</th>\n";
}
ofs << "</tr>\n";
for (size_t i = 0; i < g_shapes.size(); ++i) {
ofs << "<tr>\n";
ofs << "<td>" << g_shapes[i].name << "</td>\n";
for (size_t k = 0; k < kernels.size(); ++k) {
ofs << "<td>";
ofs << "<img src='" << prefix << "_" << kernels[k] << "_" << g_shapes[i].name << ".png'>";
ofs << "</td>";
}
ofs << "</tr>\n";
}
ofs << "</table>\n";
ofs << "</body></html>\n";
ofs.close();
}
// run test
for (size_t k = 0; k < kernels.size(); ++k) {
std::string const &kernel = kernels[k];
// prep GPU kernel
#ifdef OPENSUBDIV_HAS_OPENCL
if (kernel == "CL") {
if (initCL(&g_clContext, &g_clQueue) == false) {
std::cout << "Error in initializing OpenCL\n";
exit(1);
}
}
#endif
#ifdef OPENSUBDIV_HAS_CUDA
if (kernel == "CUDA") {
cudaGLSetGLDevice( cutGetMaxGflopsDeviceId() );
}
#endif
for (size_t i = 0; i < g_shapes.size(); ++i) {
// run test
runTest(g_shapes[i], kernel, isolationLevel, adaptive, &drawRegistry);
if (writeToFile) {
// read back pixels
std::vector<unsigned char> data(width*height*3);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, &data[0]);
// write image
std::string filename = prefix + "_" + kernel + "_" + g_shapes[i].name + ".png";
// flip vertical
stbi_write_png(filename.c_str(), width, height, 3, &data[width*3*(height-1)], -width*3);
}
glfwSwapBuffers(window);
}
#ifdef OPENSUBDIV_HAS_OPENCL
if (kernel == "CL") {
uninitCL(g_clContext, g_clQueue);
}
#endif
}
return 0;
}

View 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.
//
#include <common/shape_utils.h>
struct ShapeDesc {
ShapeDesc(char const * iname, std::string const & idata, Scheme ischeme) :
name(iname), data(idata), scheme(ischeme) { }
std::string name,
data;
Scheme scheme;
};
static std::vector<ShapeDesc> g_shapes;
#include <shapes/catmark_bishop.h>
#include <shapes/catmark_car.h>
#include <shapes/catmark_chaikin0.h>
#include <shapes/catmark_chaikin1.h>
#include <shapes/catmark_chaikin2.h>
#include <shapes/catmark_cube_corner0.h>
#include <shapes/catmark_cube_corner1.h>
#include <shapes/catmark_cube_corner2.h>
#include <shapes/catmark_cube_corner3.h>
#include <shapes/catmark_cube_corner4.h>
#include <shapes/catmark_cube_creases0.h>
#include <shapes/catmark_cube_creases1.h>
#include <shapes/catmark_cube_creases2.h>
#include <shapes/catmark_cube.h>
#include <shapes/catmark_dart_edgecorner.h>
#include <shapes/catmark_dart_edgeonly.h>
#include <shapes/catmark_edgecorner.h>
#include <shapes/catmark_edgeonly.h>
#include <shapes/catmark_fan.h>
#include <shapes/catmark_flap.h>
#include <shapes/catmark_flap2.h>
#include <shapes/catmark_fvar_bound0.h>
#include <shapes/catmark_fvar_bound1.h>
#include <shapes/catmark_fvar_bound2.h>
#include <shapes/catmark_gregory_test0.h>
#include <shapes/catmark_gregory_test1.h>
#include <shapes/catmark_gregory_test2.h>
#include <shapes/catmark_gregory_test3.h>
#include <shapes/catmark_gregory_test4.h>
#include <shapes/catmark_gregory_test5.h>
#include <shapes/catmark_gregory_test6.h>
#include <shapes/catmark_gregory_test7.h>
#include <shapes/catmark_helmet.h>
#include <shapes/catmark_hole_test1.h>
#include <shapes/catmark_hole_test2.h>
#include <shapes/catmark_hole_test3.h>
#include <shapes/catmark_hole_test4.h>
#include <shapes/catmark_pawn.h>
#include <shapes/catmark_pyramid_creases0.h>
#include <shapes/catmark_pyramid_creases1.h>
#include <shapes/catmark_pyramid.h>
#include <shapes/catmark_rook.h>
#include <shapes/catmark_smoothtris0.h>
#include <shapes/catmark_smoothtris1.h>
#include <shapes/catmark_square_hedit0.h>
#include <shapes/catmark_square_hedit1.h>
#include <shapes/catmark_square_hedit2.h>
#include <shapes/catmark_square_hedit3.h>
#include <shapes/catmark_tent_creases0.h>
#include <shapes/catmark_tent_creases1.h>
#include <shapes/catmark_tent.h>
#include <shapes/catmark_torus.h>
#include <shapes/catmark_torus_creases0.h>
#include <shapes/bilinear_cube.h>
#include <shapes/loop_cube_creases0.h>
#include <shapes/loop_cube_creases1.h>
#include <shapes/loop_cube.h>
#include <shapes/loop_icosahedron.h>
#include <shapes/loop_saddle_edgecorner.h>
#include <shapes/loop_saddle_edgeonly.h>
#include <shapes/loop_triangle_edgecorner.h>
#include <shapes/loop_triangle_edgeonly.h>
#include <shapes/loop_chaikin0.h>
#include <shapes/loop_chaikin1.h>
//------------------------------------------------------------------------------
static void initShapes() {
g_shapes.push_back( ShapeDesc("catmark_cube_corner0", catmark_cube_corner0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_cube_corner1", catmark_cube_corner1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_cube_corner2", catmark_cube_corner2, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_cube_corner3", catmark_cube_corner3, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_cube_corner4", catmark_cube_corner4, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_cube_creases0", catmark_cube_creases0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_cube_creases1", catmark_cube_creases1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_cube_creases2", catmark_cube_creases2, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_cube", catmark_cube, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_dart_edgecorner", catmark_dart_edgecorner, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_dart_edgeonly", catmark_dart_edgeonly, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_edgecorner", catmark_edgecorner, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_edgeonly", catmark_edgeonly, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_chaikin0", catmark_chaikin0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_chaikin1", catmark_chaikin1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_chaikin2", catmark_chaikin2, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_fan", catmark_fan, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_flap", catmark_flap, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_flap2", catmark_flap2, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_fvar_bound0", catmark_fvar_bound0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_fvar_bound1", catmark_fvar_bound1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_fvar_bound2", catmark_fvar_bound2, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test0", catmark_gregory_test0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test1", catmark_gregory_test1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test2", catmark_gregory_test2, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test3", catmark_gregory_test3, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test4", catmark_gregory_test4, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test5", catmark_gregory_test5, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test6", catmark_gregory_test6, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test7", catmark_gregory_test7, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_hole_test1", catmark_hole_test1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_hole_test2", catmark_hole_test2, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_hole_test3", catmark_hole_test3, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_hole_test4", catmark_hole_test4, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_pyramid_creases0", catmark_pyramid_creases0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_pyramid_creases1", catmark_pyramid_creases1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_pyramid", catmark_pyramid, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_tent_creases0", catmark_tent_creases0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_tent_creases1", catmark_tent_creases1 , kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_tent", catmark_tent, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_torus", catmark_torus, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_torus_creases0", catmark_torus_creases0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_smoothtris0", catmark_smoothtris0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_smoothtris1", catmark_smoothtris1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_bishop", catmark_bishop, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_car", catmark_car, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_helmet", catmark_helmet, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_pawn", catmark_pawn, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_rook", catmark_rook, kCatmark ) );
g_shapes.push_back( ShapeDesc("bilinear_cube", bilinear_cube, kBilinear ) );
g_shapes.push_back( ShapeDesc("loop_cube_creases0", loop_cube_creases0, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_cube_creases1", loop_cube_creases1, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_cube", loop_cube, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_icosahedron", loop_icosahedron, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_saddle_edgecorner", loop_saddle_edgecorner, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_saddle_edgeonly", loop_saddle_edgeonly, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_triangle_edgecorner", loop_triangle_edgecorner, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_triangle_edgeonly", loop_triangle_edgeonly, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_chaikin0", loop_chaikin0, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_chaikin1", loop_chaikin1, kLoop ) );
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,336 @@
//
// 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.
//
#undef OSD_USER_VARYING_DECLARE
#define OSD_USER_VARYING_DECLARE \
vec3 color;
#undef OSD_USER_VARYING_ATTRIBUTE_DECLARE
#define OSD_USER_VARYING_ATTRIBUTE_DECLARE \
layout(location = 1) in vec3 color;
#undef OSD_USER_VARYING_PER_VERTEX
#define OSD_USER_VARYING_PER_VERTEX() \
outpt.color = color
#undef OSD_USER_VARYING_PER_CONTROL_POINT
#define OSD_USER_VARYING_PER_CONTROL_POINT(ID_OUT, ID_IN) \
outpt[ID_OUT].color = inpt[ID_IN].color
#undef OSD_USER_VARYING_PER_EVAL_POINT
#define OSD_USER_VARYING_PER_EVAL_POINT(UV, a, b, c, d) \
outpt.color = \
mix(mix(inpt[a].color, inpt[b].color, UV.x), \
mix(inpt[c].color, inpt[d].color, UV.x), UV.y)
//--------------------------------------------------------------
// Uniforms / Uniform Blocks
//--------------------------------------------------------------
layout(std140) uniform Transform {
mat4 ModelViewMatrix;
mat4 ProjectionMatrix;
vec4 Viewport;
float TessLevel;
};
uniform int GregoryQuadOffsetBase;
uniform int PrimitiveIdBase;
//--------------------------------------------------------------
// Osd external functions
//--------------------------------------------------------------
mat4 OsdModelViewMatrix()
{
return ModelViewMatrix;
}
mat4 OsdProjectionMatrix()
{
return ProjectionMatrix;
}
mat4 OsdModelViewProjectionMatrix()
{
return OsdProjectionMatrix() * OsdModelViewMatrix();
}
float OsdTessLevel()
{
return TessLevel;
}
int OsdGregoryQuadOffsetBase()
{
return GregoryQuadOffsetBase;
}
int OsdPrimitiveIdBase()
{
return PrimitiveIdBase;
}
int OsdBaseVertex()
{
return 0;
}
//--------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------
#ifdef VERTEX_SHADER
layout (location=0) in vec4 position;
OSD_USER_VARYING_ATTRIBUTE_DECLARE
out block {
OutputVertex v;
OSD_USER_VARYING_DECLARE
} outpt;
void main()
{
outpt.v.position = ModelViewMatrix * position;
outpt.v.patchCoord = vec4(0);
OSD_USER_VARYING_PER_VERTEX();
}
#endif
//--------------------------------------------------------------
// Geometry Shader
//--------------------------------------------------------------
#ifdef GEOMETRY_SHADER
#ifdef PRIM_QUAD
layout(lines_adjacency) in;
#define EDGE_VERTS 4
#endif // PRIM_QUAD
#ifdef PRIM_TRI
layout(triangles) in;
#define EDGE_VERTS 3
#endif // PRIM_TRI
layout(triangle_strip, max_vertices = EDGE_VERTS) out;
in block {
OutputVertex v;
OSD_USER_VARYING_DECLARE
} inpt[EDGE_VERTS];
out block {
OutputVertex v;
noperspective out vec4 edgeDistance;
OSD_USER_VARYING_DECLARE
} outpt;
void emit(int index, vec3 normal)
{
outpt.v.position = inpt[index].v.position;
outpt.v.patchCoord = inpt[index].v.patchCoord;
#ifdef SMOOTH_NORMALS
outpt.v.normal = inpt[index].v.normal;
#else
outpt.v.normal = normal;
#endif
outpt.color = inpt[index].color;
gl_Position = ProjectionMatrix * inpt[index].v.position;
EmitVertex();
}
#if defined(GEOMETRY_OUT_WIRE) || defined(GEOMETRY_OUT_LINE)
uniform float viewportScale;
float edgeDistance(vec4 p, vec4 p0, vec4 p1)
{
vec4 viewportScale = vec4(0.5*Viewport[2],
0.5*Viewport[3],
1, 1);
p *= viewportScale;
p0 *= viewportScale;
p1 *= viewportScale;
return abs((p.x - p0.x) * (p1.y - p0.y) -
(p.y - p0.y) * (p1.x - p0.x)) / length(p1.xy - p0.xy);
}
void emit(int index, vec3 normal, vec4 edgeVerts[EDGE_VERTS])
{
outpt.edgeDistance[0] =
edgeDistance(edgeVerts[index], edgeVerts[0], edgeVerts[1]);
outpt.edgeDistance[1] =
edgeDistance(edgeVerts[index], edgeVerts[1], edgeVerts[2]);
#ifdef PRIM_TRI
outpt.edgeDistance[2] =
edgeDistance(edgeVerts[index], edgeVerts[2], edgeVerts[0]);
#endif
#ifdef PRIM_QUAD
outpt.edgeDistance[2] =
edgeDistance(edgeVerts[index], edgeVerts[2], edgeVerts[3]);
outpt.edgeDistance[3] =
edgeDistance(edgeVerts[index], edgeVerts[3], edgeVerts[0]);
#endif
emit(index, normal);
}
#endif
void main()
{
gl_PrimitiveID = gl_PrimitiveIDIn;
#ifdef PRIM_QUAD
vec3 A = (inpt[0].v.position - inpt[1].v.position).xyz;
vec3 B = (inpt[3].v.position - inpt[1].v.position).xyz;
vec3 C = (inpt[2].v.position - inpt[1].v.position).xyz;
vec3 n0 = normalize(cross(B, A));
#if defined(GEOMETRY_OUT_WIRE) || defined(GEOMETRY_OUT_LINE)
vec4 edgeVerts[EDGE_VERTS];
edgeVerts[0] = ProjectionMatrix * inpt[0].v.position;
edgeVerts[1] = ProjectionMatrix * inpt[1].v.position;
edgeVerts[2] = ProjectionMatrix * inpt[2].v.position;
edgeVerts[3] = ProjectionMatrix * inpt[3].v.position;
edgeVerts[0].xy /= edgeVerts[0].w;
edgeVerts[1].xy /= edgeVerts[1].w;
edgeVerts[2].xy /= edgeVerts[2].w;
edgeVerts[3].xy /= edgeVerts[3].w;
emit(0, n0, edgeVerts);
emit(1, n0, edgeVerts);
emit(3, n0, edgeVerts);
emit(2, n0, edgeVerts);
#else
emit(0, n0);
emit(1, n0);
emit(3, n0);
emit(2, n0);
#endif
#endif // PRIM_QUAD
#ifdef PRIM_TRI
vec3 A = (inpt[0].v.position - inpt[1].v.position).xyz;
vec3 B = (inpt[2].v.position - inpt[1].v.position).xyz;
vec3 n0 = normalize(cross(B, A));
#if defined(GEOMETRY_OUT_WIRE) || defined(GEOMETRY_OUT_LINE)
vec4 edgeVerts[EDGE_VERTS];
edgeVerts[0] = ProjectionMatrix * inpt[0].v.position;
edgeVerts[1] = ProjectionMatrix * inpt[1].v.position;
edgeVerts[2] = ProjectionMatrix * inpt[2].v.position;
edgeVerts[0].xy /= edgeVerts[0].w;
edgeVerts[1].xy /= edgeVerts[1].w;
edgeVerts[2].xy /= edgeVerts[2].w;
emit(0, n0, edgeVerts);
emit(1, n0, edgeVerts);
emit(2, n0, edgeVerts);
#else
emit(0, n0);
emit(1, n0);
emit(2, n0);
#endif
#endif // PRIM_TRI
EndPrimitive();
}
#endif
//--------------------------------------------------------------
// Fragment Shader
//--------------------------------------------------------------
#ifdef FRAGMENT_SHADER
in block {
OutputVertex v;
noperspective in vec4 edgeDistance;
OSD_USER_VARYING_DECLARE
} inpt;
out vec4 outColor;
uniform vec4 diffuseColor = vec4(1);
uniform vec4 ambientColor = vec4(1);
vec4
edgeColor(vec4 Cfill, vec4 edgeDistance)
{
#if defined(GEOMETRY_OUT_WIRE) || defined(GEOMETRY_OUT_LINE)
#ifdef PRIM_TRI
float d =
min(inpt.edgeDistance[0], min(inpt.edgeDistance[1], inpt.edgeDistance[2]));
#endif
#ifdef PRIM_QUAD
float d =
min(min(inpt.edgeDistance[0], inpt.edgeDistance[1]),
min(inpt.edgeDistance[2], inpt.edgeDistance[3]));
#endif
float v = 0.8;
vec4 Cedge = vec4(Cfill.r*v, Cfill.g*v, Cfill.b*v, 1);
float p = exp2(-2 * d * d);
#if defined(GEOMETRY_OUT_WIRE)
if (p < 0.25) discard;
#endif
Cfill.rgb = mix(Cfill.rgb, Cedge.rgb, p);
#endif
return Cfill;
}
#if defined(PRIM_QUAD) || defined(PRIM_TRI)
void
main()
{
vec3 N = (gl_FrontFacing ? inpt.v.normal : -inpt.v.normal);
float d = dot(N, vec3(0,0,1));
#if defined(DISPLAY_MODE_VARYING)
vec4 color = vec4(inpt.color, 1);
#else
vec4 color = diffuseColor;
#endif
vec4 Cf = color * d;
#if defined(GEOMETRY_OUT_WIRE) || defined(GEOMETRY_OUT_LINE)
Cf = edgeColor(Cf, inpt.edgeDistance);
#endif
#if defined(DISPLAY_MODE_NORMAL)
outColor = vec4(N.x, N.y, N.z, 1);
return;
#endif
outColor = Cf;
}
#endif
#endif

View File

@ -0,0 +1,697 @@
/* stb_image_write - v0.97 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
no warranty implied; use at your own risk
Before #including,
#define STB_IMAGE_WRITE_IMPLEMENTATION
in the file that you want to have the implementation.
Will probably not work correctly with strict-aliasing optimizations.
ABOUT:
This header file is a library for writing images to C stdio. It could be
adapted to write to memory or a general streaming interface; let me know.
The PNG output is not optimal; it is 20-50% larger than the file
written by a decent optimizing implementation. This library is designed
for source code compactness and simplicitly, not optimal image file size
or run-time performance.
USAGE:
There are four functions, one for each image file format:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_hdr(char const *filename, int w, int h, int comp, const void *data);
Each function returns 0 on failure and non-0 on success.
The functions create an image file defined by the parameters. The image
is a rectangle of pixels stored from left-to-right, top-to-bottom.
Each pixel contains 'comp' channels of data stored interleaved with 8-bits
per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
The *data pointer points to the first byte of the top-left-most pixel.
For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
a row of pixels to the first byte of the next row of pixels.
PNG creates output files with the same number of components as the input.
The BMP format expands Y to RGB in the file format and does not
output alpha.
PNG supports writing rectangles of data even when the bytes storing rows of
data are not consecutive in memory (e.g. sub-rectangles of a larger image),
by supplying the stride between the beginning of adjacent rows. The other
formats do not. (Thus you cannot write a native-format BMP through the BMP
writer, both because it is in BGR order and because it may have padding
at the end of the line.)
HDR expects linear float data. Since the format is always 32-bit rgb(e)
data, alpha (if provided) is discarded, and for monochrome data it is
replicated across all three channels.
CREDITS:
PNG/BMP/TGA
Sean Barrett
HDR
Baldur Karlsson
TGA monochrome:
Jean-Sebastien Guay
Bugfixes:
Chribba@github
*/
#ifndef INCLUDE_STB_IMAGE_WRITE_H
#define INCLUDE_STB_IMAGE_WRITE_H
#ifdef __cplusplus
extern "C" {
#endif
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
#ifdef __cplusplus
}
#endif
#endif//INCLUDE_STB_IMAGE_WRITE_H
#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <math.h>
typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
static void writefv(FILE *f, const char *fmt, va_list v)
{
while (*fmt) {
switch (*fmt++) {
case ' ': break;
case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; }
case '2': { int x = va_arg(v,int); unsigned char b[2];
b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8);
fwrite(b,2,1,f); break; }
case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4];
b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8);
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
fwrite(b,4,1,f); break; }
default:
assert(0);
return;
}
}
}
static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
{
unsigned char arr[3];
arr[0] = a, arr[1] = b, arr[2] = c;
fwrite(arr, 3, 1, f);
}
static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
{
unsigned char bg[3] = { 255, 0, 255}, px[3];
stbiw_uint32 zero = 0;
int i,j,k, j_end;
if (y <= 0)
return;
if (vdir < 0)
j_end = -1, j = y-1;
else
j_end = y, j = 0;
for (; j != j_end; j += vdir) {
for (i=0; i < x; ++i) {
unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
if (write_alpha < 0)
fwrite(&d[comp-1], 1, 1, f);
switch (comp) {
case 1: fwrite(d, 1, 1, f);
break;
case 2: if (expand_mono)
write3(f, d[0],d[0],d[0]); // monochrome bmp
else
fwrite(d, 1, 1, f); // monochrome TGA
break;
case 4:
if (!write_alpha) {
// composite against pink background
for (k=0; k < 3; ++k)
px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255;
write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]);
break;
}
/* FALLTHROUGH */
case 3:
write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]);
break;
}
if (write_alpha > 0)
fwrite(&d[comp-1], 1, 1, f);
}
fwrite(&zero,scanline_pad,1,f);
}
}
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
{
FILE *f;
if (y < 0 || x < 0) return 0;
f = fopen(filename, "wb");
if (f) {
va_list v;
va_start(v, fmt);
writefv(f, fmt, v);
va_end(v);
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad,expand_mono);
fclose(f);
}
return f != NULL;
}
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
{
int pad = (-x*3) & 3;
return outfile(filename,-1,-1,x,y,comp,1,(void *) data,0,pad,
"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
}
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
{
int has_alpha = (comp == 2 || comp == 4);
int colorbytes = has_alpha ? comp-1 : comp;
int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
return outfile(filename, -1,-1, x, y, comp, 0, (void *) data, has_alpha, 0,
"111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, (colorbytes+has_alpha)*8, has_alpha*8);
}
// *************************************************************************************************
// Radiance RGBE HDR writer
// by Baldur Karlsson
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
{
int exponent;
float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
if (maxcomp < 1e-32) {
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
} else {
float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
rgbe[0] = (unsigned char)(linear[0] * normalize);
rgbe[1] = (unsigned char)(linear[1] * normalize);
rgbe[2] = (unsigned char)(linear[2] * normalize);
rgbe[3] = (unsigned char)(exponent + 128);
}
}
void stbiw__write_run_data(FILE *f, int length, unsigned char databyte)
{
unsigned char lengthbyte = (unsigned char) (length+128);
assert(length+128 <= 255);
fwrite(&lengthbyte, 1, 1, f);
fwrite(&databyte, 1, 1, f);
}
void stbiw__write_dump_data(FILE *f, int length, unsigned char *data)
{
unsigned char lengthbyte = (unsigned char )(length & 0xff);
assert(length <= 128); // inconsistent with spec but consistent with official code
fwrite(&lengthbyte, 1, 1, f);
fwrite(data, length, 1, f);
}
void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scratch, const float *scanline)
{
unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
unsigned char rgbe[4];
float linear[3];
int x;
scanlineheader[2] = (width&0xff00)>>8;
scanlineheader[3] = (width&0x00ff);
/* skip RLE for images too small or large */
if (width < 8 || width >= 32768) {
for (x=0; x < width; x++) {
switch (comp) {
case 4: /* fallthrough */
case 3: linear[2] = scanline[x*comp + 2];
linear[1] = scanline[x*comp + 1];
linear[0] = scanline[x*comp + 0];
break;
case 2: /* fallthrough */
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
break;
}
stbiw__linear_to_rgbe(rgbe, linear);
fwrite(rgbe, 4, 1, f);
}
} else {
int c,r;
/* encode into scratch buffer */
for (x=0; x < width; x++) {
switch(comp) {
case 4: /* fallthrough */
case 3: linear[2] = scanline[x*comp + 2];
linear[1] = scanline[x*comp + 1];
linear[0] = scanline[x*comp + 0];
break;
case 2: /* fallthrough */
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
break;
}
stbiw__linear_to_rgbe(rgbe, linear);
scratch[x + width*0] = rgbe[0];
scratch[x + width*1] = rgbe[1];
scratch[x + width*2] = rgbe[2];
scratch[x + width*3] = rgbe[3];
}
fwrite(scanlineheader, 4, 1, f);
/* RLE each component separately */
for (c=0; c < 4; c++) {
unsigned char *comp = &scratch[width*c];
x = 0;
while (x < width) {
// find first run
r = x;
while (r+2 < width) {
if (comp[r] == comp[r+1] && comp[r] == comp[r+2])
break;
++r;
}
if (r+2 >= width)
r = width;
// dump up to first run
while (x < r) {
int len = r-x;
if (len > 128) len = 128;
stbiw__write_dump_data(f, len, &comp[x]);
x += len;
}
// if there's a run, output it
if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
// find next byte after run
while (r < width && comp[r] == comp[x])
++r;
// output run up to r
while (x < r) {
int len = r-x;
if (len > 127) len = 127;
stbiw__write_run_data(f, len, comp[x]);
x += len;
}
}
}
}
}
}
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
{
int i;
FILE *f;
if (y <= 0 || x <= 0 || data == NULL) return 0;
f = fopen(filename, "wb");
if (f) {
/* Each component is stored separately. Allocate scratch space for full output scanline. */
unsigned char *scratch = (unsigned char *) malloc(x*4);
fprintf(f, "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n" );
fprintf(f, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n" , y, x);
for(i=0; i < y; i++)
stbiw__write_hdr_scanline(f, x, comp, scratch, data + comp*i*x);
free(scratch);
fclose(f);
}
return f != NULL;
}
/////////////////////////////////////////////////////////
// PNG
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (a) - 2)
#define stbiw__sbm(a) stbiw__sbraw(a)[0]
#define stbiw__sbn(a) stbiw__sbraw(a)[1]
#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
#define stbiw__sbfree(a) ((a) ? free(stbiw__sbraw(a)),0 : 0)
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
{
int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
void *p = realloc(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
assert(p);
if (p) {
if (!*arr) ((int *) p)[1] = 0;
*arr = (void *) ((int *) p + 2);
stbiw__sbm(*arr) = m;
}
return *arr;
}
static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
{
while (*bitcount >= 8) {
stbiw__sbpush(data, (unsigned char) *bitbuffer);
*bitbuffer >>= 8;
*bitcount -= 8;
}
return data;
}
static int stbiw__zlib_bitrev(int code, int codebits)
{
int res=0;
while (codebits--) {
res = (res << 1) | (code & 1);
code >>= 1;
}
return res;
}
static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
{
int i;
for (i=0; i < limit && i < 258; ++i)
if (a[i] != b[i]) break;
return i;
}
static unsigned int stbiw__zhash(unsigned char *data)
{
stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
#define stbiw__zlib_add(code,codebits) \
(bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
// default huffman tables
#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)
#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)
#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)
#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8)
#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n))
#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
#define stbiw__ZHASH 16384
unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
{
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };
unsigned int bitbuf=0;
int i,j, bitcount=0;
unsigned char *out = NULL;
unsigned char **hash_table[stbiw__ZHASH]; // 64KB on the stack!
if (quality < 5) quality = 5;
stbiw__sbpush(out, 0x78); // DEFLATE 32K window
stbiw__sbpush(out, 0x5e); // FLEVEL = 1
stbiw__zlib_add(1,1); // BFINAL = 1
stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman
for (i=0; i < stbiw__ZHASH; ++i)
hash_table[i] = NULL;
i=0;
while (i < data_len-3) {
// hash next 3 bytes of data to be compressed
int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
unsigned char *bestloc = 0;
unsigned char **hlist = hash_table[h];
int n = stbiw__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32768) { // if entry lies within window
int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
if (d >= best) best=d,bestloc=hlist[j];
}
}
// when hash table entry is too long, delete half the entries
if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
memcpy(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
stbiw__sbn(hash_table[h]) = quality;
}
stbiw__sbpush(hash_table[h],data+i);
if (bestloc) {
// "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
hlist = hash_table[h];
n = stbiw__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32767) {
int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
if (e > best) { // if next match is better, bail on current match
bestloc = NULL;
break;
}
}
}
}
if (bestloc) {
int d = (int) (data+i - bestloc); // distance back
assert(d <= 32767 && best <= 258);
for (j=0; best > lengthc[j+1]-1; ++j);
stbiw__zlib_huff(j+257);
if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
for (j=0; d > distc[j+1]-1; ++j);
stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);
if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
i += best;
} else {
stbiw__zlib_huffb(data[i]);
++i;
}
}
// write out final bytes
for (;i < data_len; ++i)
stbiw__zlib_huffb(data[i]);
stbiw__zlib_huff(256); // end of block
// pad with 0 bits to byte boundary
while (bitcount)
stbiw__zlib_add(0,1);
for (i=0; i < stbiw__ZHASH; ++i)
(void) stbiw__sbfree(hash_table[i]);
{
// compute adler32 on input
unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552;
int j=0;
while (j < data_len) {
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
s1 %= 65521, s2 %= 65521;
j += blocklen;
blocklen = 5552;
}
stbiw__sbpush(out, (unsigned char) (s2 >> 8));
stbiw__sbpush(out, (unsigned char) s2);
stbiw__sbpush(out, (unsigned char) (s1 >> 8));
stbiw__sbpush(out, (unsigned char) s1);
}
*out_len = stbiw__sbn(out);
// make returned pointer freeable
memmove(stbiw__sbraw(out), out, *out_len);
return (unsigned char *) stbiw__sbraw(out);
}
unsigned int stbiw__crc32(unsigned char *buffer, int len)
{
static unsigned int crc_table[256];
unsigned int crc = ~0u;
int i,j;
if (crc_table[1] == 0)
for(i=0; i < 256; i++)
for (crc_table[i]=i, j=0; j < 8; ++j)
crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
for (i=0; i < len; ++i)
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
return ~crc;
}
#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4)
#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
static void stbiw__wpcrc(unsigned char **data, int len)
{
unsigned int crc = stbiw__crc32(*data - len - 4, len+4);
stbiw__wp32(*data, crc);
}
static unsigned char stbiw__paeth(int a, int b, int c)
{
int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
if (pa <= pb && pa <= pc) return (unsigned char) a;
if (pb <= pc) return (unsigned char) b;
return (unsigned char) c;
}
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
{
int ctype[5] = { -1, 0, 4, 2, 6 };
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
unsigned char *out,*o, *filt, *zlib;
signed char *line_buffer;
int i,j,k,p,zlen;
if (stride_bytes == 0)
stride_bytes = x * n;
filt = (unsigned char *) malloc((x*n+1) * y); if (!filt) return 0;
line_buffer = (signed char *) malloc(x * n); if (!line_buffer) { free(filt); return 0; }
for (j=0; j < y; ++j) {
static int mapping[] = { 0,1,2,3,4 };
static int firstmap[] = { 0,1,0,5,6 };
int *mymap = j ? mapping : firstmap;
int best = 0, bestval = 0x7fffffff;
for (p=0; p < 2; ++p) {
for (k= p?best:0; k < 5; ++k) {
int type = mymap[k],est=0;
unsigned char *z = pixels + stride_bytes*j;
for (i=0; i < n; ++i)
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
case 5: line_buffer[i] = z[i]; break;
case 6: line_buffer[i] = z[i]; break;
}
for (i=n; i < x*n; ++i) {
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i] - z[i-n]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
}
}
if (p) break;
for (i=0; i < x*n; ++i)
est += abs((signed char) line_buffer[i]);
if (est < bestval) { bestval = est; best = k; }
}
}
// when we get here, best contains the filter type, and line_buffer contains the data
filt[j*(x*n+1)] = (unsigned char) best;
memcpy(filt+j*(x*n+1)+1, line_buffer, x*n);
}
free(line_buffer);
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
free(filt);
if (!zlib) return 0;
// each tag requires 12 bytes of overhead
out = (unsigned char *) malloc(8 + 12+13 + 12+zlen + 12);
if (!out) return 0;
*out_len = 8 + 12+13 + 12+zlen + 12;
o=out;
memcpy(o,sig,8); o+= 8;
stbiw__wp32(o, 13); // header length
stbiw__wptag(o, "IHDR");
stbiw__wp32(o, x);
stbiw__wp32(o, y);
*o++ = 8;
*o++ = (unsigned char) ctype[n];
*o++ = 0;
*o++ = 0;
*o++ = 0;
stbiw__wpcrc(&o,13);
stbiw__wp32(o, zlen);
stbiw__wptag(o, "IDAT");
memcpy(o, zlib, zlen); o += zlen; free(zlib);
stbiw__wpcrc(&o, zlen);
stbiw__wp32(o,0);
stbiw__wptag(o, "IEND");
stbiw__wpcrc(&o,0);
assert(o == out + *out_len);
return out;
}
int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
{
FILE *f;
int len;
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
if (!png) return 0;
f = fopen(filename, "wb");
if (!f) { free(png); return 0; }
fwrite(png, 1, len, f);
fclose(f);
free(png);
return 1;
}
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history
0.97 (2015-01-18)
fixed HDR asserts, rewrote HDR rle logic
0.96 (2015-01-17)
add HDR output
fix monochrome BMP
0.95 (2014-08-17)
add monochrome TGA output
0.94 (2014-05-31)
rename private functions to avoid conflicts with stb_image.h
0.93 (2014-05-27)
warning fixes
0.92 (2010-08-01)
casts to unsigned char to fix warnings
0.91 (2010-07-17)
first public release
0.90 first internal release
*/

View File

@ -46,6 +46,7 @@ GLFWmonitor* g_primary=0;
#include <osd/glDrawContext.h>
#include <osd/glDrawRegistry.h>
#include <far/error.h>
#include <far/ptexIndices.h>
#include <osd/cpuGLVertexBuffer.h>
#include <osd/cpuComputeContext.h>
@ -229,7 +230,8 @@ createOsdMesh() {
OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Options(sdctype, sdcoptions));
// count ptex face id
int numPtexFaces = refiner->GetNumPtexFaces();
OpenSubdiv::Far::PtexIndices ptexIndices(*refiner);
int numPtexFaces = ptexIndices.GetNumFaces();
delete g_mesh;
g_mesh = NULL;

View File

@ -1033,7 +1033,7 @@ createOsdMesh(int level, int kernel) {
OpenSubdiv::Osd::MeshBitset bits;
bits.set(OpenSubdiv::Osd::MeshAdaptive, doAdaptive);
bits.set(OpenSubdiv::Osd::MeshPtexData, true);
bits.set(OpenSubdiv::Osd::MeshUseGregoryBasis, true);
bits.set(OpenSubdiv::Osd::MeshEndCapGregoryBasis, true);
int numVertexElements = g_adaptive ? 3 : 6;
int numVaryingElements = 0;
@ -1755,7 +1755,7 @@ drawCageEdges() {
typedef OpenSubdiv::Far::PatchDescriptor FDesc;
OpenSubdiv::Osd::DrawContext::PatchDescriptor desc(
FDesc(FDesc::LINES, FDesc::NON_TRANSITION, 0), 0, 0, 0);
FDesc(FDesc::LINES), 0, 0);
EffectDrawRegistry::ConfigType *config = getInstance(effect, desc);
glUseProgram(config->program);

View File

@ -423,7 +423,85 @@ layout(std140) uniform Lighting {
};
#if defined COLOR_PATCHTYPE
uniform vec4 overrideColor;
vec4
GetOverrideColor(int patchParam)
{
const vec4 patchColors[7*6] = vec4[7*6](
vec4(1.0f, 1.0f, 1.0f, 1.0f), // regular
vec4(0.0f, 1.0f, 1.0f, 1.0f), // regular pattern 0
vec4(0.0f, 0.5f, 1.0f, 1.0f), // regular pattern 1
vec4(0.0f, 0.5f, 0.5f, 1.0f), // regular pattern 2
vec4(0.5f, 0.0f, 1.0f, 1.0f), // regular pattern 3
vec4(1.0f, 0.5f, 1.0f, 1.0f), // regular pattern 4
vec4(1.0f, 0.5f, 0.5f, 1.0f), // single crease
vec4(1.0f, 0.70f, 0.6f, 1.0f), // single crease pattern 0
vec4(1.0f, 0.65f, 0.6f, 1.0f), // single crease pattern 1
vec4(1.0f, 0.60f, 0.6f, 1.0f), // single crease pattern 2
vec4(1.0f, 0.55f, 0.6f, 1.0f), // single crease pattern 3
vec4(1.0f, 0.50f, 0.6f, 1.0f), // single crease pattern 4
vec4(0.8f, 0.0f, 0.0f, 1.0f), // boundary
vec4(0.0f, 0.0f, 0.75f, 1.0f), // boundary pattern 0
vec4(0.0f, 0.2f, 0.75f, 1.0f), // boundary pattern 1
vec4(0.0f, 0.4f, 0.75f, 1.0f), // boundary pattern 2
vec4(0.0f, 0.6f, 0.75f, 1.0f), // boundary pattern 3
vec4(0.0f, 0.8f, 0.75f, 1.0f), // boundary pattern 4
vec4(0.0f, 1.0f, 0.0f, 1.0f), // corner
vec4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 0
vec4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 1
vec4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 2
vec4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 3
vec4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 4
vec4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
vec4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
vec4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
vec4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
vec4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
vec4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
vec4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
vec4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
vec4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
vec4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
vec4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
vec4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
vec4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
vec4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
vec4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
vec4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
vec4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
vec4(1.0f, 0.7f, 0.3f, 1.0f) // gregory basis
);
int patchType = 0;
#if defined OSD_PATCH_SINGLE_CREASE
patchType = 1;
#elif defined OSD_PATCH_GREGORY
patchType = 4;
#elif defined OSD_PATCH_GREGORY_BOUNDARY
patchType = 5;
#elif defined OSD_PATCH_GREGORY_BASIS
patchType = 6;
#endif
int edgeCount = bitCount((patchParam >> 4) & 0xf);
if (edgeCount == 1) {
patchType = 2; // BOUNDARY
}
if (edgeCount == 2) {
patchType = 3; // CORNER
}
int pattern = bitCount((patchParam >> 8) & 0xf);
int offset = 7*patchType + pattern;
return patchColors[offset];
}
#endif
#if defined(NORMAL_HW_SCREENSPACE) || defined(NORMAL_SCREENSPACE)
@ -597,7 +675,7 @@ main()
textureImage_Data,
textureImage_Packing);
#elif defined COLOR_PATCHTYPE
vec4 texColor = edgeColor(lighting(overrideColor, inpt.v.position.xyz, normal, 1, 0));
vec4 texColor = edgeColor(lighting(GetOverrideColor(GetPatchParam()), inpt.v.position.xyz, normal, 1, 0));
outColor = texColor;
return;
#elif defined COLOR_PATCHCOORD

View File

@ -47,6 +47,7 @@ GLFWmonitor* g_primary=0;
#include <osd/glDrawRegistry.h>
#include <osd/glMesh.h>
#include <far/error.h>
#include <far/ptexIndices.h>
#include <osd/cpuGLVertexBuffer.h>
#include <osd/cpuComputeContext.h>
@ -295,8 +296,6 @@ public:
_computeContext = ComputeContext::Create(vertexStencils, varyingStencils);
_kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils));
_numVertices = vertexStencils->GetNumStencils() +
vertexStencils->GetNumControlVertices();
}
@ -328,7 +327,6 @@ public:
globalVaryingDesc.stride);
_computeController.Compute(_computeContext,
_kernelBatches,
typedInstance->GetVertexBuffer(),
typedInstance->GetVaryingBuffer(),
&vertexDesc,
@ -364,7 +362,6 @@ public:
private:
COMPUTE_CONTROLLER _computeController;
ComputeContext *_computeContext;
Far::KernelBatchVector _kernelBatches;
};
// ---------------------------------------------------------------------------
@ -394,8 +391,6 @@ Topology(Far::PatchTables const * patchTables,
_computeContext = ComputeContext::Create(g_clContext, vertexStencils, varyingStencils);
_kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils));
_numVertices = vertexStencils->GetNumStencils() +
vertexStencils->GetNumControlVertices();
}
@ -594,7 +589,8 @@ createOsdMesh( const std::string &shapeStr, int level, Scheme scheme=kCatmark )
}
// create ptex index to coarse face index mapping
int numPtexFaces = refiner->GetNumPtexFaces();
Far::PtexIndices ptexIndices(*refiner);
int numPtexFaces = ptexIndices.GetNumFaces();
// XXX: duped logic to simpleHbr
std::vector<int> ptexIndexToFaceMapping(numPtexFaces);

View File

@ -49,6 +49,7 @@ GLFWmonitor* g_primary=0;
#include "../common/gl_hud.h"
#include <far/patchTablesFactory.h>
#include <far/ptexIndices.h>
#include <far/stencilTablesFactory.h>
#include <osd/cpuGLVertexBuffer.h>
@ -327,7 +328,8 @@ createMesh(ShapeDesc const & shapeDesc, int level) {
refiner->RefineAdaptive(options);
}
int nfaces = refiner->GetNumPtexFaces();
Far::PtexIndices ptexIndices(*refiner);
int nfaces = ptexIndices.GetNumFaces();
float * u = new float[g_nsamples*nfaces], * uPtr = u,
* v = new float[g_nsamples*nfaces], * vPtr = v;

View File

@ -141,6 +141,11 @@ enum DisplayStyle { kWire = 0,
kInterleavedVaryingColor,
kFaceVaryingColor };
enum EndCap { kEndCapNone = 0,
kEndCapRegular,
kEndCapGregoryBasis,
kEndCapLegacyGregory };
enum HudCheckBox { kHUD_CB_DISPLAY_CAGE_EDGES,
kHUD_CB_DISPLAY_CAGE_VERTS,
kHUD_CB_ANIMATE_VERTICES,
@ -149,7 +154,9 @@ enum HudCheckBox { kHUD_CB_DISPLAY_CAGE_EDGES,
kHUD_CB_FRACTIONAL_SPACING,
kHUD_CB_PATCH_CULL,
kHUD_CB_FREEZE,
kHUD_CB_DISPLAY_PATCH_COUNTS };
kHUD_CB_DISPLAY_PATCH_COUNTS,
kHUD_CB_ADAPTIVE,
kHUD_CB_SINGLE_CREASE_PATCH };
int g_currentShape = 0;
@ -166,6 +173,7 @@ int g_fullscreen = 0,
g_freeze = 0,
g_displayStyle = kWireShaded,
g_adaptive = 1,
g_endCap = kEndCapRegular,
g_singleCreasePatch = 1,
g_drawCageEdges = 1,
g_drawCageVertices = 0,
@ -176,7 +184,7 @@ int g_displayPatchColor = 1,
g_screenSpaceTess = 1,
g_fractionalSpacing = 1,
g_patchCull = 0,
g_displayPatchCounts = 0;
g_displayPatchCounts = 1;
float g_rotate[2] = {0, 0},
g_dolly = 5,
@ -535,7 +543,9 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level, int kernel, Scheme scheme=
bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, doSingleCreasePatch);
bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, interleaveVarying);
bits.set(OpenSubdiv::Osd::MeshFVarData, g_displayStyle == kFaceVaryingColor);
bits.set(OpenSubdiv::Osd::MeshUseGregoryBasis, true);
bits.set(OpenSubdiv::Osd::MeshEndCapRegular, g_endCap == kEndCapRegular);
bits.set(OpenSubdiv::Osd::MeshEndCapLegacyGregory, g_endCap == kEndCapLegacyGregory);
bits.set(OpenSubdiv::Osd::MeshEndCapGregoryBasis, g_endCap == kEndCapGregoryBasis);
int numVertexElements = 3;
int numVaryingElements =
@ -1158,7 +1168,7 @@ display() {
g_mesh->GetDrawContext()->GetPatchArrays();
// patch drawing
int patchCount[13][6][4]; // [Type][Pattern][Rotation] (see far/patchTables.h)
int patchCount[13]; // [Type] (see far/patchTables.h)
int numTotalPatches = 0;
int numDrawCalls = 0;
memset(patchCount, 0, sizeof(patchCount));
@ -1174,13 +1184,8 @@ display() {
OpenSubdiv::Osd::DrawContext::PatchDescriptor desc = patch.GetDescriptor();
OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType();
int patchPattern = desc.GetPattern();
int patchRotation = desc.GetRotation();
int subPatch = desc.GetSubPatch();
if (subPatch == 0) {
patchCount[patchType][patchPattern][patchRotation] += patch.GetNumPatches();
}
patchCount[patchType] += patch.GetNumPatches();
numTotalPatches += patch.GetNumPatches();
GLenum primType;
@ -1286,50 +1291,21 @@ display() {
if (g_displayPatchCounts) {
int x = -280;
int y = -480;
int y = -180;
g_hud.DrawString(x, y, "NonPatch : %d",
patchCount[Descriptor::QUADS][0][0]); y += 20;
patchCount[Descriptor::QUADS]); y += 20;
g_hud.DrawString(x, y, "Regular : %d",
patchCount[Descriptor::REGULAR][0][0]); y+= 20;
patchCount[Descriptor::REGULAR]); y+= 20;
g_hud.DrawString(x, y, "Boundary : %d",
patchCount[Descriptor::BOUNDARY][0][0]); y+= 20;
patchCount[Descriptor::BOUNDARY]); y+= 20;
g_hud.DrawString(x, y, "Corner : %d",
patchCount[Descriptor::CORNER][0][0]); y+= 20;
g_hud.DrawString(x, y, "Single Crease : %d",
patchCount[Descriptor::SINGLE_CREASE][0][0]); y+= 20;
patchCount[Descriptor::CORNER]); y+= 20;
g_hud.DrawString(x, y, "Gregory : %d",
patchCount[Descriptor::GREGORY][0][0]); y+= 20;
patchCount[Descriptor::GREGORY]); y+= 20;
g_hud.DrawString(x, y, "Boundary Gregory : %d",
patchCount[Descriptor::GREGORY_BOUNDARY][0][0]); y+= 20;
patchCount[Descriptor::GREGORY_BOUNDARY]); y+= 20;
g_hud.DrawString(x, y, "Gregory Basis : %d",
patchCount[Descriptor::GREGORY_BASIS][0][0]); y+= 20;
g_hud.DrawString(x, y, "Trans. Regular : %d %d %d %d %d",
patchCount[Descriptor::REGULAR][Descriptor::PATTERN0][0],
patchCount[Descriptor::REGULAR][Descriptor::PATTERN1][0],
patchCount[Descriptor::REGULAR][Descriptor::PATTERN2][0],
patchCount[Descriptor::REGULAR][Descriptor::PATTERN3][0],
patchCount[Descriptor::REGULAR][Descriptor::PATTERN4][0]); y+= 20;
for (int i=0; i < 5; i++) {
g_hud.DrawString(x, y, "Trans. Boundary%d : %d %d %d %d", i,
patchCount[Descriptor::BOUNDARY][i+1][0],
patchCount[Descriptor::BOUNDARY][i+1][1],
patchCount[Descriptor::BOUNDARY][i+1][2],
patchCount[Descriptor::BOUNDARY][i+1][3]); y+= 20;
}
for (int i=0; i < 5; i++) {
g_hud.DrawString(x, y, "Trans. Corner%d : %d %d %d %d", i,
patchCount[Descriptor::CORNER][i+1][0],
patchCount[Descriptor::CORNER][i+1][1],
patchCount[Descriptor::CORNER][i+1][2],
patchCount[Descriptor::CORNER][i+1][3]); y+= 20;
}
for (int i=0; i < 5; i++) {
g_hud.DrawString(x, y, "Trans. Single Crease%d : %d %d %d %d", i,
patchCount[Descriptor::SINGLE_CREASE][i+1][0],
patchCount[Descriptor::SINGLE_CREASE][i+1][1],
patchCount[Descriptor::SINGLE_CREASE][i+1][2],
patchCount[Descriptor::SINGLE_CREASE][i+1][3]); y+= 20;
}
patchCount[Descriptor::GREGORY_BASIS]); y+= 20;
}
int y = -220;
@ -1500,6 +1476,12 @@ callbackDisplayStyle(int b) {
g_displayStyle = b;
}
static void
callbackEndCap(int endCap) {
g_endCap = endCap;
rebuildOsdMesh();
}
static void
callbackKernel(int k) {
g_kernel = k;
@ -1540,24 +1522,24 @@ callbackModel(int m) {
rebuildOsdMesh();
}
static void
callbackAdaptive(bool checked, int /* a */) {
if (OpenSubdiv::Osd::GLDrawContext::SupportsAdaptiveTessellation()) {
g_adaptive = checked;
rebuildOsdMesh();
}
}
static void
callbackSingleCreasePatch(bool checked, int /* a */) {
if (OpenSubdiv::Osd::GLDrawContext::SupportsAdaptiveTessellation()) {
g_singleCreasePatch = checked;
rebuildOsdMesh();
}
}
static void
callbackCheckBox(bool checked, int button) {
if (OpenSubdiv::Osd::GLDrawContext::SupportsAdaptiveTessellation()) {
switch(button) {
case kHUD_CB_ADAPTIVE:
g_adaptive = checked;
rebuildOsdMesh();
return;
case kHUD_CB_SINGLE_CREASE_PATCH:
g_singleCreasePatch = checked;
rebuildOsdMesh();
return;
default:
break;
}
}
switch (button) {
case kHUD_CB_DISPLAY_CAGE_EDGES:
g_drawCageEdges = checked;
@ -1653,14 +1635,31 @@ initHUD() {
}
#endif
if (OpenSubdiv::Osd::GLDrawContext::SupportsAdaptiveTessellation()) {
g_hud.AddCheckBox("Adaptive (`)", g_adaptive!=0, 10, 190, callbackAdaptive, 0, '`');
g_hud.AddCheckBox("Single Crease Patch (S)", g_singleCreasePatch!=0, 10, 210, callbackSingleCreasePatch, 0, 's');
g_hud.AddCheckBox("Adaptive (`)", g_adaptive!=0,
10, 190, callbackCheckBox, kHUD_CB_ADAPTIVE, '`');
g_hud.AddCheckBox("Single Crease Patch (S)", g_singleCreasePatch!=0,
10, 210, callbackCheckBox, kHUD_CB_SINGLE_CREASE_PATCH, 's');
int endcap_pulldown = g_hud.AddPullDown(
"End cap (E)", 10, 230, 200, callbackEndCap, 'e');
g_hud.AddPullDownButton(endcap_pulldown,"None",
kEndCapNone,
g_endCap == kEndCapNone);
g_hud.AddPullDownButton(endcap_pulldown, "Regular",
kEndCapRegular,
g_endCap == kEndCapRegular);
g_hud.AddPullDownButton(endcap_pulldown, "GregoryBasis",
kEndCapGregoryBasis,
g_endCap == kEndCapGregoryBasis);
g_hud.AddPullDownButton(endcap_pulldown, "LegacyGregory",
kEndCapLegacyGregory,
g_endCap == kEndCapLegacyGregory);
}
for (int i = 1; i < 11; ++i) {
char level[16];
sprintf(level, "Lv. %d", i);
g_hud.AddRadioButton(3, level, i==2, 10, 210+i*20, callbackLevel, i, '0'+(i%10));
g_hud.AddRadioButton(3, level, i==2, 10, 310+i*20, callbackLevel, i, '0'+(i%10));
}
int shapes_pulldown = g_hud.AddPullDown("Shape (N)", -300, 10, 300, callbackModel, 'n');

View File

@ -149,12 +149,18 @@ void main()
layout(triangle_strip, max_vertices = EDGE_VERTS) out;
in block {
OutputVertex v;
#ifdef OSD_PATCH_ENABLE_SINGLE_CREASE
float sharpness;
#endif
OSD_USER_VARYING_DECLARE
} inpt[EDGE_VERTS];
out block {
OutputVertex v;
noperspective out vec4 edgeDistance;
#ifdef OSD_PATCH_ENABLE_SINGLE_CREASE
float sharpness;
#endif
OSD_USER_VARYING_DECLARE
} outpt;
@ -168,6 +174,10 @@ void emit(int index, vec3 normal)
outpt.v.normal = normal;
#endif
#ifdef OSD_PATCH_ENABLE_SINGLE_CREASE
outpt.sharpness = inpt[index].sharpness;
#endif
#ifdef VARYING_COLOR
outpt.color = inpt[index].color;
#endif
@ -298,6 +308,9 @@ void main()
in block {
OutputVertex v;
noperspective in vec4 edgeDistance;
#ifdef OSD_PATCH_ENABLE_SINGLE_CREASE
float sharpness;
#endif
OSD_USER_VARYING_DECLARE
} inpt;
@ -374,6 +387,85 @@ edgeColor(vec4 Cfill, vec4 edgeDistance)
return Cfill;
}
vec4
getAdaptivePatchColor(int patchParam)
{
const vec4 patchColors[7*6] = vec4[7*6](
vec4(1.0f, 1.0f, 1.0f, 1.0f), // regular
vec4(0.0f, 1.0f, 1.0f, 1.0f), // regular pattern 0
vec4(0.0f, 0.5f, 1.0f, 1.0f), // regular pattern 1
vec4(0.0f, 0.5f, 0.5f, 1.0f), // regular pattern 2
vec4(0.5f, 0.0f, 1.0f, 1.0f), // regular pattern 3
vec4(1.0f, 0.5f, 1.0f, 1.0f), // regular pattern 4
vec4(1.0f, 0.5f, 0.5f, 1.0f), // single crease
vec4(1.0f, 0.70f, 0.6f, 1.0f), // single crease pattern 0
vec4(1.0f, 0.65f, 0.6f, 1.0f), // single crease pattern 1
vec4(1.0f, 0.60f, 0.6f, 1.0f), // single crease pattern 2
vec4(1.0f, 0.55f, 0.6f, 1.0f), // single crease pattern 3
vec4(1.0f, 0.50f, 0.6f, 1.0f), // single crease pattern 4
vec4(0.8f, 0.0f, 0.0f, 1.0f), // boundary
vec4(0.0f, 0.0f, 0.75f, 1.0f), // boundary pattern 0
vec4(0.0f, 0.2f, 0.75f, 1.0f), // boundary pattern 1
vec4(0.0f, 0.4f, 0.75f, 1.0f), // boundary pattern 2
vec4(0.0f, 0.6f, 0.75f, 1.0f), // boundary pattern 3
vec4(0.0f, 0.8f, 0.75f, 1.0f), // boundary pattern 4
vec4(0.0f, 1.0f, 0.0f, 1.0f), // corner
vec4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 0
vec4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 1
vec4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 2
vec4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 3
vec4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 4
vec4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
vec4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
vec4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
vec4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
vec4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
vec4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
vec4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
vec4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
vec4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
vec4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
vec4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
vec4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
vec4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
vec4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
vec4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
vec4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
vec4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
vec4(1.0f, 0.7f, 0.3f, 1.0f) // gregory basis
);
int patchType = 0;
#if defined OSD_PATCH_GREGORY
patchType = 4;
#elif defined OSD_PATCH_GREGORY_BOUNDARY
patchType = 5;
#elif defined OSD_PATCH_GREGORY_BASIS
patchType = 6;
#endif
int edgeCount = bitCount((patchParam >> 4) & 0xf);
if (edgeCount == 1) {
patchType = 2; // BOUNDARY
}
if (edgeCount == 2) {
patchType = 3; // CORNER
}
int pattern = bitCount((patchParam >> 8) & 0xf);
#ifdef OSD_PATCH_ENABLE_SINGLE_CREASE
if (inpt.sharpness > 0) pattern += 6;
#endif
return patchColors[6*patchType + pattern];
}
#if defined(PRIM_QUAD) || defined(PRIM_TRI)
void
main()
@ -387,7 +479,8 @@ main()
vec4 color = vec4(inpt.color.rg,
int(floor(20*inpt.color.r)+floor(20*inpt.color.g))&1, 1);
#else
vec4 color = diffuseColor;
//vec4 color = diffuseColor;
vec4 color = getAdaptivePatchColor(GetPatchParam());
#endif
vec4 Cf = lighting(color, inpt.v.position.xyz, N);

View File

@ -486,7 +486,7 @@ GLMesh::InitializeFVar(Options options, TopologyRefiner const & refiner,
if (OpenSubdiv::Far::PatchDescriptor::IsAdaptive(type)) {
color = getAdaptivePatchColor(
OpenSubdiv::Far::PatchDescriptor(type, 0, 0));
OpenSubdiv::Far::PatchDescriptor(type));
} else {
static float quadColor[3] = { 1.0f, 1.0f, 0.0f };
color = quadColor;

View File

@ -412,8 +412,11 @@ RefineAdaptive(Hmesh & mesh, int maxlevel,
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
class Far::PatchTablesFactory {
// FIXME:
// XXX: we need this class named PatchTablesFactoryBase because of friend access.
class PatchTablesFactoryBase {
public:
@ -451,15 +454,12 @@ private:
// A convenience container for the different types of feature adaptive patches
template<class TYPE> struct PatchTypes {
static const int NUM_TRANSITIONS=6,
NUM_ROTATIONS=4;
TYPE R[NUM_TRANSITIONS], // regular patch
B[NUM_TRANSITIONS][NUM_ROTATIONS], // boundary patch (4 rotations)
C[NUM_TRANSITIONS][NUM_ROTATIONS], // corner patch (4 rotations)
G, // gregory patch
GB, // gregory boundary patch
GP; // gregory basis
TYPE R, // regular patch
B, // boundary patch (4 rotations)
C, // corner patch (4 rotations)
G, // gregory patch
GB, // gregory boundary patch
GP; // gregory basis
PatchTypes() { memset(this, 0, sizeof(PatchTypes<TYPE>)); }
@ -480,38 +480,28 @@ private:
//------------------------------------------------------------------------------
template <class TYPE> TYPE &
Far::PatchTablesFactory::PatchTypes<TYPE>::getValue( Far::PatchDescriptor desc ) {
Far::PatchTablesFactoryBase::PatchTypes<TYPE>::getValue( Far::PatchDescriptor desc ) {
switch (desc.GetType()) {
case Far::PatchDescriptor::REGULAR : return R[desc.GetPattern()];
case Far::PatchDescriptor::SINGLE_CREASE : break;
case Far::PatchDescriptor::BOUNDARY : return B[desc.GetPattern()][desc.GetRotation()];
case Far::PatchDescriptor::CORNER : return C[desc.GetPattern()][desc.GetRotation()];
case Far::PatchDescriptor::REGULAR : return R;
case Far::PatchDescriptor::BOUNDARY : return B;
case Far::PatchDescriptor::CORNER : return C;
case Far::PatchDescriptor::GREGORY : return G;
case Far::PatchDescriptor::GREGORY_BOUNDARY : return GB;
case Far::PatchDescriptor::GREGORY_BASIS : return GP;
default : assert(0);
}
// can't be reached (suppress compiler warning)
return R[0];
return R;
}
template <class TYPE> int
Far::PatchTablesFactory::PatchTypes<TYPE>::getNumPatchArrays() const {
Far::PatchTablesFactoryBase::PatchTypes<TYPE>::getNumPatchArrays() const {
int result=0;
for (int i=0; i<6; ++i) {
if (R[i]) ++result;
for (int j=0; j<4; ++j) {
if (B[i][j]) ++result;
if (C[i][j]) ++result;
}
}
if (R) ++result;
if (B) ++result;
if (C) ++result;
if (G) ++result;
if (GB) ++result;
@ -522,7 +512,7 @@ Far::PatchTablesFactory::PatchTypes<TYPE>::getNumPatchArrays() const {
// True if the surrounding faces are "tagged" (unsupported feature : watertight
// critical patches)
bool
Far::PatchTablesFactory::vertexHasTaggedNeighbors(Hvertex * v) {
Far::PatchTablesFactoryBase::vertexHasTaggedNeighbors(Hvertex * v) {
assert(v);
@ -546,7 +536,7 @@ Far::PatchTablesFactory::vertexHasTaggedNeighbors(Hvertex * v) {
// Returns a rotation index for boundary patches (range [0-3])
unsigned char
Far::PatchTablesFactory::computeBoundaryPatchRotation( Hface * f ) {
Far::PatchTablesFactoryBase::computeBoundaryPatchRotation( Hface * f ) {
unsigned char rot=0;
for (unsigned char i=0; i<4;++i) {
if (f->GetVertex(i)->OnBoundary() and
@ -559,7 +549,7 @@ Far::PatchTablesFactory::computeBoundaryPatchRotation( Hface * f ) {
// Returns a rotation index for corner patches (range [0-3])
unsigned char
Far::PatchTablesFactory::computeCornerPatchRotation( Hface * f ) {
Far::PatchTablesFactoryBase::computeCornerPatchRotation( Hface * f ) {
unsigned char rot=0;
for (unsigned char i=0; i<4; ++i) {
if (not f->GetVertex((i+3)%4)->OnBoundary())
@ -582,7 +572,7 @@ Far::PatchTablesFactory::getNumPatches( Far::PatchTables::PatchArrayVector const
*/
//------------------------------------------------------------------------------
void
Far::PatchTablesFactory::allocateTables( Far::PatchTables * tables, int /* nlevels */, int fvarwidth ) {
Far::PatchTablesFactoryBase::allocateTables( Far::PatchTables * tables, int /* nlevels */, int fvarwidth ) {
int nverts = 0, npatches = 0;
for (int i=0; i<tables->GetNumPatchArrays(); ++i) {
@ -615,7 +605,7 @@ Far::PatchTablesFactory::allocateTables( Far::PatchTables * tables, int /* nleve
//------------------------------------------------------------------------------
Far::PatchTables const *
Far::PatchTablesFactory::Create(Hmesh & mesh, int maxvalence) {
Far::PatchTablesFactoryBase::Create(Hmesh & mesh, int maxvalence) {
int nfaces = mesh.GetNumFaces();
@ -695,17 +685,17 @@ Far::PatchTablesFactory::Create(Hmesh & mesh, int maxvalence) {
switch (boundaryVerts) {
case 0 : { // Regular patch
patchCtr.R[Far::PatchDescriptor::NON_TRANSITION]++;
patchCtr.R++;
} break;
case 2 : { // Boundary patch
f->_adaptiveFlags.rots=computeBoundaryPatchRotation(f);
patchCtr.B[Far::PatchDescriptor::NON_TRANSITION][0]++;
patchCtr.B++;
} break;
case 3 : { // Corner patch
f->_adaptiveFlags.rots=computeCornerPatchRotation(f);
patchCtr.C[Far::PatchDescriptor::NON_TRANSITION][0]++;
patchCtr.C++;
} break;
default : break;
@ -784,7 +774,7 @@ Far::PatchTablesFactory::Create(Hmesh & mesh, int maxvalence) {
switch (boundaryVerts) {
case 0 : { // regular patch
patchCtr.R[pattern+1]++;
patchCtr.R++;
} break;
case 2 : { // boundary patch
@ -794,7 +784,7 @@ Far::PatchTablesFactory::Create(Hmesh & mesh, int maxvalence) {
f->_adaptiveFlags.rots=rot; // override the transition rotation
patchCtr.B[pattern+1][f->_adaptiveFlags.brots]++;
patchCtr.B++;
} break;
case 3 : { // corner patch
@ -804,7 +794,7 @@ Far::PatchTablesFactory::Create(Hmesh & mesh, int maxvalence) {
f->_adaptiveFlags.rots=rot; // override the transition rotation
patchCtr.C[pattern+1][f->_adaptiveFlags.brots]++;
patchCtr.C++;
} break;
default : assert(0); break;
@ -879,27 +869,24 @@ Far::PatchTablesFactory::Create(Hmesh & mesh, int maxvalence) {
if (f->_adaptiveFlags.patchType==Hface::kFull) {
if (not f->_adaptiveFlags.isExtraordinary and f->_adaptiveFlags.bverts!=1) {
int pattern = Far::PatchDescriptor::NON_TRANSITION,
rot = 0;
switch (f->_adaptiveFlags.bverts) {
case 0 : { // Regular Patch (16 CVs)
iptrs.R[pattern] = getOneRing(f, 16, remapRegular, iptrs.R[0]);
pptrs.R[pattern] = computePatchParam(f, pptrs.R[0]);
iptrs.R = getOneRing(f, 16, remapRegular, iptrs.R);
pptrs.R = computePatchParam(f, pptrs.R);
//fptrs.R[pattern] = computeFVarData(f, fvarwidth, fptrs.R[0], /*isAdaptive=*/true);
} break;
case 2 : { // Boundary Patch (12 CVs)
f->_adaptiveFlags.brots = (f->_adaptiveFlags.rots+1)%4;
iptrs.B[pattern][rot] = getOneRing(f, 12, remapRegularBoundary, iptrs.B[0][0]);
pptrs.B[pattern][rot] = computePatchParam(f, pptrs.B[0][0]);
iptrs.B = getOneRing(f, 12, remapRegularBoundary, iptrs.B);
pptrs.B = computePatchParam(f, pptrs.B);
//fptrs.B[pattern][rot] = computeFVarData(f, fvarwidth, fptrs.B[0][0], /*isAdaptive=*/true);
} break;
case 3 : { // Corner Patch (9 CVs)
f->_adaptiveFlags.brots = (f->_adaptiveFlags.rots+1)%4;
iptrs.C[pattern][rot] = getOneRing(f, 9, remapRegularCorner, iptrs.C[0][0]);
pptrs.C[pattern][rot] = computePatchParam(f, pptrs.C[0][0]);
iptrs.C = getOneRing(f, 9, remapRegularCorner, iptrs.C);
pptrs.C = computePatchParam(f, pptrs.C);
//fptrs.C[pattern][rot] = computeFVarData(f, fvarwidth, fptrs.C[0][0], /*isAdaptive=*/true);
} break;
@ -944,22 +931,22 @@ Far::PatchTablesFactory::Create(Hmesh & mesh, int maxvalence) {
switch (f->_adaptiveFlags.bverts) {
case 0 : { // Regular Transition Patch (16 CVs)
iptrs.R[pattern] = getOneRing(f, 16, remapRegular, iptrs.R[pattern]);
pptrs.R[pattern] = computePatchParam(f, pptrs.R[pattern]);
iptrs.R = getOneRing(f, 16, remapRegular, iptrs.R);
pptrs.R = computePatchParam(f, pptrs.R);
//fptrs.R[pattern] = computeFVarData(f, fvarwidth, fptrs.R[pattern], /*isAdaptive=*/true);
} break;
case 2 : { // Boundary Transition Patch (12 CVs)
unsigned rot = f->_adaptiveFlags.brots;
iptrs.B[pattern][rot] = getOneRing(f, 12, remapRegularBoundary, iptrs.B[pattern][rot]);
pptrs.B[pattern][rot] = computePatchParam(f, pptrs.B[pattern][rot]);
//unsigned rot = f->_adaptiveFlags.brots;
iptrs.B = getOneRing(f, 12, remapRegularBoundary, iptrs.B);
pptrs.B = computePatchParam(f, pptrs.B);
//fptrs.B[pattern][rot] = computeFVarData(f, fvarwidth, fptrs.B[pattern][rot], /*isAdaptive=*/true);
} break;
case 3 : { // Corner Transition Patch (9 CVs)
unsigned rot = f->_adaptiveFlags.brots;
iptrs.C[pattern][rot] = getOneRing(f, 9, remapRegularCorner, iptrs.C[pattern][rot]);
pptrs.C[pattern][rot] = computePatchParam(f, pptrs.C[pattern][rot]);
//unsigned rot = f->_adaptiveFlags.brots;
iptrs.C = getOneRing(f, 9, remapRegularCorner, iptrs.C);
pptrs.C = computePatchParam(f, pptrs.C);
//fptrs.C[pattern][rot] = computeFVarData(f, fvarwidth, fptrs.C[pattern][rot], /*isAdaptive=*/true);
} break;
}
@ -1068,7 +1055,7 @@ Far::PatchTablesFactory::Create(Hmesh & mesh, int maxvalence) {
//------------------------------------------------------------------------------
// The One Ring vertices to rule them all !
Far::Index *
Far::PatchTablesFactory::getOneRing(Hface const * f,
Far::PatchTablesFactoryBase::getOneRing(Hface const * f,
int ringsize, Far::Index const * remap, Far::Index * result) {
assert( f and f->GetNumVertices()==4 and ringsize >=4 );
@ -1199,7 +1186,7 @@ Far::PatchTablesFactory::getOneRing(Hface const * f,
//------------------------------------------------------------------------------
// Populate the quad-offsets table used by Gregory patches
void
Far::PatchTablesFactory::getQuadOffsets(Hface const * f, unsigned int * result) {
Far::PatchTablesFactoryBase::getQuadOffsets(Hface const * f, unsigned int * result) {
assert(result and f and f->GetNumVertices()==4);
@ -1275,7 +1262,7 @@ Far::PatchTablesFactory::getQuadOffsets(Hface const * f, unsigned int * result)
//------------------------------------------------------------------------------
// Computes per-face or per-patch local ptex texture coordinates.
OpenSubdiv::Far::PatchParam *
Far::PatchTablesFactory::computePatchParam(Hface const * f, OpenSubdiv::Far::PatchParam *coord) {
Far::PatchTablesFactoryBase::computePatchParam(Hface const * f, OpenSubdiv::Far::PatchParam *coord) {
unsigned short u, v, ofs = 1;
unsigned char depth;
@ -1284,7 +1271,7 @@ Far::PatchTablesFactory::computePatchParam(Hface const * f, OpenSubdiv::Far::Pat
if (coord == NULL) return NULL;
// save the rotation state of the coarse face
unsigned char rots = (unsigned char)f->_adaptiveFlags.rots;
//unsigned char rots = (unsigned char)f->_adaptiveFlags.rots;
// track upwards towards coarse parent face, accumulating u,v indices
Hface const * p = f->GetParent();
@ -1312,10 +1299,13 @@ Far::PatchTablesFactory::computePatchParam(Hface const * f, OpenSubdiv::Far::Pat
p = f->GetParent();
}
coord->Set( f->GetPtexIndex(), u, v, rots, depth, nonquad );
unsigned short boundaryMask = 0;
unsigned short transitionMask = 0;
coord->Set( f->GetPtexIndex(), u, v, depth, nonquad, boundaryMask, transitionMask );
return ++coord;
}
}
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
@ -1326,7 +1316,7 @@ using namespace OPENSUBDIV_VERSION;
OpenSubdiv::Far::PatchTables const *
CreatePatchTables(Hmesh & mesh, int maxvalence) {
return OpenSubdiv::Far::PatchTablesFactory::Create(mesh, maxvalence);
return OpenSubdiv::Far::PatchTablesFactoryBase::Create(mesh, maxvalence);
}
//------------------------------------------------------------------------------

View File

@ -50,6 +50,7 @@ GLFWmonitor* g_primary=0;
#include <osd/cpuGLVertexBuffer.h>
#include <far/gregoryBasis.h>
#include <far/endCapGregoryBasisPatchFactory.h>
#include <far/patchTablesFactory.h>
#include <far/stencilTables.h>
#include <far/stencilTablesFactory.h>
@ -119,7 +120,8 @@ int g_displayPatchColor = 1,
g_numPatches = 0,
g_maxValence = 0,
g_currentPatch = 0,
g_Adaptive = true;
g_Adaptive = true,
g_useStencils = true;
typedef OpenSubdiv::Sdc::Options SdcOptions;
@ -723,7 +725,6 @@ createPtexNumbers(OpenSubdiv::Far::PatchTables const & patchTables,
int * remap = 0;
switch (patchTables.GetPatchArrayDescriptor(array).GetType()) {
case Descriptor::REGULAR: remap = regular; break;
case Descriptor::SINGLE_CREASE: remap = boundary; break;
case Descriptor::BOUNDARY: remap = boundary; break;
case Descriptor::CORNER: remap = corner; break;
case Descriptor::GREGORY:
@ -751,67 +752,57 @@ createVtrMesh(Shape * shape, int maxlevel) {
Stopwatch s;
s.Start();
using namespace OpenSubdiv;
// create Vtr mesh (topology)
OpenSubdiv::Sdc::SchemeType sdctype = GetSdcType(*shape);
OpenSubdiv::Sdc::Options sdcoptions = GetSdcOptions(*shape);
Sdc::SchemeType sdctype = GetSdcType(*shape);
Sdc::Options sdcoptions = GetSdcOptions(*shape);
sdcoptions.SetFVarLinearInterpolation(g_fvarInterpolation);
OpenSubdiv::Far::TopologyRefiner * refiner =
OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Create(*shape,
OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Options(sdctype, sdcoptions));
Far::TopologyRefiner * refiner =
Far::TopologyRefinerFactory<Shape>::Create(*shape,
Far::TopologyRefinerFactory<Shape>::Options(sdctype, sdcoptions));
if (g_Adaptive) {
OpenSubdiv::Far::TopologyRefiner::AdaptiveOptions options(maxlevel);
Far::TopologyRefiner::AdaptiveOptions options(maxlevel);
options.useSingleCreasePatch = false;
refiner->RefineAdaptive(options);
} else {
OpenSubdiv::Far::TopologyRefiner::UniformOptions options(maxlevel);
Far::TopologyRefiner::UniformOptions options(maxlevel);
options.fullTopologyInLastLevel = true;
refiner->RefineUniform(options);
}
//
// Stencils
//
//#define no_stencils
#ifdef no_stencils
{
s.Start();
// populate buffer with Vtr interpolated vertex data
refiner->Interpolate(verts, verts + ncoarseverts);
s.Stop();
//printf(" %f ms (interpolate)\n", float(s.GetElapsed())*1000.0f);
//printf(" %f ms (total)\n", float(s.GetTotalElapsed())*1000.0f);
}
#else
OpenSubdiv::Far::StencilTables const * stencilTables = 0;
{
OpenSubdiv::Far::StencilTablesFactory::Options options;
options.generateOffsets=true;
options.generateIntermediateLevels=true;
stencilTables =
OpenSubdiv::Far::StencilTablesFactory::Create(*refiner, options);
}
#endif
int numTotalVerts = refiner->GetNumVerticesTotal();
//
// Patch tables
//
std::vector<Vertex> fvarBuffer;
OpenSubdiv::Far::PatchTables * patchTables = 0;
Far::PatchTables * patchTables = 0;
bool createFVarWire = g_VtrDrawFVarPatches or g_VtrDrawFVarVerts;
if (g_Adaptive) {
assert(stencilTables);
OpenSubdiv::Far::PatchTablesFactory::Options options;
options.adaptiveStencilTables = stencilTables;
// for stencil based gregory evaluation
Far::EndCapGregoryBasisPatchFactory *gregoryBasisFactory = NULL;
if (g_Adaptive) {
Far::PatchTablesFactory::Options options;
options.generateFVarTables = createFVarWire;
patchTables = OpenSubdiv::Far::PatchTablesFactory::Create(*refiner, options);
// use GregoryBasis as EndPatch strategy.
// we want to share boundary vertices of marginal gregory patches
// only if using stencils.
bool shareBoundaryVertices = g_useStencils;
gregoryBasisFactory = new Far::EndCapGregoryBasisPatchFactory(
*refiner, shareBoundaryVertices);
patchTables =
Far::PatchTablesFactoryT<Far::EndCapGregoryBasisPatchFactory>::Create(
*refiner, options, gregoryBasisFactory);
// increase vertex buffer for the additional gregory verts
numTotalVerts += gregoryBasisFactory->GetNumGregoryBasisVertices();
g_numPatches = patchTables->GetNumPatchesTotal();
g_maxValence = patchTables->GetMaxValence();
@ -820,7 +811,7 @@ createVtrMesh(Shape * shape, int maxlevel) {
// interpolate fvar values
//OpenSubdiv::Far::FVarPatchTables const * fvarTables =
//Far::FVarPatchTables const * fvarTables =
// patchTables->GetFVarPatchTables();
//assert(fvarTables);
@ -836,26 +827,13 @@ createVtrMesh(Shape * shape, int maxlevel) {
float const * ptr = &shape->uvs[i*2];
values[i].SetPosition(ptr[0], ptr[1], 0.0f);
}
refiner->InterpolateFaceVarying(values, values + nCoarseValues);
}
}
// note: gregoryBasisStencilTables is owned by patchTables.
OpenSubdiv::Far::StencilTables const * gregoryBasisStencilTables =
patchTables->GetEndCapVertexStencilTables();
if (gregoryBasisStencilTables) {
OpenSubdiv::Far::StencilTables const *inStencilTables[] = {
stencilTables, gregoryBasisStencilTables
};
OpenSubdiv::Far::StencilTables const *concatStencilTables =
concatStencilTables = OpenSubdiv::Far::StencilTablesFactory::Create(
2, inStencilTables);
delete stencilTables;
stencilTables = concatStencilTables;
}
int numTotalVerts = shape->GetNumVertices() + stencilTables->GetNumStencils();
//
// interpolate vertices
//
// create vertex primvar data buffer
std::vector<Vertex> vertexBuffer(numTotalVerts);
@ -868,11 +846,73 @@ createVtrMesh(Shape * shape, int maxlevel) {
verts[i].SetPosition(ptr[0], ptr[1], ptr[2]);
}
//
// apply stencils
//
stencilTables->UpdateValues(verts, verts + ncoarseverts);
s.Start();
if (g_useStencils) {
//
// Stencil interpolation
//
Far::StencilTables const * stencilTables = 0;
Far::StencilTablesFactory::Options options;
options.generateOffsets=true;
options.generateIntermediateLevels=true;
stencilTables = Far::StencilTablesFactory::Create(*refiner, options);
// append gregory basis stencils if needed
if (gregoryBasisFactory) {
if (Far::StencilTables const * stencilTablesWithGregoryBasis =
gregoryBasisFactory->CreateVertexStencilTables(stencilTables, /*append=*/true)) {
delete stencilTables;
stencilTables = stencilTablesWithGregoryBasis;
}
}
//
// apply stencils
//
stencilTables->UpdateValues(verts, verts + ncoarseverts);
delete stencilTables;
} else {
//
// TopologyRefiner interpolation
//
// populate buffer with Vtr interpolated vertex data
refiner->Interpolate(verts, verts + ncoarseverts);
//printf(" %f ms (interpolate)\n", float(s.GetElapsed())*1000.0f);
//printf(" %f ms (total)\n", float(s.GetTotalElapsed())*1000.0f);
// gregory basis evaluation (without stencils)
if (gregoryBasisFactory) {
// gregory basis is defined at the maximum level.
// all src verts exist in maximum level and indexed within the level
// and resulting gregory verts will be placed after all refined verts
Vertex * src = verts + refiner->GetNumVerticesTotal() - refiner->GetNumVertices(maxlevel);
Vertex * dst = verts + refiner->GetNumVerticesTotal();
int nPatchArrays = patchTables->GetNumPatchArrays();
for (int i = 0; i < nPatchArrays; ++i) {
Far::PatchDescriptor desc =
patchTables->GetPatchArrayDescriptor(i);
if (desc.GetType() == Far::PatchDescriptor::GREGORY_BASIS) {
int nPatches = patchTables->GetNumPatches(i);
for (int j = 0; j < nPatches; ++j) {
// GregoryBasisFactory knows faceIndex in VtrLevel for this patch
int faceIndex = gregoryBasisFactory->GetFaceIndex(j);
Far::GregoryBasis const *gregoryBasis =
Far::EndCapGregoryBasisPatchFactory::Create(*refiner, faceIndex);
gregoryBasis->Evaluate(src, dst);
dst += 20;
delete gregoryBasis;
}
}
}
}
}
s.Stop();
//
@ -928,7 +968,7 @@ createVtrMesh(Shape * shape, int maxlevel) {
delete refiner;
delete patchTables;
delete stencilTables;
delete gregoryBasisFactory;
}
//------------------------------------------------------------------------------
@ -1283,6 +1323,13 @@ callbackAdaptive(bool checked, int /* a */)
rebuildOsdMeshes();
}
static void
callbackUseStencils(bool checked, int /* a */)
{
g_useStencils = checked;
rebuildOsdMeshes();
}
static void
callbackCheckBox(bool checked, int button) {
@ -1413,7 +1460,8 @@ initHUD() {
g_hud.AddCheckBox("Edge Sharp", g_VtrDrawEdgeSharpness!=0, 10, 295, callbackDrawIDs, 8);
g_hud.AddCheckBox("Gregory Basis", g_VtrDrawGregogyBasis!=0, 10, 315, callbackDrawIDs, 9);
g_hud.AddCheckBox("Adaptive (`)", g_Adaptive!=0, 10, 350, callbackAdaptive, 0, '`');
g_hud.AddCheckBox("Use Stencils (s)", g_useStencils!=0, 10, 350, callbackUseStencils, 0, 's');
g_hud.AddCheckBox("Adaptive (`)", g_Adaptive!=0, 10, 370, callbackAdaptive, 0, '`');
g_hud.AddSlider("Font Scale", 0.0f, 0.1f, 0.01f,

View File

@ -26,12 +26,16 @@
# source & headers
set(SOURCE_FILES
error.cpp
endCapLegacyGregoryPatchFactory.cpp
endCapGregoryBasisPatchFactory.cpp
endCapRegularPatchFactory.cpp
gregoryBasis.cpp
interpolate.cpp
patchDescriptor.cpp
patchMap.cpp
patchTables.cpp
patchTablesFactory.cpp
ptexIndices.cpp
stencilTablesFactory.cpp
topologyRefiner.cpp
topologyRefinerFactory.cpp
@ -43,15 +47,17 @@ set(PRIVATE_HEADER_FILES
set(PUBLIC_HEADER_FILES
error.h
endCapLegacyGregoryPatchFactory.h
endCapGregoryBasisPatchFactory.h
endCapRegularPatchFactory.h
gregoryBasis.h
interpolate.h
kernelBatch.h
kernelBatchDispatcher.h
patchDescriptor.h
patchParam.h
patchMap.h
patchTables.h
patchTablesFactory.h
ptexIndices.h
stencilTables.h
stencilTablesFactory.h
topologyRefiner.h

View File

@ -0,0 +1,465 @@
//
// 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/gregoryBasis.h"
#include "../far/endCapGregoryBasisPatchFactory.h"
#include "../far/error.h"
#include "../far/stencilTablesFactory.h"
#include "../far/topologyRefiner.h"
#include <cassert>
#include <cmath>
#include <cstring>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
static inline bool
checkMaxValence(Vtr::Level const & level) {
if (level.getMaxValence()>EndCapGregoryBasisPatchFactory::GetMaxValence()) {
// The proto-basis closed-form table limits valence to 'MAX_VALENCE'
Error(FAR_RUNTIME_ERROR,
"Vertex valence %d exceeds maximum %d supported",
level.getMaxValence(), EndCapGregoryBasisPatchFactory::GetMaxValence());
return false;
}
return true;
}
// ---------------------------------------------------------------------------
//
// Factory context
//
struct EndCapGregoryBasisPatchFactory::Context {
Context(TopologyRefiner const *refiner, bool shareBoundaryVertices) :
refiner(refiner), shareBoundaryVertices(shareBoundaryVertices),
numGregoryBasisVertices(0), numGregoryBasisPatches(0) { }
std::vector<GregoryBasis::Point> vertexStencils;
std::vector<GregoryBasis::Point> varyingStencils;
TopologyRefiner const *refiner;
bool shareBoundaryVertices;
int numGregoryBasisVertices;
int numGregoryBasisPatches;
std::vector<Index> basisIndices;
std::vector<Index> topology;
};
// ---------------------------------------------------------------------------
//
// EndCapGregoryBasisPatchFactory for Vertex StencilTables
//
EndCapGregoryBasisPatchFactory::EndCapGregoryBasisPatchFactory(
TopologyRefiner const & refiner, bool shareBoundaryVertices) :
_context(NULL) {
// Sanity check: the mesh must be adaptively refined
assert(not refiner.IsUniform());
// create context
_context = new EndCapGregoryBasisPatchFactory::Context(
&refiner, shareBoundaryVertices);
}
EndCapGregoryBasisPatchFactory::~EndCapGregoryBasisPatchFactory() {
delete _context;
}
int
EndCapGregoryBasisPatchFactory::GetMaxValence() {
return GregoryBasis::MAX_VALENCE;
}
//
// Stateless EndCapGregoryBasisPatchFactory
//
GregoryBasis const *
EndCapGregoryBasisPatchFactory::Create(TopologyRefiner const & refiner,
Index faceIndex, int fvarChannel) {
// Gregory patches are end-caps: they only exist on max-level
Vtr::Level const & level = refiner.getLevel(refiner.GetMaxLevel());
if (not checkMaxValence(level)) {
return 0;
}
GregoryBasis::ProtoBasis basis(level, faceIndex, fvarChannel);
int nelems= basis.GetNumElements();
GregoryBasis * result = new GregoryBasis;
result->_indices.resize(nelems);
result->_weights.resize(nelems);
basis.Copy(result->_sizes, &result->_indices[0], &result->_weights[0]);
// note: this function doesn't create varying stencils.
for (int i=0, offset=0; i<20; ++i) {
result->_offsets[i] = offset;
offset += result->_sizes[i];
}
return result;
}
static void factorizeBasisVertex(StencilTables const * stencils,
GregoryBasis::Point const & p,
ProtoStencil dst) {
// Use the Allocator to factorize the Gregory patch influence CVs with the
// supporting CVs from the stencil tables.
if (!stencils) return;
dst.Clear();
for (int j=0; j<p.GetSize(); ++j) {
dst.AddWithWeight(*stencils,
p.GetIndices()[j], p.GetWeights()[j]);
}
}
bool
EndCapGregoryBasisPatchFactory::addPatchBasis(Index faceIndex,
bool verticesMask[4][5]) {
// Gregory patches only exist on the hight
Vtr::Level const & level = _context->refiner->getLevel(
_context->refiner->GetMaxLevel());
if (not checkMaxValence(level)) {
return false;
}
// Gather the CVs that influence the Gregory patch and their relative
// weights in a basis
GregoryBasis::ProtoBasis basis(level, faceIndex);
for (int i = 0; i < 4; ++i) {
if (verticesMask[i][0]) {
_context->vertexStencils.push_back(basis.P[i]);
_context->varyingStencils.push_back(basis.V[i]);
}
if (verticesMask[i][1]) {
_context->vertexStencils.push_back(basis.Ep[i]);
_context->varyingStencils.push_back(basis.V[i]);
}
if (verticesMask[i][2]) {
_context->vertexStencils.push_back(basis.Em[i]);
_context->varyingStencils.push_back(basis.V[i]);
}
if (verticesMask[i][3]) {
_context->vertexStencils.push_back(basis.Fp[i]);
_context->varyingStencils.push_back(basis.V[i]);
}
if (verticesMask[i][4]) {
_context->vertexStencils.push_back(basis.Fm[i]);
_context->varyingStencils.push_back(basis.V[i]);
}
}
return true;
}
static void
createStencil(StencilAllocator &alloc,
StencilTables const *baseStencils,
TopologyRefiner const *refiner,
std::vector<GregoryBasis::Point> const &gregoryStencils) {
// Gregory limit stencils have indices that are relative to the level
// (maxlevel) of subdivision. These indices need to be offset to match
// the indices from the multi-level adaptive stencil tables.
// In addition: stencil tables can be built with singular stencils
// (single weight of 1.0f) as place-holders for coarse mesh vertices,
// which also needs to be accounted for.
int stencilsIndexOffset = 0;
{
int maxlevel = refiner->GetMaxLevel();
int nverts = refiner->GetNumVerticesTotal();
int nBaseStencils = baseStencils->GetNumStencils();
if (nBaseStencils == nverts) {
// the table contain stencils for the control vertices
stencilsIndexOffset = nverts - refiner->GetNumVertices(maxlevel);
} else if (nBaseStencils == (nverts -refiner->GetNumVertices(0))) {
// the table does not contain stencils for the control vertices
stencilsIndexOffset = nverts - refiner->GetNumVertices(maxlevel)
- refiner->GetNumVertices(0);
} else {
// these are not the stencils you are looking for...
assert(0);
return;
}
}
int nStencils = (int)gregoryStencils.size();
alloc.Resize(nStencils);
for (int i = 0; i < nStencils; ++i) {
GregoryBasis::Point p = gregoryStencils[i];
p.OffsetIndices(stencilsIndexOffset);
factorizeBasisVertex(baseStencils, p, alloc[i]);
}
}
StencilTables const *
EndCapGregoryBasisPatchFactory::createStencilTables(StencilAllocator &alloc,
StencilTables const *baseStencils,
bool append,
int const permute[20]) {
int nStencils = alloc.GetNumStencils();
int nelems = alloc.GetNumVerticesTotal();
// return NULL if empty
if (nStencils==0 or nelems==0) {
return NULL;
}
// Finalize the stencil tables from the temporary pool allocator
StencilTables * result = new StencilTables;
result->_numControlVertices = _context->refiner->GetNumVertices(0);
result->resize(nStencils, nelems);
Stencil dst(&result->_sizes.at(0),
&result->_indices.at(0), &result->_weights.at(0));
for (int i = 0; i < nStencils; ++i) {
Index index = i;
if (permute) {
int localIndex = i % 20,
baseIndex = i - localIndex;
index = baseIndex + permute[localIndex];
}
*dst._size = alloc.CopyStencil(index, dst._indices, dst._weights);
dst.Next();
}
result->generateOffsets();
if (append) {
StencilTables const *inStencilTables[] = {
baseStencils, result
};
StencilTables const *concatStencilTables =
StencilTablesFactory::Create(2, inStencilTables);
delete result;
return concatStencilTables;
} else {
return result;
}
}
PatchDescriptor::Type
EndCapGregoryBasisPatchFactory::GetPatchType(PatchTablesFactoryBase::PatchFaceTag const &) const {
return PatchDescriptor::GREGORY_BASIS;
}
//
// Populates the topology table used by Gregory-basis patches
//
// Note : 'faceIndex' values are expected to be sorted in ascending order !!!
// Note 2: this code attempts to identify basis vertices shared along
// gregory patch edges
ConstIndexArray
EndCapGregoryBasisPatchFactory::GetTopology(
Vtr::Level const& level, Index faceIndex,
PatchTablesFactoryBase::PatchFaceTag const * levelPatchTags,
int /*not used: levelVertsOffset*/)
{
// allocate indices (awkward)
// assert(Vtr::INDEX_INVALID==0xFFFFFFFF);
for (int i = 0; i < 20; ++i) {
_context->topology.push_back(Vtr::INDEX_INVALID);
}
Index * dest = &_context->topology[_context->numGregoryBasisPatches * 20];
int gregoryVertexOffset = _context->refiner->GetNumVerticesTotal();
if (_context->shareBoundaryVertices) {
ConstIndexArray fedges = level.getFaceEdges(faceIndex);
assert(fedges.size()==4);
for (int i=0; i<4; ++i) {
Index edge = fedges[i], adjface = 0;
{ // Gather adjacent faces
ConstIndexArray adjfaces = level.getEdgeFaces(edge);
for (int i=0; i<adjfaces.size(); ++i) {
if (adjfaces[i]==faceIndex) {
// XXXX manuelk if 'edge' is non-manifold, arbitrarily pick the
// next face in the list of adjacent faces
adjface = (adjfaces[(i+1)%adjfaces.size()]);
break;
}
}
}
// We are looking for adjacent faces that:
// - exist (no boundary)
// - have already been processed (known CV indices)
// - are also Gregory basis patches
if (adjface!=Vtr::INDEX_INVALID and (adjface < faceIndex) and
(not levelPatchTags[adjface]._isRegular)) {
ConstIndexArray aedges = level.getFaceEdges(adjface);
int aedge = aedges.FindIndexIn4Tuple(edge);
assert(aedge!=Vtr::INDEX_INVALID);
// Find index of basis in the list of basis already generated
struct compare {
static int op(void const * a, void const * b) {
return *(Index *)a - *(Index *)b;
}
};
Index * ptr = (Index *)std::bsearch(&adjface,
&_context->basisIndices[0],
_context->basisIndices.size(),
sizeof(Index), compare::op);
int srcBasisIdx = (int)(ptr - &_context->basisIndices[0]);
if (!ptr) {
// if the adjface is hole, it won't be found
break;
}
assert(ptr
and srcBasisIdx>=0
and srcBasisIdx<(int)_context->basisIndices.size());
// Copy the indices of CVs from the face on the other side of the
// shared edge
static int const gregoryEdgeVerts[4][4] = { { 0, 1, 7, 5},
{ 5, 6, 12, 10},
{10, 11, 17, 15},
{15, 16, 2, 0} };
Index * src = &_context->topology[srcBasisIdx*20];
for (int j=0; j<4; ++j) {
// invert direction
// note that src indices have already been offsetted.
dest[gregoryEdgeVerts[i][3-j]] = src[gregoryEdgeVerts[aedge][j]];
}
}
}
}
bool newVerticesMask[4][5];
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 5; ++j) {
if (dest[i*5+j]==Vtr::INDEX_INVALID) {
// assign new vertex
dest[i*5+j] =
_context->numGregoryBasisVertices + gregoryVertexOffset;
++_context->numGregoryBasisVertices;
newVerticesMask[i][j] = true;
} else {
// share vertex
newVerticesMask[i][j] = false;
}
}
}
_context->basisIndices.push_back(faceIndex);
// add basis
addPatchBasis(faceIndex, newVerticesMask);
++_context->numGregoryBasisPatches;
// return cvs;
return ConstIndexArray(dest, 20);
}
Index
EndCapGregoryBasisPatchFactory::GetFaceIndex(Index patchIndex) const {
return _context->basisIndices[patchIndex];
}
int
EndCapGregoryBasisPatchFactory::GetNumGregoryBasisPatches() const {
return _context->numGregoryBasisPatches;
}
int
EndCapGregoryBasisPatchFactory::GetNumGregoryBasisVertices() const {
return _context->numGregoryBasisVertices;
}
StencilTables const *
EndCapGregoryBasisPatchFactory::CreateVertexStencilTables(
StencilTables const *baseStencils,
bool append,
int const permute[20]) {
// Factorize the basis CVs with the stencil tables: the basis is now
// expressed as a linear combination of vertices from the coarse control
// mesh with no data dependencies
int maxvalence = _context->refiner->GetMaxValence();
StencilAllocator alloc(GregoryBasis::getNumMaxElements(maxvalence));
createStencil(alloc, baseStencils,
_context->refiner, _context->vertexStencils);
return createStencilTables(alloc, baseStencils, append, permute);
}
StencilTables const *
EndCapGregoryBasisPatchFactory::CreateVaryingStencilTables(
StencilTables const *baseStencils,
bool append,
int const permute[20]) {
int maxvalence = _context->refiner->GetMaxValence();
StencilAllocator alloc(GregoryBasis::getNumMaxElements(maxvalence));
createStencil(alloc, baseStencils,
_context->refiner, _context->varyingStencils);
return createStencilTables(alloc, baseStencils, append, permute);
}
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv

View File

@ -0,0 +1,153 @@
//
// 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 FAR_END_CAP_GREGORY_BASIS_PATCH_FACTORY_H
#define FAR_END_CAP_GREGORY_BASIS_PATCH_FACTORY_H
#include "../far/patchTablesFactory.h"
#include "../far/protoStencil.h"
#include "../vtr/level.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
class GregoryBasis;
class TopologyRefiner;
/// \brief A specialized factory to gather Gregory basis control vertices
///
class EndCapGregoryBasisPatchFactory {
public:
//
// Single patch GregoryBasis basis factory
//
/// \brief Instantiates a GregoryBasis from a TopologyRefiner that has been
/// refined adaptively for a given face.
///
/// @param refiner The TopologyRefiner containing the topology
///
/// @param faceIndex The index of the face (level is assumed to be MaxLevel)
///
/// @param fvarChannel Index of face-varying channel topology (default -1)
///
static GregoryBasis const * Create(TopologyRefiner const & refiner,
Index faceIndex, int fvarChannel=-1);
/// \brief Returns the maximum valence of a vertex in the mesh that the
/// Gregory patches can handle
static int GetMaxValence();
public:
///
/// Multi-patch Gregory stencils factory
///
// XXXX need to add support for face-varying channel stencils
/// \brief This factory accumulates vertex for Gregory basis patch
///
/// @param refiner TopologyRefiner from which to generate patches
///
/// @param shareBoundaryVertices Use same boundary vertices for neighboring
/// patches. It reduces the number of stencils
/// to be used.
///
EndCapGregoryBasisPatchFactory(TopologyRefiner const & refiner,
bool shareBoundaryVertices=true);
~EndCapGregoryBasisPatchFactory();
/// \brief Returns a patch type for \a patchTag generated by this factory.
///
/// @param patchTag identified tag information for the patch
///
PatchDescriptor::Type GetPatchType(PatchTablesFactoryBase::PatchFaceTag const &patchTag) const;
/// \brief Returns an end patch vertex indices for \a faceIndex.
///
/// @param level vtr refinement level
///
/// @param faceIndex vtr faceIndex at the level
///
/// @param levelPatchTags Array of patchTags for all faces in the level
///
/// @param levelVertOffset relative offset of patch vertex indices
///
ConstIndexArray GetTopology(Vtr::Level const& level, Index faceIndex,
PatchTablesFactoryBase::PatchFaceTag const * levelPatchTags,
int levelVertOffset);
/// \brief Returns the face index in vtr level for the given \a patchIndex.
Index GetFaceIndex(Index patchIndex) const;
/// \brief Returns the number of gregory basis patches generated.
///
int GetNumGregoryBasisPatches() const;
/// \brief Returns the number of gregory basis vertices generated.
///
int GetNumGregoryBasisVertices() const;
/// After all the gregory basis vertices have been collected, factorize
/// their stencils with given stencil table and create new stencil table.
///
/// @param baseStencils source stencil table
///
/// @param append if true, returns concatinated stencil table which
/// also includes source stencil table at the front.
///
/// @param permute index permutation table (optional)
///
StencilTables const * CreateVertexStencilTables(
StencilTables const *baseStencils, bool append, int const permute[20]=0);
StencilTables const * CreateVaryingStencilTables(
StencilTables const *baseStencils, bool append, int const permute[20]=0);
private:
/// Creates a basis for the vertices specified in mask on the face and
/// accumates it
bool addPatchBasis(Index faceIndex, bool newVerticesMask[4][5]);
StencilTables const *createStencilTables(StencilAllocator &alloc,
StencilTables const *baseStencils,
bool append,
int const permute[20]);
struct Context;
Context *_context;
};
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv
#endif // FAR_END_CAP_GREGORY_BASIS_PATCH_FACTORY_H

View File

@ -0,0 +1,197 @@
//
// 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/error.h"
#include "../far/endCapLegacyGregoryPatchFactory.h"
#include "../far/topologyRefiner.h"
#include "../vtr/level.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
EndCapLegacyGregoryPatchFactory::EndCapLegacyGregoryPatchFactory(TopologyRefiner const &refiner) :
_refiner(refiner) {
}
PatchDescriptor::Type
EndCapLegacyGregoryPatchFactory::GetPatchType(PatchTablesFactoryBase::PatchFaceTag const &tag) const {
if (tag._boundaryCount) {
return PatchDescriptor::GREGORY_BOUNDARY;
} else {
return PatchDescriptor::GREGORY;
}
}
ConstIndexArray
EndCapLegacyGregoryPatchFactory::GetTopology(Vtr::Level const& level, Index faceIndex,
PatchTablesFactoryBase::PatchFaceTag const * levelPatchTags,
int levelVertOffset) {
PatchTablesFactoryBase::PatchFaceTag patchTag = levelPatchTags[faceIndex];
// Gregory Regular Patch (4 CVs + quad-offsets / valence tables)
Vtr::ConstIndexArray faceVerts = level.getFaceVertices(faceIndex);
if (patchTag._boundaryCount) {
for (int j = 0; j < 4; ++j) {
// apply level offset
_gregoryBoundaryTopology.push_back(faceVerts[j] + levelVertOffset);
}
_gregoryBoundaryFaceIndices.push_back(faceIndex);
return ConstIndexArray(&_gregoryBoundaryTopology[_gregoryBoundaryTopology.size()-4], 4);
} else {
for (int j = 0; j < 4; ++j) {
// apply level offset
_gregoryTopology.push_back(faceVerts[j] + levelVertOffset);
}
_gregoryFaceIndices.push_back(faceIndex);
return ConstIndexArray(&_gregoryTopology[_gregoryTopology.size()-4], 4);
}
}
//
// Populate the quad-offsets table used by Gregory patches
//
static void getQuadOffsets(
Vtr::Level const& level, Index faceIndex, unsigned int offsets[]) {
Vtr::ConstIndexArray fVerts = level.getFaceVertices(faceIndex);
for (int i = 0; i < 4; ++i) {
Vtr::Index vIndex = fVerts[i];
Vtr::ConstIndexArray vFaces = level.getVertexFaces(vIndex),
vEdges = level.getVertexEdges(vIndex);
int thisFaceInVFaces = -1;
for (int j = 0; j < vFaces.size(); ++j) {
if (faceIndex == vFaces[j]) {
thisFaceInVFaces = j;
break;
}
}
assert(thisFaceInVFaces != -1);
Index vOffsets[2];
vOffsets[0] = thisFaceInVFaces;
vOffsets[1] = (thisFaceInVFaces + 1)%vEdges.size();
// we have to use the number of incident edges to modulo the local index
// because there could be 2 consecutive edges in the face belonging to
// the Gregory patch.
offsets[i] = vOffsets[0] | (vOffsets[1] << 8);
}
}
void
EndCapLegacyGregoryPatchFactory::AddGregoryPatchTables(PatchTables *patchTables)
{
// populate quad offsets
size_t numGregoryPatches = _gregoryFaceIndices.size();
size_t numGregoryBoundaryPatches = _gregoryBoundaryFaceIndices.size();
Vtr::Level const &level = _refiner.getLevel(_refiner.GetMaxLevel());
patchTables->_quadOffsetsTable.resize(
(numGregoryPatches + numGregoryBoundaryPatches)*4);
PatchTables::QuadOffsetsTable::value_type *p = &patchTables->_quadOffsetsTable[0];
for (size_t i = 0; i < numGregoryPatches; ++i) {
getQuadOffsets(level, _gregoryFaceIndices[i], p);
p += 4;
}
for (size_t i = 0; i < numGregoryBoundaryPatches; ++i) {
getQuadOffsets(level, _gregoryBoundaryFaceIndices[i], p);
p += 4;
}
// populate vertex valences
//
// Now deal with the "vertex valence" table for Gregory patches -- this table contains the one-ring
// of vertices around each vertex. Currently it is extremely wasteful for the following reasons:
// - it allocates 2*maxvalence+1 for ALL vertices
// - it initializes the one-ring for ALL vertices
// We use the full size expected (not sure what else relies on that) but we avoiding initializing
// the vast majority of vertices that are not associated with gregory patches -- by having previously
// marked those that are associated above and skipping all others.
//
const int SizePerVertex = 2*patchTables->_maxValence + 1;
std::vector<Index> & vTable = patchTables->_vertexValenceTable;
vTable.resize(_refiner.GetNumVerticesTotal() * SizePerVertex);
int vOffset = 0;
int levelLast = _refiner.GetMaxLevel();
for (int i = 0; i <= levelLast; ++i) {
Vtr::Level const * level = &_refiner.getLevel(i);
if (i == levelLast) {
int vTableOffset = vOffset * SizePerVertex;
for (int vIndex = 0; vIndex < level->getNumVertices(); ++vIndex) {
int* vTableEntry = &vTable[vTableOffset];
//
// If not marked as a vertex of a gregory patch, just set to 0 to ignore. Otherwise
// gather the one-ring around the vertex and set its resulting size (note the negative
// size used to distinguish between boundary/interior):
//
//if (!gregoryVertexFlags[vIndex + vOffset]) {
vTableEntry[0] = 0;
//} else {
int * ringDest = vTableEntry + 1,
ringSize = level->gatherQuadRegularRingAroundVertex(vIndex, ringDest);
for (int j = 0; j < ringSize; ++j) {
ringDest[j] += vOffset;
}
if (ringSize & 1) {
// boundary vertex : duplicate boundary vertex index
// and store negative valence.
ringSize++;
vTableEntry[ringSize]=vTableEntry[ringSize-1];
vTableEntry[0] = -ringSize/2;
} else {
vTableEntry[0] = ringSize/2;
}
//}
vTableOffset += SizePerVertex;
}
}
vOffset += level->getNumVertices();
}
}
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv

View File

@ -0,0 +1,65 @@
//
// 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 FAR_END_CAP_LEGACY_GREGORY_PATCH_FACTORY_H
#define FAR_END_CAP_LEGACY_GREGORY_PATCH_FACTORY_H
#include "../far/patchTablesFactory.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
class PatchTables;
class TopologyRefiner;
namespace Far {
/// \brief This factory generates legacy (OpenSubdiv 2.x) gregory patches.
///
class EndCapLegacyGregoryPatchFactory {
public:
EndCapLegacyGregoryPatchFactory(TopologyRefiner const & refiner);
PatchDescriptor::Type GetPatchType(PatchTablesFactoryBase::PatchFaceTag const &tag) const;
ConstIndexArray GetTopology(Vtr::Level const& level, Index faceIndex,
PatchTablesFactoryBase::PatchFaceTag const * levelPatchTags,
int levelVertOffset);
void AddGregoryPatchTables(PatchTables *patchTables);
private:
TopologyRefiner const &_refiner;
std::vector<Index> _gregoryTopology;
std::vector<Index> _gregoryBoundaryTopology;
std::vector<Index> _gregoryFaceIndices;
std::vector<Index> _gregoryBoundaryFaceIndices;
};
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv
#endif // FAR_END_CAP_LEGACY_GREGORY_PATCH_FACTORY_H

View File

@ -0,0 +1,278 @@
//
// 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/gregoryBasis.h"
#include "../far/endCapRegularPatchFactory.h"
#include "../far/endCapGregoryBasisPatchFactory.h"
#include "../far/error.h"
#include "../far/stencilTablesFactory.h"
#include "../far/topologyRefiner.h"
#include <cassert>
#include <cmath>
#include <cstring>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
struct EndCapRegularPatchFactory::Context {
Context(TopologyRefiner const *refiner) :
refiner(refiner), numVertices(0), numPatches(0) { }
TopologyRefiner const *refiner;
std::vector<GregoryBasis::Point> vertexStencils;
std::vector<GregoryBasis::Point> varyingStencils;
int numVertices;
int numPatches;
std::vector<Index> vertIndices;
};
EndCapRegularPatchFactory::EndCapRegularPatchFactory(
TopologyRefiner const & refiner) {
_context = new Context(&refiner);
}
EndCapRegularPatchFactory::~EndCapRegularPatchFactory() {
delete _context;
}
PatchDescriptor::Type
EndCapRegularPatchFactory::GetPatchType(
PatchTablesFactoryBase::PatchFaceTag const &) const {
return PatchDescriptor::REGULAR;
}
ConstIndexArray
EndCapRegularPatchFactory::GetTopology(
Vtr::Level const& level, Index faceIndex,
PatchTablesFactoryBase::PatchFaceTag const * /*levelPatchTags*/,
int /*levelVertOffset*/) {
// XXX: For now, always create new 16 indices for each patch.
// we'll optimize later to share all regular control points with
// other patches as well as to try to make extra ordinary verts watertight.
int vertexOffset = _context->refiner->GetNumVerticesTotal();
for (int i = 0; i < 16; ++i) {
_context->vertIndices.push_back(_context->numVertices + vertexOffset);
++_context->numVertices;
}
// XXX: temporary hack. we should traverse topology and find existing
// vertices if available
//
// Reorder gregory basis stencils into regular bezier
GregoryBasis::ProtoBasis basis(level, faceIndex);
std::vector<GregoryBasis::Point> bezierCP;
bezierCP.reserve(16);
bezierCP.push_back(basis.P[0]);
bezierCP.push_back(basis.Ep[0]);
bezierCP.push_back(basis.Em[1]);
bezierCP.push_back(basis.P[1]);
bezierCP.push_back(basis.Em[0]);
bezierCP.push_back(basis.Fp[0]); // arbitrary
bezierCP.push_back(basis.Fp[1]); // arbitrary
bezierCP.push_back(basis.Ep[1]);
bezierCP.push_back(basis.Ep[3]);
bezierCP.push_back(basis.Fp[3]); // arbitrary
bezierCP.push_back(basis.Fp[2]); // arbitrary
bezierCP.push_back(basis.Em[2]);
bezierCP.push_back(basis.P[3]);
bezierCP.push_back(basis.Em[3]);
bezierCP.push_back(basis.Ep[2]);
bezierCP.push_back(basis.P[2]);
// Apply basis conversion from bezier to b-spline
float Q[4][4] = {{ 6, -7, 2, 0},
{ 0, 2, -1, 0},
{ 0, -1, 2, 0},
{ 0, 2, -7, 6} };
std::vector<GregoryBasis::Point> H(16);
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
for (int k = 0; k < 4; ++k) {
if (Q[i][k] != 0) H[i*4+j] += bezierCP[j+k*4] * Q[i][k];
}
}
}
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
GregoryBasis::Point p;
for (int k = 0; k < 4; ++k) {
if (Q[j][k] != 0) p += H[i*4+k] * Q[j][k];
}
_context->vertexStencils.push_back(p);
}
}
int varyingIndices[] = { 0, 0, 1, 1,
0, 0, 1, 1,
3, 3, 2, 2,
3, 3, 2, 2,};
for (int i = 0; i < 16; ++i) {
_context->varyingStencils.push_back(basis.V[varyingIndices[i]]);
}
++_context->numPatches;
return ConstIndexArray(
&_context->vertIndices[(_context->numPatches-1)*16], 16);
}
StencilTables const *
EndCapRegularPatchFactory::createStencilTables(StencilAllocator &alloc,
StencilTables const *baseStencils,
bool append) {
int nStencils = alloc.GetNumStencils();
int nelems = alloc.GetNumVerticesTotal();
// return NULL if empty
if (nStencils==0 or nelems==0) {
return NULL;
}
// Finalize the stencil tables from the temporary pool allocator
StencilTables * result = new StencilTables;
result->_numControlVertices = _context->refiner->GetNumVertices(0);
result->resize(nStencils, nelems);
Stencil dst(&result->_sizes.at(0),
&result->_indices.at(0), &result->_weights.at(0));
for (int i = 0; i < nStencils; ++i) {
Index index = i;
*dst._size = alloc.CopyStencil(index, dst._indices, dst._weights);
dst.Next();
}
result->generateOffsets();
if (append) {
StencilTables const *inStencilTables[] = {
baseStencils, result
};
StencilTables const *concatStencilTables =
StencilTablesFactory::Create(2, inStencilTables);
delete result;
return concatStencilTables;
} else {
return result;
}
}
static void
createStencil(StencilAllocator &alloc,
StencilTables const *baseStencils,
TopologyRefiner const *refiner,
std::vector<GregoryBasis::Point> const &gregoryStencils) {
// Gregory limit stencils have indices that are relative to the level
// (maxlevel) of subdivision. These indices need to be offset to match
// the indices from the multi-level adaptive stencil tables.
// In addition: stencil tables can be built with singular stencils
// (single weight of 1.0f) as place-holders for coarse mesh vertices,
// which also needs to be accounted for.
int stencilsIndexOffset = 0;
{
int maxlevel = refiner->GetMaxLevel();
int nverts = refiner->GetNumVerticesTotal();
int nBaseStencils = baseStencils->GetNumStencils();
if (nBaseStencils == nverts) {
// the table contain stencils for the control vertices
stencilsIndexOffset = nverts - refiner->GetNumVertices(maxlevel);
} else if (nBaseStencils == (nverts -refiner->GetNumVertices(0))) {
// the table does not contain stencils for the control vertices
stencilsIndexOffset = nverts - refiner->GetNumVertices(maxlevel)
- refiner->GetNumVertices(0);
} else {
// these are not the stencils you are looking for...
assert(0);
return;
}
}
int nStencils = (int)gregoryStencils.size();
alloc.Resize(nStencils);
for (int i = 0; i < nStencils; ++i) {
GregoryBasis::Point p = gregoryStencils[i];
p.OffsetIndices(stencilsIndexOffset);
p.FactorizeBasisVertex(baseStencils, alloc[i]);
}
}
StencilTables const *
EndCapRegularPatchFactory::CreateVertexStencilTables(
StencilTables const *baseStencils,
bool append) {
// Factorize the basis CVs with the stencil tables: the basis is now
// expressed as a linear combination of vertices from the coarse control
// mesh with no data dependencies
int maxvalence = _context->refiner->GetMaxValence();
StencilAllocator alloc(GregoryBasis::getNumMaxElements(maxvalence));
createStencil(alloc, baseStencils,
_context->refiner, _context->vertexStencils);
return createStencilTables(alloc, baseStencils, append);
}
StencilTables const *
EndCapRegularPatchFactory::CreateVaryingStencilTables(
StencilTables const *baseStencils,
bool append) {
int maxvalence = _context->refiner->GetMaxValence();
StencilAllocator alloc(GregoryBasis::getNumMaxElements(maxvalence));
createStencil(alloc, baseStencils,
_context->refiner, _context->varyingStencils);
return createStencilTables(alloc, baseStencils, append);
}
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv

View File

@ -0,0 +1,108 @@
//
// 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 FAR_END_CAP_REGULAR_PATCH_FACTORY_H
#define FAR_END_CAP_REGULAR_PATCH_FACTORY_H
#include "../far/patchTablesFactory.h"
#include "../far/protoStencil.h"
#include "../vtr/level.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
class TopologyRefiner;
/// \brief A specialized factory to gather Regular B-spline control vertices
///
class EndCapRegularPatchFactory {
public:
// XXXX need to add support for face-varying channel stencils
/// \brief This factory accumulates vertex for regular end cap
///
/// @param refiner TopologyRefiner from which to generate patches
///
/// @param shareBoundaryVertices Use same boundary vertices for neighboring
/// patches. It reduces the number of stencils
/// to be used.
///
EndCapRegularPatchFactory(TopologyRefiner const & refiner);
~EndCapRegularPatchFactory();
/// \brief Returns a patch type for \a patchTag generated by this factory.
///
/// @param patchTag identified tag information for the patch
///
PatchDescriptor::Type GetPatchType(PatchTablesFactoryBase::PatchFaceTag const &patchTag) const;
/// \brief Returns an end patch vertex indices for \a faceIndex.
///
/// @param level vtr refinement level
///
/// @param faceIndex vtr faceIndex at the level
///
/// @param levelPatchTags Array of patchTags for all faces in the level
///
/// @param levelVertOffset relative offset of patch vertex indices
///
ConstIndexArray GetTopology(Vtr::Level const& level, Index faceIndex,
PatchTablesFactoryBase::PatchFaceTag const * levelPatchTags,
int levelVertOffset);
/// After all the gregory basis vertices have been collected, factorize
/// their stencils with given stencil table and create new stencil table.
///
/// @param baseStencils source stencil table
///
/// @param append if true, returns concatinated stencil table which
/// also includes source stencil table at the front.
///
/// @param permute index permutation table (optional)
///
StencilTables const * CreateVertexStencilTables(
StencilTables const *baseStencils, bool append);
StencilTables const * CreateVaryingStencilTables(
StencilTables const *baseStencils, bool append);
private:
StencilTables const *createStencilTables(StencilAllocator &alloc,
StencilTables const *baseStencils,
bool append);
struct Context;
Context *_context;
};
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv
#endif // FAR_END_CAP_GREGORY_BASIS_PATCH_FACTORY_H

View File

@ -24,6 +24,7 @@
#include "../far/gregoryBasis.h"
#include "../far/error.h"
#include "../far/stencilTablesFactory.h"
#include "../far/topologyRefiner.h"
#include <cassert>
@ -33,6 +34,7 @@
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
// Builds a table of local indices pairs for each vertex of the patch.
//
// o
@ -85,200 +87,8 @@ getQuadOffsets(Vtr::Level const & level, Vtr::Index fIndex,
}
}
#define GetNumMaxElems( maxvalence ) \
16 + maxvalence - 3
// limit valence of 30 because we use a pre-computed closed-form 'ef' table
// XXXtakahito: revisit here to determine appropriate size
static const int MAX_VALENCE=(30*2),
MAX_ELEMS = GetNumMaxElems(MAX_VALENCE);
namespace Far {
static inline bool
checkMaxValence(Vtr::Level const & level) {
if (level.getMaxValence()>GregoryBasisFactory::GetMaxValence()) {
// The proto-basis closed-form table limits valence to 'MAX_VALENCE'
Error(FAR_RUNTIME_ERROR,
"Vertex valence %d exceeds maximum %d supported",
level.getMaxValence(), GregoryBasisFactory::GetMaxValence());
return false;
}
return true;
}
//
// Basis point
//
// Implements arithmetic operators to manipulate the influence of the
// 1-ring control vertices supporting the patch basis
//
class Point {
public:
Point() : _size(0) { }
Point(Index idx, float weight = 1.0f) {
_size = 1;
_indices[0] = idx;
_weights[0] = weight;
}
Point(Point const & other) {
*this = other;
}
int GetSize() const {
return _size;
}
Index const * GetIndices() const {
return _indices;
}
float const * GetWeights() const {
return _weights;
}
Point & operator = (Point const & other) {
_size = other._size;
memcpy(_indices, other._indices, other._size*sizeof(Index));
memcpy(_weights, other._weights, other._size*sizeof(float));
return *this;
}
Point & operator += (Point const & other) {
for (int i=0; i<other._size; ++i) {
Index idx = findIndex(other._indices[i]);
_weights[idx] += other._weights[i];
}
return *this;
}
Point & operator -= (Point const & other) {
for (int i=0; i<other._size; ++i) {
Index idx = findIndex(other._indices[i]);
_weights[idx] -= other._weights[i];
}
return *this;
}
Point & operator *= (float f) {
for (int i=0; i<_size; ++i) {
_weights[i] *= f;
}
return *this;
}
Point & operator /= (float f) {
return (*this)*=(1.0f/f);
}
friend Point operator * (Point const & src, float f) {
Point p( src ); return p*=f;
}
friend Point operator / (Point const & src, float f) {
Point p( src ); return p*= (1.0f/f);
}
Point operator + (Point const & other) {
Point p(*this); return p+=other;
}
Point operator - (Point const & other) {
Point p(*this); return p-=other;
}
void OffsetIndices(Index offset) {
for (int i=0; i<_size; ++i) {
_indices[i] += offset;
}
}
void Copy(int ** size, Index ** indices, float ** weights) const;
private:
int findIndex(Index idx) {
for (int i=0; i<_size; ++i) {
if (_indices[i]==idx) {
return i;
}
}
_indices[_size]=idx;
_weights[_size]=0.0f;
++_size;
return _size-1;
}
int _size;
// XXXX this would really be better with VLA where we only allocate
// space based on the max vertex valence in the mesh, not the
// absolute maximum supported by the closed-form tangents table.
Index _indices[MAX_ELEMS];
float _weights[MAX_ELEMS];
};
void
Point::Copy(int ** size, Index ** indices, float ** weights) const {
memcpy(*indices, _indices, _size*sizeof(Index));
memcpy(*weights, _weights, _size*sizeof(float));
**size = _size;
*indices += _size;
*weights += _size;
++(*size);
}
//
// ProtoBasis
//
// Given a Vtr::Level and a face index, gathers all the influences of the 1-ring
// that supports the 20 CVs of a Gregory patch basis.
//
struct ProtoBasis {
ProtoBasis(Vtr::Level const & level, Index faceIndex, int fvarChannel=-1);
int GetNumElements() const;
void OffsetIndices(Index offset);
void Copy(int * sizes, Index * indices, float * weights) const;
// Control Vertices based on :
// "Approximating Subdivision Surfaces with Gregory Patches for Hardware Tessellation"
// Loop, Schaefer, Ni, Castafio (ACM ToG Siggraph Asia 2009)
//
// P3 e3- e2+ P2
// O--------O--------O--------O
// | | | |
// | | | |
// | | f3- | f2+ |
// | O O |
// e3+ O------O O------O e2-
// | f3+ f2- |
// | |
// | |
// | f0- f1+ |
// e0- O------O O------O e1+
// | O O |
// | | f0+ | f1- |
// | | | |
// | | | |
// O--------O--------O--------O
// P0 e0+ e1- P1
//
Point P[4], Ep[4], Em[4], Fp[4], Fm[4];
// for varying interpolation
Point V[4];
};
int
ProtoBasis::GetNumElements() const {
GregoryBasis::ProtoBasis::GetNumElements() const {
int nelems=0;
for (int vid=0; vid<4; ++vid) {
nelems += P[vid].GetSize();
@ -290,18 +100,7 @@ ProtoBasis::GetNumElements() const {
return nelems;
}
void
ProtoBasis::OffsetIndices(Index offset) {
for (int vid=0; vid<4; ++vid) {
P[vid].OffsetIndices(offset);
Ep[vid].OffsetIndices(offset);
Em[vid].OffsetIndices(offset);
Fp[vid].OffsetIndices(offset);
Fm[vid].OffsetIndices(offset);
V[vid].OffsetIndices(offset);
}
}
void
ProtoBasis::Copy(int * sizes, Index * indices, float * weights) const {
GregoryBasis::ProtoBasis::Copy(int * sizes, Index * indices, float * weights) const {
for (int vid=0; vid<4; ++vid) {
P[vid].Copy(&sizes, &indices, &weights);
Ep[vid].Copy(&sizes, &indices, &weights);
@ -310,6 +109,7 @@ ProtoBasis::Copy(int * sizes, Index * indices, float * weights) const {
Fm[vid].Copy(&sizes, &indices, &weights);
}
}
inline float csf(Index n, Index j) {
if (j%2 == 0) {
return cosf((2.0f * float(M_PI) * float(float(j-0)/2.0f))/(float(n)+3.0f));
@ -317,7 +117,9 @@ inline float csf(Index n, Index j) {
return sinf((2.0f * float(M_PI) * float(float(j-1)/2.0f))/(float(n)+3.0f));
}
}
ProtoBasis::ProtoBasis(Vtr::Level const & level, Index faceIndex, int fvarChannel) {
GregoryBasis::ProtoBasis::ProtoBasis(
Vtr::Level const & level, Index faceIndex, int fvarChannel) {
static float ef[MAX_VALENCE-3] = {
0.812816f, 0.500000f, 0.363644f, 0.287514f,
@ -364,8 +166,8 @@ ProtoBasis::ProtoBasis(Vtr::Level const & level, Index faceIndex, int fvarChanne
int valence;
if (ringSize & 1) {
// boundary vertex
++ringSize;
manifoldRing[ringSize] = manifoldRing[ringSize-1];
++ringSize;
valence = -ringSize/2;
} else {
valence = ringSize/2;
@ -573,196 +375,20 @@ ProtoBasis::ProtoBasis(Vtr::Level const & level, Index faceIndex, int fvarChanne
}
}
int GregoryBasisFactory::GetMaxValence() {
return MAX_VALENCE;
}
//
// Stateless GregoryBasisFactory
//
GregoryBasis const *
GregoryBasisFactory::Create(TopologyRefiner const & refiner,
Index faceIndex, int fvarChannel) {
void
GregoryBasis::Point::FactorizeBasisVertex(StencilTables const * stencils,
ProtoStencil dst) {
// Gregory patches are end-caps: they only exist on max-level
Vtr::Level const & level = refiner.getLevel(refiner.GetMaxLevel());
if (not checkMaxValence(level)) {
return 0;
}
ProtoBasis basis(level, faceIndex, fvarChannel);
int nelems= basis.GetNumElements();
GregoryBasis * result = new GregoryBasis;
result->_indices.resize(nelems);
result->_weights.resize(nelems);
basis.Copy(result->_sizes, &result->_indices[0], &result->_weights[0]);
// note: this function doesn't create varying stencils.
for (int i=0, offset=0; i<20; ++i) {
result->_offsets[i] = offset;
offset += result->_sizes[i];
}
return result;
}
//
// GregoryBasisFactory for Vertex StencilTables
//
GregoryBasisFactory::GregoryBasisFactory(TopologyRefiner const & refiner,
StencilTables const *stencils,
StencilTables const *varyingStencils,
int numpatches, int maxvalence) :
_currentStencil(0), _refiner(refiner),
_stencils(stencils), _varyingStencils(varyingStencils),
_alloc(GetNumMaxElems(maxvalence)),
_varyingAlloc(GetNumMaxElems(maxvalence)) {
// Sanity check: the mesh must be adaptively refined
assert(not _refiner.IsUniform());
_alloc.Resize(numpatches * 20);
_varyingAlloc.Resize(numpatches * 20);
// Gregory limit stencils have indices that are relative to the level
// (maxlevel) of subdivision. These indices need to be offset to match
// the indices from the multi-level adaptive stencil tables.
// In addition: stencil tables can be built with singular stencils
// (single weight of 1.0f) as place-holders for coarse mesh vertices,
// which also needs to be accounted for.
_stencilsOffset=-1;
{
int maxlevel = _refiner.GetMaxLevel(),
nverts = _refiner.GetNumVerticesTotal(),
nstencils = _stencils->GetNumStencils();
if (nstencils==nverts) {
// the table contain stencils for the control vertices
_stencilsOffset = nverts - _refiner.GetNumVertices(maxlevel);
} else if (nstencils==(nverts-_refiner.GetNumVertices(0))) {
// the table does not contain stencils for the control vertices
_stencilsOffset = nverts - _refiner.GetNumVertices(maxlevel)
- _refiner.GetNumVertices(0);
} else {
// these are not the stencils you are looking for...
assert(0);
}
}
}
static inline void
factorizeBasisVertex(StencilTables const * stencils, Point const & p, ProtoStencil dst) {
// Use the Allocator to factorize the Gregory patch influence CVs with the
// supporting CVs from the stencil tables.
if (!stencils) return;
dst.Clear();
for (int j=0; j<p.GetSize(); ++j) {
dst.AddWithWeight(*stencils,
p.GetIndices()[j], p.GetWeights()[j]);
for (int j = 0; j < _size; ++j) {
dst.AddWithWeight(*stencils, _indices[j], _weights[j]);
}
}
bool
GregoryBasisFactory::AddPatchBasis(Index faceIndex,
bool verticesMask[4][5]) {
// Gregory patches only exist on the hight
Vtr::Level const & level = _refiner.getLevel(_refiner.GetMaxLevel());
if (not checkMaxValence(level)) {
return false;
}
// Gather the CVs that influence the Gregory patch and their relative
// weights in a basis
ProtoBasis basis(level, faceIndex);
// The basis vertex indices are currently local to maxlevel: need to offset
// to match layout of adaptive StencilTables (see factory constructor above)
assert(_stencilsOffset>=0);
basis.OffsetIndices(_stencilsOffset);
// Factorize the basis CVs with the stencil tables: the basis is now
// expressed as a linear combination of vertices from the coarse control
// mesh with no data dependencies
for (int i=0; i<4; ++i) {
if (verticesMask[i][0]) {
factorizeBasisVertex(_stencils, basis.P[i], _alloc[_currentStencil]);
// need varying stencils only for corners
factorizeBasisVertex(_varyingStencils, basis.V[i], _varyingAlloc[_currentStencil]);
++_currentStencil;
}
if (verticesMask[i][1]) {
factorizeBasisVertex(_stencils, basis.Ep[i], _alloc[_currentStencil]);
factorizeBasisVertex(_varyingStencils, basis.V[i], _varyingAlloc[_currentStencil]);
++_currentStencil;
}
if (verticesMask[i][2]) {
factorizeBasisVertex(_stencils, basis.Em[i], _alloc[_currentStencil]);
factorizeBasisVertex(_varyingStencils, basis.V[i], _varyingAlloc[_currentStencil]);
++_currentStencil;
}
if (verticesMask[i][3]) {
factorizeBasisVertex(_stencils, basis.Fp[i], _alloc[_currentStencil]);
factorizeBasisVertex(_varyingStencils, basis.V[i], _varyingAlloc[_currentStencil]);
++_currentStencil;
}
if (verticesMask[i][4]) {
factorizeBasisVertex(_stencils, basis.Fm[i], _alloc[_currentStencil]);
factorizeBasisVertex(_varyingStencils, basis.V[i], _varyingAlloc[_currentStencil]);
++_currentStencil;
}
}
return true;
}
StencilTables const *
GregoryBasisFactory::createStencilTables(int const permute[20],
StencilAllocator &alloc) {
int nstencils = _currentStencil;
int nelems = alloc.GetNumVerticesTotal();
if (nstencils==0 or nelems==0) {
return 0;
}
// Finalize the stencil tables from the temporary pool allocator
StencilTables * result = new StencilTables;
result->_numControlVertices = _refiner.GetNumVertices(0);
result->resize(nstencils, nelems);
Stencil dst(&result->_sizes.at(0),
&result->_indices.at(0), &result->_weights.at(0));
for (int i=0; i<nstencils; ++i) {
Index index = i;
if (permute) {
int localIndex = i % 20,
baseIndex = i - localIndex;
index = baseIndex + permute[localIndex];
}
*dst._size = alloc.CopyStencil(index, dst._indices, dst._weights);
dst.Next();
}
result->generateOffsets();
return result;
}
} // end namespace Far

View File

@ -26,6 +26,8 @@
#define FAR_GREGORY_BASIS_H
#include "../far/protoStencil.h"
#include "../vtr/level.h"
#include <cstring>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
@ -64,9 +66,185 @@ public:
}
}
static const int MAX_VALENCE = (30*2);
static const int MAX_ELEMS = (16 + MAX_VALENCE);
// limit valence of 30 because we use a pre-computed closed-form 'ef' table
// XXXtakahito: revisit here to determine appropriate size
// or remove fixed size limit and use Sdc mask
static int getNumMaxElements(int maxValence) {
return (16 + maxValence);
}
//
// Basis point
//
// Implements arithmetic operators to manipulate the influence of the
// 1-ring control vertices supporting the patch basis
//
class Point {
public:
Point() : _size(0) { }
Point(Index idx, float weight = 1.0f) {
_size = 1;
_indices[0] = idx;
_weights[0] = weight;
}
Point(Point const & other) {
*this = other;
}
int GetSize() const {
return _size;
}
Index const * GetIndices() const {
return _indices;
}
float const * GetWeights() const {
return _weights;
}
Point & operator = (Point const & other) {
_size = other._size;
memcpy(_indices, other._indices, other._size*sizeof(Index));
memcpy(_weights, other._weights, other._size*sizeof(float));
return *this;
}
Point & operator += (Point const & other) {
for (int i=0; i<other._size; ++i) {
Index idx = findIndex(other._indices[i]);
_weights[idx] += other._weights[i];
}
return *this;
}
Point & operator -= (Point const & other) {
for (int i=0; i<other._size; ++i) {
Index idx = findIndex(other._indices[i]);
_weights[idx] -= other._weights[i];
}
return *this;
}
Point & operator *= (float f) {
for (int i=0; i<_size; ++i) {
_weights[i] *= f;
}
return *this;
}
Point & operator /= (float f) {
return (*this)*=(1.0f/f);
}
friend Point operator * (Point const & src, float f) {
Point p( src ); return p*=f;
}
friend Point operator / (Point const & src, float f) {
Point p( src ); return p*= (1.0f/f);
}
Point operator + (Point const & other) {
Point p(*this); return p+=other;
}
Point operator - (Point const & other) {
Point p(*this); return p-=other;
}
void OffsetIndices(Index offset) {
for (int i=0; i<_size; ++i) {
_indices[i] += offset;
}
}
void Copy(int ** size, Index ** indices, float ** weights) const {
memcpy(*indices, _indices, _size*sizeof(Index));
memcpy(*weights, _weights, _size*sizeof(float));
**size = _size;
*indices += _size;
*weights += _size;
++(*size);
}
void FactorizeBasisVertex(StencilTables const * stencils,
ProtoStencil dst);
private:
int findIndex(Index idx) {
for (int i=0; i<_size; ++i) {
if (_indices[i]==idx) {
return i;
}
}
_indices[_size]=idx;
_weights[_size]=0.0f;
++_size;
return _size-1;
}
int _size;
// XXXX this would really be better with VLA where we only allocate
// space based on the max vertex valence in the mesh, not the
// absolute maximum supported by the closed-form tangents table.
Index _indices[MAX_ELEMS];
float _weights[MAX_ELEMS];
};
//
// ProtoBasis
//
// Given a Vtr::Level and a face index, gathers all the influences of the 1-ring
// that supports the 20 CVs of a Gregory patch basis.
//
struct ProtoBasis {
ProtoBasis(Vtr::Level const & level, Index faceIndex, int fvarChannel=-1);
int GetNumElements() const;
void Copy(int * sizes, Index * indices, float * weights) const;
// Control Vertices based on :
// "Approximating Subdivision Surfaces with Gregory Patches for Hardware Tessellation"
// Loop, Schaefer, Ni, Castafio (ACM ToG Siggraph Asia 2009)
//
// P3 e3- e2+ P2
// O--------O--------O--------O
// | | | |
// | | | |
// | | f3- | f2+ |
// | O O |
// e3+ O------O O------O e2-
// | f3+ f2- |
// | |
// | |
// | f0- f1+ |
// e0- O------O O------O e1+
// | O O |
// | | f0+ | f1- |
// | | | |
// | | | |
// O--------O--------O--------O
// P0 e0+ e1- P1
//
Point P[4], Ep[4], Em[4], Fp[4], Fm[4];
// for varying interpolation
Point V[4];
};
private:
friend class GregoryBasisFactory;
friend class EndCapGregoryBasisPatchFactory;
int _sizes[20],
_offsets[20];
@ -75,82 +253,6 @@ private:
std::vector<float> _weights;
};
/// \brief A specialized factory to gather Gregory basis control vertices
///
class GregoryBasisFactory {
public:
//
// Single patch GregoryBasis basis factory
//
/// \brief Instantiates a GregoryBasis from a TopologyRefiner that has been
/// refined adaptively for a given face.
///
/// @param refiner The TopologyRefiner containing the topology
///
/// @param faceIndex The index of the face (level is assumed to be MaxLevel)
///
/// @param fvarChannel Index of face-varying channel topology (default -1)
///
static GregoryBasis const * Create(TopologyRefiner const & refiner,
Index faceIndex, int fvarChannel=-1);
/// \brief Returns the maximum valence of a vertex in the mesh that the
/// Gregory patches can handle
static int GetMaxValence();
public:
//
// Multi-patch Gregory stencils factory
//
// XXXX need to add support for face-varying channel stencils
// This factory accumulates vertex Gregory patch basis into StencilTables
//
// Note: the TopologyRefiner and StencilTables references are held for the
// lifespan of the factory - neither can be deleted or modified while
// this factory is active.
//
GregoryBasisFactory(TopologyRefiner const & refiner,
StencilTables const * stencils,
StencilTables const * varyingStencils,
int numpatches, int maxvalence);
// Creates a basis for the vertices specified in mask on the face and
// adds it to the stencil pool allocator
bool AddPatchBasis(Index faceIndex,
bool newVerticesMask[4][5]);
// After all the patches have been collected, create the final table
StencilTables const * CreateVertexStencilTables(int const permute[20]=0) {
return createStencilTables(permute, _alloc);
}
StencilTables const * CreateVaryingStencilTables(int const permute[20]=0) {
return createStencilTables(permute, _varyingAlloc);
}
private:
StencilTables const * createStencilTables(int const permute[20],
StencilAllocator &alloc);
// XXX: StencilAllocator method's constness needs to be fixed.
int _currentStencil;
TopologyRefiner const & _refiner; // XXXX these should be smart pointers !
Index _stencilsOffset;
StencilTables const * _stencils;
StencilTables const * _varyingStencils;
StencilAllocator _alloc;
StencilAllocator _varyingAlloc;
};
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION

View File

@ -233,9 +233,7 @@ InterpolateCornerPatch(Index const * cvs,
/// \brief Interpolate the (s,t) parametric location of a Gregory bicubic
/// patch
///
/// @param basisStencils Stencil tables driving the 20 CV basis of the patches
///
/// @param stencilIndex Index of the first CV stencil in the basis stencils tables
/// @param cvs Array of 20 control vertex indices
///
/// @param s Patch coordinate (in coarse face normalized space)
///
@ -255,8 +253,7 @@ InterpolateCornerPatch(Index const * cvs,
///
template <class T, class U>
inline void
InterpolateGregoryPatch(StencilTables const * basisStencils,
int stencilIndex, float s, float t,
InterpolateGregoryPatch(Index const *cvs, float s, float t,
float const * Q, float const *Qd1, float const *Qd2,
T const & src, U & dst) {
@ -281,76 +278,58 @@ InterpolateGregoryPatch(StencilTables const * basisStencils,
//
// P3 e3- e2+ P2
// O--------O--------O--------O
// 15------17-------11--------10
// | | | |
// | | | |
// | | f3- | f2+ |
// | O O |
// e3+ O------O O------O e2-
// | 19 13 |
// e3+ 16-----18 14-----12 e2-
// | f3+ f2- |
// | |
// | |
// | f0- f1+ |
// e0- O------O O------O e1+
// | O O |
// e0- 2------4 8------6 e1+
// | 3 9 |
// | | f0+ | f1- |
// | | | |
// | | | |
// O--------O--------O--------O
// O--------1--------7--------5
// P0 e0+ e1- P1
//
// XXXX manuelk re-order stencils in factory and get rid of permutation ?
int const permute[16] =
{ 0, 1, 7, 5, 2, -1, -1, 6, 16, -1, -1, 12, 15, 17, 11, 10 };
for (int i=0, fcount=0; i<16; ++i) {
// gregory-to-bezier map
static int const permute[16] =
{ 0, 1, 7, 5, 2, -1, -2, 6, 16, -3, -4, 12, 15, 17, 11, 10 };
int index = permute[i],
offset = stencilIndex;
for (int k = 0; k < 16; ++k) {
if (index==-1) {
// 0-ring vertex: blend 2 extra basis CVs
int const fpermute[4][2] = { {3, 4}, {9, 8}, {19, 18}, {13, 14} };
assert(fcount < 4);
int v0 = fpermute[fcount][0],
v1 = fpermute[fcount][1];
Stencil s0 = basisStencils->GetStencil(offset + v0),
s1 = basisStencils->GetStencil(offset + v1);
float w0=weights[fcount][0],
w1=weights[fcount][1];
{
Index const * srcIndices = s0.GetVertexIndices();
float const * srcWeights = s0.GetWeights();
for (int j=0; j<s0.GetSize(); ++j) {
dst.AddWithWeight(src[srcIndices[j]],
Q[i]*w0*srcWeights[j], Qd1[i]*w0*srcWeights[j],
Qd2[i]*w0*srcWeights[j]);
}
}
{
Index const * srcIndices = s1.GetVertexIndices();
float const * srcWeights = s1.GetWeights();
for (int j=0; j<s1.GetSize(); ++j) {
dst.AddWithWeight(src[srcIndices[j]],
Q[i]*w1*srcWeights[j], Qd1[i]*w1*srcWeights[j],
Qd2[i]*w1*srcWeights[j]);
}
}
++fcount;
} else {
Stencil stencil = basisStencils->GetStencil(offset + index);
Index const * srcIndices = stencil.GetVertexIndices();
float const * srcWeights = stencil.GetWeights();
for (int j=0; j<stencil.GetSize(); ++j) {
dst.AddWithWeight( src[srcIndices[j]],
Q[i]*srcWeights[j], Qd1[i]*srcWeights[j],
Qd2[i]*srcWeights[j]);
}
int index = permute[k];
if (index >=0) {
dst.AddWithWeight(src[cvs[index]], Q[k], Qd1[k], Qd2[k]);
} else if (index == -1) {
// 3, 4
float w0 = weights[0][0];
float w1 = weights[0][1];
dst.AddWithWeight(src[cvs[3]], w0*Q[k], w0*Qd1[k], w0*Qd2[k]);
dst.AddWithWeight(src[cvs[4]], w1*Q[k], w1*Qd1[k], w1*Qd2[k]);
} else if (index == -2) {
// 8, 9
float w0 = weights[1][0];
float w1 = weights[1][1];
dst.AddWithWeight(src[cvs[9]], w0*Q[k], w0*Qd1[k], w0*Qd2[k]);
dst.AddWithWeight(src[cvs[8]], w1*Q[k], w1*Qd1[k], w1*Qd2[k]);
} else if (index == -3) {
// 18, 19
float w0 = weights[2][0];
float w1 = weights[2][1];
dst.AddWithWeight(src[cvs[19]], w0*Q[k], w0*Qd1[k], w0*Qd2[k]);
dst.AddWithWeight(src[cvs[18]], w1*Q[k], w1*Qd1[k], w1*Qd2[k]);
} else if (index == -4) {
// 13, 14
float w0 = weights[3][0];
float w1 = weights[3][1];
dst.AddWithWeight(src[cvs[13]], w0*Q[k], w0*Qd1[k], w0*Qd2[k]);
dst.AddWithWeight(src[cvs[14]], w1*Q[k], w1*Qd1[k], w1*Qd2[k]);
}
}
}

View File

@ -1,82 +0,0 @@
//
// 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 FAR_KERNEL_BATCH_H
#define FAR_KERNEL_BATCH_H
#include "../version.h"
#include <vector>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
/// \brief A GP Compute Kernel descriptor.
///
/// Vertex refinement through subdivision schemes requires the successive
/// application of dedicated compute kernels. OpenSubdiv groups these vertices
/// in batches based on their topology in order to minimize the number of kernel
/// switches to process a given primitive.
///
struct KernelBatch {
public:
enum KernelType {
KERNEL_UNKNOWN=0,
KERNEL_STENCIL_TABLE,
KERNEL_USER_DEFINED
};
/// \brief Constructor.
///
/// @param _kernelType The type of compute kernel kernel
///
/// @param _level The level of subdivision of the vertices in the batch
///
/// @param _start Index of the first vertex in the batch
///
/// @param _end Index of the last vertex in the batch
///
KernelBatch( int _kernelType, int _level, int _start, int _end ) :
kernelType(_kernelType), level(_level), start(_start), end(_end) { }
int kernelType, // the type of compute kernel kernel
level, // the level of subdivision of the vertices in the batch
start, // index of the first vertex in the batch
end; // index of the last vertex in the batch
};
typedef std::vector<KernelBatch> KernelBatchVector;
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* FAR_KERNEL_BATCH_H */

View File

@ -1,164 +0,0 @@
//
// 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 FAR_KERNELBATCH_DISPATCHER_H
#define FAR_KERNELBATCH_DISPATCHER_H
#include "../version.h"
#include "../far/kernelBatch.h"
#include "../far/stencilTables.h"
#include <cassert>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
/// \brief Subdivision refinement encapsulation layer.
///
/// The kernel dispatcher allows client code to customize parts or the entire
/// computation process. This pattern aims at hiding the logic specific to
/// the subdivision algorithms and expose a simplified access to minimalistic
/// compute kernels. By default, meshes revert to a default dispatcher that
/// implements single-threaded CPU kernels.
///
/// - derive a dispatcher class from this one
/// - override the virtual functions
/// - pass the derived dispatcher to the factory (one instance can be shared by many meshes)
///
/// Note : the caller is responsible for deleting a custom dispatcher
///
class KernelBatchDispatcher {
public:
/// \brief Launches the processing of a vector of kernel batches
/// this is a convenient API for controllers which don't have any user defined kernels.
///
/// @param controller refinement controller implementation (vertex array)
///
/// @param context refinement context implementation (subdivision tables)
/// passed to the controller.
///
/// @param batches batches of kernels that need to be processed
///
/// @param maxlevel process vertex batches up to this level
///
template <class CONTROLLER, class CONTEXT> static void Apply(
CONTROLLER *controller, CONTEXT *context, KernelBatchVector const & batches, int maxlevel);
protected:
/// \brief Launches the processing of a kernel batch
/// returns true if the batch is handled, otherwise returns false (i.e. user defined kernel)
///
/// @param controller refinement controller implementation
///
/// @param context refinement context implementation
///
/// @param batch a batch of kernel that need to be processed
///
template <class CONTROLLER, class CONTEXT> static bool ApplyKernel(
CONTROLLER *controller, CONTEXT *context, KernelBatch const &batch);
};
///
/// \brief Far default controller implementation
///
/// This is Far's default implementation of a kernal batch controller.
///
class DefaultController {
public:
template <class CONTEXT> void ApplyStencilTableKernel(
KernelBatch const &batch, CONTEXT *context) const;
};
// Launches the processing of a kernel batch
template <class CONTROLLER, class CONTEXT> bool
KernelBatchDispatcher::ApplyKernel(CONTROLLER *controller, CONTEXT *context,
KernelBatch const &batch) {
if (batch.end==0) {
return true;
}
switch(batch.kernelType) {
case KernelBatch::KERNEL_UNKNOWN:
assert(0);
case KernelBatch::KERNEL_STENCIL_TABLE:
controller->ApplyStencilTableKernel(batch, context);
break;
default: // user defined kernel type
return false;
}
return true;
}
// Launches the processing of a vector of kernel batches
template <class CONTROLLER, class CONTEXT> void
KernelBatchDispatcher::Apply(CONTROLLER *controller, CONTEXT *context,
KernelBatchVector const & batches, int maxlevel) {
for (int i = 0; i < (int)batches.size(); ++i) {
const KernelBatch &batch = batches[i];
if (maxlevel>=0 and batch.level>=maxlevel) {
continue;
}
ApplyKernel(controller, context, batch);
}
}
template <class CONTEXT> void
DefaultController::ApplyStencilTableKernel(
KernelBatch const &batch, CONTEXT *context) const {
StencilTables const * stencilTables = context->GetStencilTables();
assert(stencilTables);
typename CONTEXT::VertexType *vsrc = &context->GetVertices().at(0),
*vdst = vsrc + batch.start + stencilTables->GetNumControlVertices();
stencilTables->UpdateValues(vsrc, vdst, batch.start, batch.end);
}
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* FAR_KERNELBATCH_DISPATCHER_H */

View File

@ -43,94 +43,18 @@ PatchDescriptor::GetAdaptivePatchDescriptors(Sdc::SchemeType type) {
static PatchDescriptor _loopDescriptors[] = {
// XXXX work in progress !
PatchDescriptor(LOOP, NON_TRANSITION, 0)
PatchDescriptor(LOOP),
};
static PatchDescriptor _catmarkDescriptors[] = {
// non-transition patches : 7
PatchDescriptor(REGULAR, NON_TRANSITION, 0),
PatchDescriptor(SINGLE_CREASE, NON_TRANSITION, 0),
PatchDescriptor(BOUNDARY, NON_TRANSITION, 0),
PatchDescriptor(CORNER, NON_TRANSITION, 0),
PatchDescriptor(GREGORY, NON_TRANSITION, 0),
PatchDescriptor(GREGORY_BOUNDARY, NON_TRANSITION, 0),
PatchDescriptor(GREGORY_BASIS, NON_TRANSITION, 0),
// transition pattern 0
PatchDescriptor(REGULAR, PATTERN0, 0),
PatchDescriptor(SINGLE_CREASE, PATTERN0, 0),
PatchDescriptor(SINGLE_CREASE, PATTERN0, 1),
PatchDescriptor(SINGLE_CREASE, PATTERN0, 2),
PatchDescriptor(SINGLE_CREASE, PATTERN0, 3),
PatchDescriptor(BOUNDARY, PATTERN0, 0),
PatchDescriptor(BOUNDARY, PATTERN0, 1),
PatchDescriptor(BOUNDARY, PATTERN0, 2),
PatchDescriptor(BOUNDARY, PATTERN0, 3),
PatchDescriptor(CORNER, PATTERN0, 0),
PatchDescriptor(CORNER, PATTERN0, 1),
PatchDescriptor(CORNER, PATTERN0, 2),
PatchDescriptor(CORNER, PATTERN0, 3),
// transition pattern 1
PatchDescriptor(REGULAR, PATTERN1, 0),
PatchDescriptor(SINGLE_CREASE, PATTERN1, 0),
PatchDescriptor(SINGLE_CREASE, PATTERN1, 1),
PatchDescriptor(SINGLE_CREASE, PATTERN1, 2),
PatchDescriptor(SINGLE_CREASE, PATTERN1, 3),
PatchDescriptor(BOUNDARY, PATTERN1, 0),
PatchDescriptor(BOUNDARY, PATTERN1, 1),
PatchDescriptor(BOUNDARY, PATTERN1, 2),
PatchDescriptor(BOUNDARY, PATTERN1, 3),
PatchDescriptor(CORNER, PATTERN1, 0),
PatchDescriptor(CORNER, PATTERN1, 1),
PatchDescriptor(CORNER, PATTERN1, 2),
PatchDescriptor(CORNER, PATTERN1, 3),
// transition pattern 2
PatchDescriptor(REGULAR, PATTERN2, 0),
PatchDescriptor(SINGLE_CREASE, PATTERN2, 0),
PatchDescriptor(SINGLE_CREASE, PATTERN2, 1),
PatchDescriptor(SINGLE_CREASE, PATTERN2, 2),
PatchDescriptor(SINGLE_CREASE, PATTERN2, 3),
PatchDescriptor(BOUNDARY, PATTERN2, 0),
PatchDescriptor(BOUNDARY, PATTERN2, 1),
PatchDescriptor(BOUNDARY, PATTERN2, 2),
PatchDescriptor(BOUNDARY, PATTERN2, 3),
PatchDescriptor(CORNER, PATTERN2, 0),
PatchDescriptor(CORNER, PATTERN2, 1),
PatchDescriptor(CORNER, PATTERN2, 2),
PatchDescriptor(CORNER, PATTERN2, 3),
// transition pattern 3
PatchDescriptor(REGULAR, PATTERN3, 0),
PatchDescriptor(SINGLE_CREASE, PATTERN3, 0),
PatchDescriptor(SINGLE_CREASE, PATTERN3, 1),
PatchDescriptor(SINGLE_CREASE, PATTERN3, 2),
PatchDescriptor(SINGLE_CREASE, PATTERN3, 3),
PatchDescriptor(BOUNDARY, PATTERN3, 0),
PatchDescriptor(BOUNDARY, PATTERN3, 1),
PatchDescriptor(BOUNDARY, PATTERN3, 2),
PatchDescriptor(BOUNDARY, PATTERN3, 3),
PatchDescriptor(CORNER, PATTERN3, 0),
PatchDescriptor(CORNER, PATTERN3, 1),
PatchDescriptor(CORNER, PATTERN3, 2),
PatchDescriptor(CORNER, PATTERN3, 3),
// transition pattern 4
PatchDescriptor(REGULAR, PATTERN4, 0),
PatchDescriptor(SINGLE_CREASE, PATTERN4, 0),
PatchDescriptor(SINGLE_CREASE, PATTERN4, 1),
PatchDescriptor(SINGLE_CREASE, PATTERN4, 2),
PatchDescriptor(SINGLE_CREASE, PATTERN4, 3),
PatchDescriptor(BOUNDARY, PATTERN4, 0),
PatchDescriptor(BOUNDARY, PATTERN4, 1),
PatchDescriptor(BOUNDARY, PATTERN4, 2),
PatchDescriptor(BOUNDARY, PATTERN4, 3),
PatchDescriptor(CORNER, PATTERN4, 0),
PatchDescriptor(CORNER, PATTERN4, 1),
PatchDescriptor(CORNER, PATTERN4, 2),
PatchDescriptor(CORNER, PATTERN4, 3),
// XXXdyu-patch-drawing
PatchDescriptor(REGULAR),
PatchDescriptor(BOUNDARY),
PatchDescriptor(CORNER),
PatchDescriptor(GREGORY),
PatchDescriptor(GREGORY_BOUNDARY),
PatchDescriptor(GREGORY_BASIS),
};
switch (type) {
@ -155,8 +79,8 @@ PatchDescriptor::print() const {
"SINGLE_CREASE", "BOUNDARY", "CORNER", "GREGORY",
"GREGORY_BOUNDARY", "GREGORY_BASIS" };
printf(" type %s trans %d rot %d\n",
types[_type], _pattern, _rotation);
printf(" type %s\n",
types[_type]);
}

View File

@ -45,17 +45,15 @@ namespace Far {
/// or TRIANGLES
///
/// * Adaptively subdivided meshes contain bicubic patches of types REGULAR,
/// BOUNDARY, SINGLE_CREASE, CORNER, GREGORY, GREGORY_BOUNDARY, GREGOYR_BASIS.
/// BOUNDARY, CORNER, GREGORY, GREGORY_BOUNDARY, GREGOYR_BASIS.
/// These bicubic patches are also further distinguished by a transition
/// pattern as well as a rotational orientation.
///
/// Bitfield layout :
///
/// Field | Bits | Content
/// -----------|:----:|------------------------------------------------------
/// _type | 4 | patch type
/// _pattern | 3 | patch transition pattern
/// _rotation | 2 | patch rotation
/// Field | Bits | Content
/// ------------|:----:|------------------------------------------------------
/// _type | 4 | patch type
///
class PatchDescriptor {
@ -73,7 +71,6 @@ public:
LOOP, ///< Loop patch
REGULAR, ///< feature-adaptive bicubic patches
SINGLE_CREASE,
BOUNDARY,
CORNER,
GREGORY,
@ -81,44 +78,25 @@ public:
GREGORY_BASIS
};
enum TransitionPattern {
NON_TRANSITION = 0,
PATTERN0,
PATTERN1,
PATTERN2,
PATTERN3,
PATTERN4
};
public:
/// \brief Default constructor.
PatchDescriptor() :
_type(NON_PATCH), _pattern(NON_TRANSITION), _rotation(0) {}
_type(NON_PATCH) { }
/// \brief Constructor
PatchDescriptor(int type, int pattern, unsigned char rotation) :
_type(type), _pattern(pattern), _rotation(rotation) { }
PatchDescriptor(int type) :
_type(type) { }
/// \brief Copy Constructor
PatchDescriptor( PatchDescriptor const & d ) :
_type(d.GetType()), _pattern(d.GetPattern()), _rotation(d.GetRotation()) { }
_type(d.GetType()) { }
/// \brief Returns the type of the patch
Type GetType() const {
return (Type)_type;
}
/// \brief Returns the transition pattern of the patch if any (5 types)
TransitionPattern GetPattern() const {
return (TransitionPattern)_pattern;
}
/// \brief Returns the rotation of the patch (4 rotations)
unsigned char GetRotation() const {
return (unsigned char)_rotation;
}
/// \brief Returns true if the type is an adaptive patch
static inline bool IsAdaptive(Type type) {
return (type>=LOOP and type<=GREGORY_BASIS);
@ -151,10 +129,10 @@ public:
static short GetRegularPatchSize() { return 16; }
/// \brief Number of control vertices of Boundary Patches in table.
static short GetBoundaryPatchSize() { return 12; }
static short GetBoundaryPatchSize() { return 16; }
/// \brief Number of control vertices of Boundary Patches in table.
static short GetCornerPatchSize() { return 9; }
static short GetCornerPatchSize() { return 16; }
/// \brief Number of control vertices of Gregory (and Gregory Boundary) Patches in table.
static short GetGregoryPatchSize() { return 4; }
@ -177,11 +155,7 @@ public:
void print() const;
private:
friend class PatchTablesFactory;
unsigned int _type:4;
unsigned int _pattern:3;
unsigned int _rotation:2;
};
typedef Vtr::ConstArray<PatchDescriptor> ConstPatchDescriptorArray;
@ -191,7 +165,6 @@ inline short
PatchDescriptor::GetNumControlVertices( Type type ) {
switch (type) {
case REGULAR : return GetRegularPatchSize();
case SINGLE_CREASE : return GetRegularPatchSize();
case QUADS : return 4;
case GREGORY :
case GREGORY_BOUNDARY : return GetGregoryPatchSize();
@ -210,7 +183,6 @@ inline short
PatchDescriptor::GetNumFVarControlVertices( Type type ) {
switch (type) {
case REGULAR : return GetRegularPatchSize();
case SINGLE_CREASE : return GetRegularPatchSize();
case QUADS : return 4;
case TRIANGLES : return 3;
case BOUNDARY : return GetBoundaryPatchSize();
@ -227,17 +199,13 @@ PatchDescriptor::GetNumFVarControlVertices( Type type ) {
// Allows ordering of patches by type
inline bool
PatchDescriptor::operator < ( PatchDescriptor const other ) const {
return _pattern < other._pattern or ((_pattern == other._pattern) and
(_type < other._type or ((_type == other._type) and
(_rotation < other._rotation))));
return (_type < other._type);
}
// True if the descriptors are identical
inline bool
PatchDescriptor::operator == ( PatchDescriptor const other ) const {
return _pattern == other._pattern and
_type == other._type and
_rotation == other._rotation;
return _type == other._type;
}

View File

@ -48,12 +48,12 @@ namespace Far {
///
/// Field | Bits | Content
/// -----------|:----:|------------------------------------------------------
/// level | 4 | the subdivision level of the patch
/// level | 3 | the subdivision level of the patch
/// nonquad | 1 | whether the patch is the child of a non-quad face
/// rotation | 2 | patch rotations necessary to match CCW face-winding
/// boundary | 4 | boundary edge mask encoding
/// transition | 4 | transition 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
/// reserved1 | 5 | padding
///
/// Note : the bitfield is not expanded in the struct due to differences in how
/// GPU & CPU compilers pack bit-fields and endian-ness.
@ -73,28 +73,35 @@ struct PatchParam {
/// @param depth subdivision level of the patch
/// @param nonquad true if the root face is not a quad
///
void Set( short u, short v, unsigned char rots, unsigned char depth, bool nonquad );
void Set( short u, short v, unsigned char depth, bool nonquad,
unsigned short boundary, unsigned short transition );
/// \brief Returns the log2 value of the u parameter at the top left corner of
/// the patch
unsigned short GetU() const { return (unsigned short)((field >> 17) & 0x3ff); }
unsigned short GetU() const { return (unsigned short)((field >> 22) & 0x3ff); }
/// \brief Returns the log2 value of the v parameter at the top left corner of
/// the patch
unsigned short GetV() const { return (unsigned short)((field >> 7) & 0x3ff); }
unsigned short GetV() const { return (unsigned short)((field >> 12) & 0x3ff); }
/// \brief Returns the rotation of the patch (the number of CCW parameter winding)
unsigned char GetRotation() const { return (unsigned char)((field >> 5) & 0x3); }
/// \brief Returns the transition edge encoding for the patch.
unsigned short GetTransition() const { return (unsigned short)((field >> 8) & 0xf); }
/// \brief Returns the boundary edge encoding for the patch.
unsigned short GetBoundary() const { return (unsigned short)((field >> 4) & 0xf); }
/// \brief Deprecated XXXdyu-patch-drawing (patches rotated when gathered from refiner)
unsigned char GetRotation() const { return 0; }
/// \brief True if the parent coarse face is a non-quad
bool NonQuadRoot() const { return (field >> 4) & 0x1; }
bool NonQuadRoot() const { return (field >> 3) & 0x1; }
/// \brief Returns the fratcion of normalized parametric space covered by the
/// sub-patch.
float GetParamFraction() const;
/// \brief Returns the level of subdivision of the patch
unsigned char GetDepth() const { return (unsigned char)(field & 0xf); }
unsigned char GetDepth() const { return (unsigned char)(field & 0x7); }
/// The (u,v) pair is normalized to this sub-parametric space.
///
@ -103,14 +110,6 @@ struct PatchParam {
///
void Normalize( float & u, float & v ) const;
/// \brief Rotate (u,v) pair to compensate for transition pattern and boundary
/// orientations.
///
/// @param u u parameter
/// @param v v parameter
///
void Rotate( float & u, float & v ) const;
/// \brief Resets the values to 0
void Clear() { field = 0; }
@ -127,7 +126,8 @@ struct PatchParam {
/// @param depth subdivision level of the patch
/// @param nonquad true if the root face is not a quad
///
void Set( Index faceid, short u, short v, unsigned char rots, unsigned char depth, bool nonquad );
void Set( Index faceid, short u, short v, unsigned char depth, bool nonquad ,
unsigned short boundary, unsigned short transition );
/// \brief Resets everything to 0
void Clear();
@ -139,11 +139,13 @@ typedef Vtr::Array<PatchParam> PatchParamArray;
typedef Vtr::ConstArray<PatchParam> ConstPatchParamArray;
inline void
PatchParam::BitField::Set( short u, short v, unsigned char rots, unsigned char depth, bool nonquad ) {
field = (u << 17) |
(v << 7) |
(rots << 5) |
((nonquad ? 1:0) << 4) |
PatchParam::BitField::Set( short u, short v, unsigned char depth, bool nonquad,
unsigned short boundary, unsigned short transition ) {
field = (u << 22) |
(v << 12) |
(transition << 8) |
(boundary << 4) |
((nonquad ? 1:0) << 3) |
(nonquad ? depth+1 : depth);
}
@ -172,21 +174,10 @@ PatchParam::BitField::Normalize( float & u, float & v ) const {
}
inline void
PatchParam::BitField::Rotate( float & u, float & v ) const {
switch( GetRotation() ) {
case 0 : break;
case 1 : { float tmp=v; v=1.0f-u; u=tmp; } break;
case 2 : { u=1.0f-u; v=1.0f-v; } break;
case 3 : { float tmp=u; u=1.0f-v; v=tmp; } break;
default:
assert(0);
}
}
inline void
PatchParam::Set( Index faceid, short u, short v, unsigned char rots, unsigned char depth, bool nonquad ) {
PatchParam::Set( Index faceid, short u, short v, unsigned char depth, bool nonquad,
unsigned short boundary, unsigned short transition ) {
faceIndex = faceid;
bitField.Set(u,v,rots,depth,nonquad);
bitField.Set(u,v,depth,nonquad,boundary,transition);
}
inline void

View File

@ -33,9 +33,8 @@ namespace OPENSUBDIV_VERSION {
namespace Far {
PatchTables::PatchTables(int maxvalence) :
_maxValence(maxvalence),
_endcapVertexStencilTables(0),
_endcapVaryingStencilTables(0) { }
_maxValence(maxvalence) {
}
// Copy constructor
// XXXX manuelk we need to eliminate this constructor (C++11 smart pointers)
@ -50,16 +49,9 @@ PatchTables::PatchTables(PatchTables const & src) :
_fvarChannels(src._fvarChannels),
_sharpnessIndices(src._sharpnessIndices),
_sharpnessValues(src._sharpnessValues) {
_endcapVertexStencilTables = src._endcapVertexStencilTables ?
new StencilTables(*src._endcapVertexStencilTables) : 0;
_endcapVaryingStencilTables = src._endcapVaryingStencilTables ?
new StencilTables(*src._endcapVaryingStencilTables) : 0;
}
PatchTables::~PatchTables() {
delete _endcapVertexStencilTables;
delete _endcapVaryingStencilTables;
}
//
@ -399,7 +391,7 @@ bool
PatchTables::IsFeatureAdaptive() const {
// check for presence of tables only used by adaptive patches
if (not _vertexValenceTable.empty() or _endcapVertexStencilTables)
if (not _vertexValenceTable.empty())
return true;
// otherwise, we have to check each patch array

View File

@ -29,8 +29,6 @@
#include "../far/interpolate.h"
#include "../far/patchDescriptor.h"
#include "../far/stencilTables.h"
#include "../far/stencilTables.h"
#include "../sdc/options.h"
@ -173,10 +171,6 @@ public:
return _vertexValenceTable;
}
/// \brief Returns a stencil table for the control vertices of end-cap patches
StencilTables const * GetEndCapVertexStencilTables() const { return _endcapVertexStencilTables; }
StencilTables const * GetEndCapVaryingStencilTables() const { return _endcapVaryingStencilTables; }
//@}
@ -336,7 +330,9 @@ public:
protected:
friend class PatchTablesFactory;
template <class T> friend class PatchTablesFactoryT;
friend class PatchTablesFactoryBase;
friend class EndCapLegacyGregoryPatchFactory;
// Factory constructor
PatchTables(int maxvalence);
@ -414,10 +410,6 @@ private:
// Extraordinary vertex closed-form evaluation
//
// XXXX manuelk end-cap stencils will obsolete the other tables
StencilTables const * _endcapVertexStencilTables;
StencilTables const * _endcapVaryingStencilTables;
QuadOffsetsTable _quadOffsetsTable; // Quad offsets (for Gregory patches)
VertexValenceTable _vertexValenceTable; // Vertex valence table (for Gregory patches)
@ -461,40 +453,23 @@ PatchTables::Evaluate(PatchHandle const & handle, float s, float t,
float Q[16], Qd1[16], Qd2[16];
if (ptype>=PatchDescriptor::REGULAR and ptype<=PatchDescriptor::CORNER) {
if (ptype==PatchDescriptor::REGULAR) {
GetBSplineWeights(bits, s, t, Q, Qd1, Qd2);
ConstIndexArray cvs = GetPatchVertices(handle);
switch (ptype) {
case PatchDescriptor::REGULAR:
InterpolateRegularPatch(cvs.begin(), Q, Qd1, Qd2, src, dst);
break;
case PatchDescriptor::SINGLE_CREASE:
// TODO: implement InterpolateSingleCreasePatch().
//InterpolateRegularPatch(cvs, Q, Qd1, Qd2, src, dst);
break;
case PatchDescriptor::BOUNDARY:
InterpolateBoundaryPatch(cvs.begin(), Q, Qd1, Qd2, src, dst);
break;
case PatchDescriptor::CORNER:
InterpolateCornerPatch(cvs.begin(), Q, Qd1, Qd2, src, dst);
break;
case PatchDescriptor::GREGORY:
case PatchDescriptor::GREGORY_BOUNDARY:
assert(0);
break;
default:
assert(0);
}
InterpolateRegularPatch(cvs.begin(), Q, Qd1, Qd2, src, dst);
// XXXdyu bits InterpolateBoundaryPatch(cvs.begin(), Q, Qd1, Qd2, src, dst);
// XXXdyu bits InterpolateCornerPatch(cvs.begin(), Q, Qd1, Qd2, src, dst);
} else if (ptype==PatchDescriptor::GREGORY_BASIS) {
assert(_endcapVertexStencilTables);
ConstIndexArray cvs = GetPatchVertices(handle);
GetBezierWeights(bits, s, t, Q, Qd1, Qd2);
InterpolateGregoryPatch(_endcapVertexStencilTables, handle.vertIndex,
s, t, Q, Qd1, Qd2, src, dst);
InterpolateGregoryPatch(cvs.begin(), s, t, Q, Qd1, Qd2, src, dst);
} else if (ptype==PatchDescriptor::QUADS) {
@ -536,14 +511,8 @@ PatchTables::EvaluateFaceVarying(int channel, PatchHandle const & handle,
case PatchDescriptor::REGULAR:
GetBSplineWeights(bits, s, t, Q, Qd1, Qd2);
InterpolateRegularPatch(cvs.begin(), Q, Qd1, Qd2, src, dst);
break;
case PatchDescriptor::BOUNDARY:
GetBSplineWeights(bits, s, t, Q, Qd1, Qd2);
InterpolateBoundaryPatch(cvs.begin(), Q, Qd1, Qd2, src, dst);
break;
case PatchDescriptor::CORNER:
GetBSplineWeights(bits, s, t, Q, Qd1, Qd2);
InterpolateCornerPatch(cvs.begin(), Q, Qd1, Qd2, src, dst);
// XXXdyu bits InterpolateBoundaryPatch(cvs.begin(), Q, Qd1, Qd2, src, dst);
// XXXdyu bits InterpolateCornerPatch(cvs.begin(), Q, Qd1, Qd2, src, dst);
break;
default:
assert(0);

File diff suppressed because it is too large Load Diff

View File

@ -37,19 +37,46 @@ namespace Vtr { class Level; }
namespace Far {
class StencilTables;
class PtexIndices;
class TopologyRefiner;
/// \brief A specialized factory for feature adaptive PatchTables
///
/// PatchTables contain the lists of vertices for each patch of an adaptive
/// mesh representation.
///
class PatchTablesFactory {
class PatchTablesFactoryBase {
public:
// PatchFaceTag
// A simple struct containing all information gathered about a face that is relevant
// to constructing a patch for it (some of these enums should probably be defined more
// as part of PatchTables)
//
// Like the HbrFace<T>::AdaptiveFlags, this struct aggregates all of the face tags
// supporting feature adaptive refinement. For now it is not used elsewhere and can
// remain local to this implementation, but we may want to move it into a header of
// its own if it has greater use later.
//
// Note that several properties being assigned here attempt to do so given a 4-bit
// mask of properties at the edges or vertices of the quad. Still not sure exactly
// what will be done this way, but the goal is to create lookup tables (of size 16
// for the 4 bits) to quickly determine was is needed, rather than iteration and
// branching on the edges or vertices.
//
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 transitionMask) {
_transitionMask = transitionMask;
}
};
typedef std::vector<PatchFaceTag> PatchTagVector;
struct Options {
@ -61,9 +88,7 @@ public:
generateFVarTables(false),
useFVarQuadEndCaps(true), // XXXX change to false when FVar Gregory is ready
numFVarChannels(-1),
fvarChannelIndices(0),
adaptiveStencilTables(0),
adaptiveVaryingStencilTables(0)
fvarChannelIndices(0)
{ }
unsigned int generateAllLevels : 1, ///< Include levels from 'firstLevel' to 'maxLevel' (Uniform mode only)
@ -77,48 +102,28 @@ public:
int numFVarChannels; ///< Number of channel indices and interpolation modes passed
int const * fvarChannelIndices; ///< List containing the indices of the channels selected for the factory
StencilTables const * adaptiveStencilTables; ///< Passing a valid stencil table allows the factory to generate
///< stencils for gregory patches and replace them with a much
///< more efficient basis.
StencilTables const * adaptiveVaryingStencilTables;
};
/// \brief Factory constructor for PatchTables
///
/// @param refiner TopologyRefiner from which to generate patches
/// @param refiner TopologyRefiner from which to generate patches
///
/// @param options Options controlling the creation of the tables
/// @param options Options controlling the creation of the tables
///
/// @return A new instance of PatchTables
/// @return A new instance of PatchTables
///
static PatchTables * Create(TopologyRefiner const & refiner, Options options=Options());
private:
static PatchTables * Create(TopologyRefiner const & refiner,
PatchTablesFactoryBase::Options options=Options());
protected:
//
// Private helper structures
//
struct AdaptiveContext;
private:
static PatchTables * createUniform(TopologyRefiner const & refiner, Options options);
static PatchTables * createAdaptive(TopologyRefiner const & refiner, Options options);
//
// High-level methods for identifying and populating patches associated with faces:
//
static void identifyAdaptivePatches(AdaptiveContext & state);
static void populateAdaptivePatches(AdaptiveContext & state);
//
// Methods for allocating and managing the patch table data arrays:
//
static PatchTables * createUniform(TopologyRefiner const & refiner, Options options);
static void allocateVertexTables(PatchTables * tables, int nlevels, bool hasSharpness);
@ -126,16 +131,72 @@ private:
Options options, int npatches, PatchTables * tables);
static PatchParam * computePatchParam(TopologyRefiner const & refiner,
int level, int face, int rotation, PatchParam * coord);
PtexIndices const & ptexIndices,
int level, int face, int rotation,
int boundaryMask, int transitionMask, PatchParam * coord);
static int gatherFVarData(AdaptiveContext & state,
int level, Index faceIndex, Index levelFaceOffset, int rotation, Index const * levelOffsets, Index fofss, Index ** fptrs);
int level, Index faceIndex, Index levelFaceOffset, int rotation,
Index const * levelOffsets, Index fofss, Index ** fptrs);
static void getQuadOffsets(Vtr::Level const & level, int face, unsigned int * result);
};
/// \brief a templated patchtable factory parameterized by end cap strategy class..
///
///
template <typename ENDCAP_FACTORY>
class PatchTablesFactoryT : public PatchTablesFactoryBase {
public:
/// \brief Factory constructor for PatchTables
///
/// @param refiner TopologyRefiner from which to generate patches
///
/// @param options Options controlling the creation of the tables
///
/// @param endCapFactory If provided, it accumulates end patches
/// for later patch/stencil generation
///
/// @return A new instance of PatchTables
///
static PatchTables * Create(TopologyRefiner const & refiner,
PatchTablesFactoryBase::Options options=Options(),
ENDCAP_FACTORY *endCapFactory=NULL);
private:
static PatchTables * createAdaptive(TopologyRefiner const & refiner, Options options,
ENDCAP_FACTORY *);
//
// High-level methods for identifying and populating patches associated with faces:
//
static void identifyAdaptivePatches(AdaptiveContext & state, ENDCAP_FACTORY *);
static void populateAdaptivePatches(AdaptiveContext & state,
PtexIndices const & ptexIndices, ENDCAP_FACTORY *);
private:
};
/// \brief Default endcap factory (does nothing for end cap)
///
///
class EndCapNoneFactory {
public:
PatchDescriptor::Type GetPatchType(PatchTablesFactoryBase::PatchFaceTag const &) const {
return PatchDescriptor::NON_PATCH;
}
ConstIndexArray GetTopology(Vtr::Level const &/*level*/, Index /*faceIndex*/,
PatchTablesFactoryBase::PatchFaceTag const * /*levelPatchTags*/,
int /*levelVertOffset*/) {
return ConstIndexArray();
}
};
typedef PatchTablesFactoryT<EndCapNoneFactory> PatchTablesFactory;
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
@ -143,4 +204,5 @@ using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* FAR_PATCH_TABLES_FACTORY_H */

View 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());
if (regFaceSize != 4) {
Far::Error(FAR_CODING_ERROR,
"Ptex Indices may only be built for quad subdivision schemes "
"(e.g., catmark).");
// last entry contains the number of ptex texture faces
_ptexIndices.push_back(0);
return;
}
Vtr::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::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 {
assert(Sdc::SchemeTypeTraits::GetRegularFaceSize(refiner.GetSchemeType()) == 4);
Vtr::Level const & level = refiner.getLevel(0);
ConstIndexArray fedges = level.getFaceEdges(face);
if (fedges.size()==4) {
// Regular ptex quad face
for (int i=0; i<4; ++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()==4) {
adjFaces[i] = _ptexIndices[adjface];
adjEdges[i] = aedges.FindIndexIn4Tuple(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);
}
}
} else {
// 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 and 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 outisde 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 outisde 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);
}
}
}
}
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv

View 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 FAR_PTEX_INDICES_H
#define 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 /* FAR_PTEX_INDICES_H */

View File

@ -100,9 +100,10 @@ public:
}
protected:
friend class GregoryBasisFactory;
friend class StencilTablesFactory;
friend class LimitStencilTablesFactory;
friend class EndCapGregoryBasisPatchFactory;
friend class EndCapRegularPatchFactory;
unsigned char * _size;
Index * _indices;
@ -203,9 +204,11 @@ protected:
void resize(int nstencils, int nelems);
protected:
StencilTables() : _numControlVertices(0) {}
friend class StencilTablesFactory;
friend class GregoryBasisFactory;
friend class EndCapGregoryBasisPatchFactory;
friend class EndCapRegularPatchFactory;
int _numControlVertices; // number of control vertices

View File

@ -23,6 +23,7 @@
//
#include "../far/stencilTablesFactory.h"
#include "../far/endCapGregoryBasisPatchFactory.h"
#include "../far/patchTablesFactory.h"
#include "../far/patchMap.h"
#include "../far/protoStencil.h"
@ -60,6 +61,9 @@ StencilTablesFactory::Create(TopologyRefiner const & refiner,
StencilTables * result = new StencilTables;
// always initialize numControlVertices (useful for torus case)
result->_numControlVertices = refiner.GetNumVertices(0);
int maxlevel = std::min(int(options.maxLevel), refiner.GetMaxLevel());
if (maxlevel==0 and (not options.generateControlVerts)) {
return result;
@ -299,16 +303,28 @@ LimitStencilTablesFactory::Create(TopologyRefiner const & refiner,
// If a stencil table was given, use it, otherwise, create a new one
PatchTables const * patchtables = patchTables;
EndCapGregoryBasisPatchFactory * gregoryBasisFactory = NULL;
if (not patchTables) {
// XXXX (manuelk) If no patch-tables was passed, we should be able to
// infer the patches fairly easily from the refiner. Once more tags
// have been added to the refiner, maybe we can remove the need for the
// patch tables.
OpenSubdiv::Far::PatchTablesFactory::Options options;
options.adaptiveStencilTables = cvstencils;
PatchTablesFactoryBase::Options options;
patchtables = PatchTablesFactory::Create(refiner, options);
gregoryBasisFactory = new EndCapGregoryBasisPatchFactory(
refiner, /*shareBoundaryVertices=*/true);
patchtables = PatchTablesFactoryT<EndCapGregoryBasisPatchFactory>::Create(
refiner, options, gregoryBasisFactory);
if (not cvStencils) {
// if cvstencils is just created above
if (StencilTables const *stencilTablesWithGregoryBasis =
gregoryBasisFactory->CreateVertexStencilTables(cvstencils, true)) {
delete cvstencils;
cvstencils = stencilTablesWithGregoryBasis;
}
}
} else {
// Sanity checks
if (patchTables->IsFeatureAdaptive()==uniform) {
@ -395,15 +411,6 @@ LimitStencilTablesFactory::Create(TopologyRefiner const & refiner,
return result;
}
//------------------------------------------------------------------------------
KernelBatch
StencilTablesFactory::Create(StencilTables const &stencilTables) {
return KernelBatch( KernelBatch::KERNEL_STENCIL_TABLE,
-1, 0, stencilTables.GetNumStencils());
}
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION

View File

@ -27,7 +27,6 @@
#include "../version.h"
#include "../far/kernelBatch.h"
#include "../far/patchTables.h"
#include <vector>
@ -103,13 +102,6 @@ public:
///
static StencilTables const * Create(int numTables, StencilTables const ** tables);
/// \brief Returns a KernelBatch applying all the stencil in the tables
/// to primvar data.
///
/// @param stencilTables The stencil tables to batch
///
static KernelBatch Create(StencilTables const &stencilTables);
private:
// Generate stencils for the coarse control-vertices (single weight = 1.0f)

View File

@ -175,167 +175,6 @@ TopologyRefiner::GetNumHoles(int level) const {
return sum;
}
//
// Ptex information accessors
//
void
TopologyRefiner::initializePtexIndices() const {
Vtr::Level const & coarseLevel = getLevel(0);
std::vector<int> & ptexIndices = const_cast<std::vector<int> &>(_ptexIndices);
int nfaces = coarseLevel.getNumFaces();
ptexIndices.resize(nfaces+1);
int ptexID=0;
int regFaceSize = Sdc::SchemeTypeTraits::GetRegularFaceSize(GetSchemeType());
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
TopologyRefiner::GetNumPtexFaces() const {
if (_ptexIndices.empty()) {
initializePtexIndices();
}
return _ptexIndices.back();
}
int
TopologyRefiner::GetPtexIndex(Index f) const {
if (_ptexIndices.empty()) {
initializePtexIndices();
}
assert(f<(int)_ptexIndices.size());
return _ptexIndices[f];
}
namespace {
// Returns the face adjacent to 'face' along edge 'edge'
inline Index
getAdjacentFace(Vtr::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
TopologyRefiner::GetPtexAdjacency(int face, int quadrant,
int adjFaces[4], int adjEdges[4]) const {
assert(GetSchemeType()==Sdc::SCHEME_CATMARK);
if (_ptexIndices.empty()) {
initializePtexIndices();
}
Vtr::Level const & level = getLevel(0);
ConstIndexArray fedges = level.getFaceEdges(face);
if (fedges.size()==4) {
// Regular ptex quad face
for (int i=0; i<4; ++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()==4) {
adjFaces[i] = _ptexIndices[adjface];
adjEdges[i] = aedges.FindIndexIn4Tuple(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);
}
}
} else {
// 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 and 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 outisde 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 outisde 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);
}
}
}
}
//
// Main refinement method -- allocating and initializing levels and refinements:

View File

@ -37,6 +37,7 @@
#include "../vtr/fvarRefinement.h"
#include "../vtr/maskInterfaces.h"
#include "../far/types.h"
#include "../far/error.h"
#include <vector>
#include <cassert>
@ -487,32 +488,6 @@ public:
//@}
//@{
/// Ptex
///
/// \brief Returns the number of ptex faces in the mesh
int GetNumPtexFaces() const;
/// \brief Returns the ptex face index given a coarse face 'f' or -1
int GetPtexIndex(Index f) const;
/// \brief Returns ptex face adjacency information for a given coarse face
///
/// @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 GetPtexAdjacency(int face, int quadrant,
int adjFaces[4], int adjEdges[4]) const;
//@}
//@{
/// @name Debugging aides
@ -586,8 +561,12 @@ protected:
// Lower level protected methods intended strictly for internal use:
//
friend class TopologyRefinerFactoryBase;
friend class GregoryBasisFactory;
friend class PatchTablesFactory;
friend class PatchTablesFactoryBase;
template <class T> friend class Far::PatchTablesFactoryT;
friend class EndCapLegacyGregoryPatchFactory;
friend class EndCapGregoryBasisPatchFactory;
friend class EndCapRegularPatchFactory;
friend class PtexIndices;
Vtr::Level & getLevel(int l) { return *_levels[l]; }
Vtr::Level const & getLevel(int l) const { return *_levels[l]; }
@ -614,7 +593,6 @@ private:
template <Sdc::SchemeType SCHEME, class T, class U> void faceVaryingLimit(T const & src, U * dst, int channel) const;
void initializePtexIndices() const;
void initializeInventory();
void updateInventory(Vtr::Level const & newLevel);
@ -644,8 +622,6 @@ private:
std::vector<Vtr::Level *> _levels;
std::vector<Vtr::Refinement *> _refinements;
std::vector<Index> _ptexIndices;
};
@ -1418,7 +1394,11 @@ template <class T, class U>
inline void
TopologyRefiner::Limit(T const & src, U * dst) const {
assert(GetMaxLevel() > 0);
if (getLevel(GetMaxLevel()).getNumVertexEdgesTotal() == 0) {
Error(FAR_RUNTIME_ERROR,
"Cannot compute limit points -- last level of refinement does not include full topology.");
return;
}
switch (_subdivType) {
case Sdc::SCHEME_CATMARK:
@ -1461,6 +1441,18 @@ TopologyRefiner::limit(T const & src, U * dst) const {
for (int vert = 0; vert < level.getNumVertices(); ++vert) {
ConstIndexArray vEdges = level.getVertexEdges(vert);
// Incomplete vertices (present in sparse refinement) do not have their full
// topological neighborhood to determine a proper limit -- just leave the
// vertex at the refined location and continue to the next:
//
if (level._vertTags[vert]._incomplete || (vEdges.size() == 0)) {
dst[vert].Clear();
dst[vert].AddWithWeight(src[vert], 1.0);
continue;
}
// Assign the mask weights to the common buffer and compute the mask:
//
float * vWeights = weightBuffer,
* eWeights = vWeights + 1,
* fWeights = eWeights + vEdges.size();
@ -1470,7 +1462,7 @@ TopologyRefiner::limit(T const & src, U * dst) const {
// This is a bit obscure -- child vertex index will be ignored here
vHood.SetIndex(vert, vert);
scheme.ComputeVertexLimitMask(vHood, vMask);
scheme.ComputeVertexLimitMask(vHood, vMask, level.getVertexRule(vert));
// Apply the weights to the vertex, the vertices opposite its incident
// edges, and the opposite vertices of its incident faces:
@ -1512,7 +1504,11 @@ template <class T, class U>
inline void
TopologyRefiner::LimitFaceVarying(T const & src, U * dst, int channel) const {
assert(GetMaxLevel() > 0);
if (getLevel(GetMaxLevel()).getNumVertexEdgesTotal() == 0) {
Error(FAR_RUNTIME_ERROR,
"Cannot compute limit points -- last level of refinement does not include full topology.");
return;
}
switch (_subdivType) {
case Sdc::SCHEME_CATMARK:
@ -1546,21 +1542,31 @@ TopologyRefiner::faceVaryingLimit(T const & src, U * dst, int channel) const {
for (int vert = 0; vert < level.getNumVertices(); ++vert) {
ConstIndexArray vEdges = level.getVertexEdges(vert);
ConstIndexArray vValues = fvarChannel.getVertexValues(vert);
// Incomplete vertices (present in sparse refinement) do not have their full
// topological neighborhood to determine a proper limit -- just leave the
// values (perhaps more than one per vertex) at the refined location.
//
// The same can be done if the face-varying channel is purely linear.
//
bool isIncomplete = (level._vertTags[vert]._incomplete || (vEdges.size() == 0));
if (isIncomplete || fvarChannel._isLinear) {
for (int i = 0; i < vValues.size(); ++i) {
Vtr::Index vValue = vValues[i];
dst[vValue].Clear();
dst[vValue].AddWithWeight(src[vValue], 1.0f);
}
continue;
}
bool fvarVertMatchesVertex = fvarChannel.valueTopologyMatches(vValues[0]);
if (fvarChannel._isLinear && fvarVertMatchesVertex) {
Vtr::Index srcValueIndex = fvarChannel.getVertexValue(vert);
Vtr::Index dstValueIndex = vValues[0];
if (fvarVertMatchesVertex) {
dst[dstValueIndex].Clear();
dst[dstValueIndex].AddWithWeight(src[srcValueIndex], 1.0f);
} else if (fvarVertMatchesVertex) {
// Assign the mask weights to the common buffer and compute the mask:
//
// Compute the limit mask based on vertex topology:
//
ConstIndexArray vEdges = level.getVertexEdges(vert);
float * vWeights = weightBuffer,
* eWeights = vWeights + 1,
* fWeights = eWeights + vEdges.size();
@ -1569,7 +1575,7 @@ TopologyRefiner::faceVaryingLimit(T const & src, U * dst, int channel) const {
vHood.SetIndex(vert, vert);
scheme.ComputeVertexLimitMask(vHood, vMask);
scheme.ComputeVertexLimitMask(vHood, vMask, level.getVertexRule(vert));
//
// Apply mask to corresponding FVar values for neighboring vertices:

View File

@ -56,10 +56,15 @@ class CLComputeContext::CLStencilTables {
public:
CLStencilTables(Far::StencilTables const & stencilTables, cl_context clContext) {
_sizes = createCLBuffer(stencilTables.GetSizes(), clContext);
_offsets = createCLBuffer(stencilTables.GetOffsets(), clContext);
_indices = createCLBuffer(stencilTables.GetControlIndices(), clContext);
_weights = createCLBuffer(stencilTables.GetWeights(), clContext);
_numStencils = stencilTables.GetNumStencils();
if (_numStencils > 0) {
_sizes = createCLBuffer(stencilTables.GetSizes(), clContext);
_offsets = createCLBuffer(stencilTables.GetOffsets(), clContext);
_indices = createCLBuffer(stencilTables.GetControlIndices(), clContext);
_weights = createCLBuffer(stencilTables.GetWeights(), clContext);
} else {
_sizes = _offsets = _indices = _weights = NULL;
}
}
~CLStencilTables() {
@ -89,12 +94,17 @@ public:
return _weights;
}
int GetNumStencils() const {
return _numStencils;
}
private:
cl_mem _sizes,
_offsets,
_indices,
_weights;
int _numStencils;
};
// -----------------------------------------------------------------------------
@ -104,7 +114,7 @@ CLComputeContext::CLComputeContext(
Far::StencilTables const * varyingStencilTables,
cl_context clContext) :
_vertexStencilTables(0), _varyingStencilTables(0),
_numControlVertices(0) {
_numControlVertices(0) {
if (vertexStencilTables) {
_vertexStencilTables = new CLStencilTables(*vertexStencilTables, clContext);
@ -139,6 +149,15 @@ CLComputeContext::HasVaryingStencilTables() const {
return _varyingStencilTables ? _varyingStencilTables->IsValid() : false;
}
int
CLComputeContext::GetNumStencilsInVertexStencilTables() const {
return _vertexStencilTables ? _vertexStencilTables->GetNumStencils() : 0;
}
int
CLComputeContext::GetNumStencilsInVaryingStencilTables() const {
return _varyingStencilTables ? _varyingStencilTables->GetNumStencils() : 0;
}
// ----------------------------------------------------------------------------
cl_mem

View File

@ -80,6 +80,12 @@ public:
return _numControlVertices;
}
/// Returns the number of stencils in vertex stencil table
int GetNumStencilsInVertexStencilTables() const;
/// Returns the number of stencils in varying stencil table
int GetNumStencilsInVaryingStencilTables() const;
/// Returns the Cuda buffer containing vertex-stencil stencil sizes
cl_mem GetVertexStencilTablesSizes() const;

View File

@ -32,6 +32,7 @@
#include <algorithm>
#include <string.h>
#include <sstream>
#include <cassert>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
@ -138,18 +139,20 @@ private:
// ----------------------------------------------------------------------------
void
CLComputeController::ApplyStencilTableKernel(
Far::KernelBatch const &batch, ComputeContext const *context) {
CLComputeController::ApplyStencilTableKernel(ComputeContext const *context) {
assert(context);
cl_int errNum;
size_t globalWorkSize[1] = { (size_t)(batch.end - batch.start) };
size_t globalWorkSize = 0;
int ncvs = context->GetNumControlVertices();
if (context->HasVertexStencilTables()) {
int start = 0;
int end = context->GetNumStencilsInVertexStencilTables();
globalWorkSize = (size_t)(end - start);
KernelBundle const * bundle = getKernel(_currentBindState.vertexDesc);
@ -167,14 +170,14 @@ CLComputeController::ApplyStencilTableKernel(
clSetKernelArg(kernel, 3, sizeof(cl_mem), &indices);
clSetKernelArg(kernel, 4, sizeof(cl_mem), &weights);
clSetKernelArg(kernel, 5, sizeof(int), &batch.start);
clSetKernelArg(kernel, 6, sizeof(int), &batch.end);
clSetKernelArg(kernel, 5, sizeof(int), &start);
clSetKernelArg(kernel, 6, sizeof(int), &end);
clSetKernelArg(kernel, 7, sizeof(int), &_currentBindState.vertexDesc.offset);
clSetKernelArg(kernel, 8, sizeof(int), &ncvs);
errNum = clEnqueueNDRangeKernel(
_clQueue, kernel, 1, NULL, globalWorkSize, NULL, 0, NULL, NULL);
_clQueue, kernel, 1, NULL, &globalWorkSize, NULL, 0, NULL, NULL);
if (errNum!=CL_SUCCESS) {
Far::Error(Far::FAR_RUNTIME_ERROR,
"ApplyStencilTableKernel (%d) ", errNum);
@ -182,6 +185,9 @@ CLComputeController::ApplyStencilTableKernel(
}
if (context->HasVaryingStencilTables()) {
int start = 0;
int end = context->GetNumStencilsInVaryingStencilTables();
globalWorkSize = (size_t)(end - start);
KernelBundle const * bundle = getKernel(_currentBindState.varyingDesc);
@ -199,14 +205,14 @@ CLComputeController::ApplyStencilTableKernel(
clSetKernelArg(kernel, 3, sizeof(cl_mem), &indices);
clSetKernelArg(kernel, 4, sizeof(cl_mem), &weights);
clSetKernelArg(kernel, 5, sizeof(int), &batch.start);
clSetKernelArg(kernel, 6, sizeof(int), &batch.end);
clSetKernelArg(kernel, 5, sizeof(int), &start);
clSetKernelArg(kernel, 6, sizeof(int), &end);
clSetKernelArg(kernel, 7, sizeof(int), &_currentBindState.varyingDesc.offset);
clSetKernelArg(kernel, 8, sizeof(int), &ncvs);
errNum = clEnqueueNDRangeKernel(
_clQueue, kernel, 1, NULL, globalWorkSize, NULL, 0, NULL, NULL);
_clQueue, kernel, 1, NULL, &globalWorkSize, NULL, 0, NULL, NULL);
if (errNum!=CL_SUCCESS) {
Far::Error(Far::FAR_RUNTIME_ERROR,
"ApplyStencilTableKernel (%d)", errNum);

View File

@ -27,7 +27,6 @@
#include "../version.h"
#include "../far/kernelBatchDispatcher.h"
#include "../osd/clComputeContext.h"
#include "../osd/vertexDescriptor.h"
#include "../osd/opencl.h"
@ -70,9 +69,6 @@ public:
///
/// @param context The CLContext to apply refinement operations to
///
/// @param batches Vector of batches of vertices organized by operative
/// kernel
///
/// @param vertexBuffer Vertex-interpolated data buffer
///
/// @param vertexDesc The descriptor of vertex elements to be refined.
@ -87,17 +83,14 @@ public:
///
template<class VERTEX_BUFFER, class VARYING_BUFFER>
void Compute( CLComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER * vertexBuffer,
VARYING_BUFFER * varyingBuffer,
VertexBufferDescriptor const * vertexDesc=NULL,
VertexBufferDescriptor const * varyingDesc=NULL ){
if (batches.empty()) return;
bind(vertexBuffer, varyingBuffer, vertexDesc, varyingDesc);
Far::KernelBatchDispatcher::Apply(this, context, batches, /*maxlevel*/ -1);
ApplyStencilTableKernel(context);
unbind();
}
@ -113,10 +106,9 @@ public:
///
template<class VERTEX_BUFFER>
void Compute(CLComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER *vertexBuffer) {
Compute<VERTEX_BUFFER>(context, batches, vertexBuffer, (VERTEX_BUFFER*)0);
Compute<VERTEX_BUFFER>(context, vertexBuffer, (VERTEX_BUFFER*)0);
}
/// Waits until all running subdivision kernels finish.
@ -130,10 +122,7 @@ public:
protected:
friend class Far::KernelBatchDispatcher;
void ApplyStencilTableKernel(Far::KernelBatch const &batch,
ComputeContext const *context);
void ApplyStencilTableKernel(ComputeContext const *context);
template<class VERTEX_BUFFER, class VARYING_BUFFER>
void bind( VERTEX_BUFFER * vertexBuffer,

View File

@ -61,7 +61,7 @@ public:
/// interpolation
///
static CpuComputeContext * Create(Far::StencilTables const * vertexStencilTables,
Far::StencilTables const * varyingStencilTables=0);
Far::StencilTables const * varyingStencilTables=0);
/// Destructor
virtual ~CpuComputeContext();

View File

@ -46,7 +46,7 @@ CpuComputeController::Synchronize() {
void
CpuComputeController::ApplyStencilTableKernel(
Far::KernelBatch const &batch, ComputeContext const *context) const {
ComputeContext const *context) const {
assert(context);
@ -61,14 +61,19 @@ CpuComputeController::ApplyStencilTableKernel(
float * destBuffer = _currentBindState.vertexBuffer + desc.offset +
vertexStencils->GetNumControlVertices() * desc.stride;
CpuComputeStencils(_currentBindState.vertexDesc,
srcBuffer, destBuffer,
&vertexStencils->GetSizes().at(0),
&vertexStencils->GetOffsets().at(0),
&vertexStencils->GetControlIndices().at(0),
&vertexStencils->GetWeights().at(0),
batch.start,
batch.end);
int start = 0;
int end = vertexStencils->GetNumStencils();
if (end > start) {
CpuComputeStencils(_currentBindState.vertexDesc,
srcBuffer, destBuffer,
&vertexStencils->GetSizes().at(0),
&vertexStencils->GetOffsets().at(0),
&vertexStencils->GetControlIndices().at(0),
&vertexStencils->GetWeights().at(0),
start,
end);
}
}
Far::StencilTables const * varyingStencils = context->GetVaryingStencilTables();
@ -82,14 +87,19 @@ CpuComputeController::ApplyStencilTableKernel(
float * destBuffer = _currentBindState.varyingBuffer + desc.offset +
varyingStencils->GetNumControlVertices() * desc.stride;
CpuComputeStencils(_currentBindState.varyingDesc,
srcBuffer, destBuffer,
&varyingStencils->GetSizes().at(0),
&varyingStencils->GetOffsets().at(0),
&varyingStencils->GetControlIndices().at(0),
&varyingStencils->GetWeights().at(0),
batch.start,
batch.end);
int start = 0;
int end = varyingStencils->GetNumStencils();
if (end > start) {
CpuComputeStencils(_currentBindState.varyingDesc,
srcBuffer, destBuffer,
&varyingStencils->GetSizes().at(0),
&varyingStencils->GetOffsets().at(0),
&varyingStencils->GetControlIndices().at(0),
&varyingStencils->GetWeights().at(0),
start,
end);
}
}
}

View File

@ -27,7 +27,6 @@
#include "../version.h"
#include "../far/kernelBatchDispatcher.h"
#include "../osd/cpuComputeContext.h"
#include "../osd/vertexDescriptor.h"
@ -64,9 +63,6 @@ public:
///
/// @param context The CpuContext to apply refinement operations to
///
/// @param batches Vector of batches of vertices organized by operative
/// kernel
///
/// @param vertexBuffer Vertex-interpolated data buffer
///
/// @param vertexDesc The descriptor of vertex elements to be refined.
@ -81,17 +77,14 @@ public:
///
template<class VERTEX_BUFFER, class VARYING_BUFFER>
void Compute( CpuComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER * vertexBuffer,
VARYING_BUFFER * varyingBuffer,
VertexBufferDescriptor const * vertexDesc=NULL,
VertexBufferDescriptor const * varyingDesc=NULL ){
if (batches.empty()) return;
bind(vertexBuffer, varyingBuffer, vertexDesc, varyingDesc);
Far::KernelBatchDispatcher::Apply(this, context, batches, /*maxlevel*/ -1);
ApplyStencilTableKernel(context);
unbind();
}
@ -100,17 +93,13 @@ public:
///
/// @param context The CpuContext to apply refinement operations to
///
/// @param batches Vector of batches of vertices organized by operative
/// kernel
///
/// @param vertexBuffer Vertex-interpolated data buffer
///
template<class VERTEX_BUFFER>
void Compute(CpuComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER *vertexBuffer) {
Compute<VERTEX_BUFFER>(context, batches, vertexBuffer, (VERTEX_BUFFER*)0);
Compute<VERTEX_BUFFER>(context, vertexBuffer, (VERTEX_BUFFER*)0);
}
/// Waits until all running subdivision kernels finish.
@ -119,10 +108,7 @@ public:
protected:
friend class Far::KernelBatchDispatcher;
void ApplyStencilTableKernel(Far::KernelBatch const &batch,
ComputeContext const *context) const;
void ApplyStencilTableKernel(ComputeContext const *context) const;
template<class VERTEX_BUFFER, class VARYING_BUFFER>
void bind( VERTEX_BUFFER * vertexBuffer,

View File

@ -234,7 +234,6 @@ CpuEvalLimitController::_EvalLimitSample( LimitLocation const & coords,
int const * permute = 0;
switch (desc.GetType()) {
case Desc::REGULAR : permute = zeroRings[0]; break;
case Desc::SINGLE_CREASE :
case Desc::BOUNDARY : permute = zeroRings[1]; break;
case Desc::CORNER : permute = zeroRings[2]; break;
case Desc::GREGORY :

View File

@ -454,17 +454,19 @@ evalGregoryBasis(Far::PatchParam::BitField bits, float u, float v,
}
// XXXX manuelk re-order stencils in factory and get rid of permutation ?
static int const permute[16] =
{ 0, 1, 7, 5, 2, 3, 8, 6, 16, 18, 13, 12, 15, 17, 11, 10 };
// negative values mean that a blended cp needed.
static int const permute[16] = { 0, 1, 7, 5,
2, -1, -2, 6,
16, -3, -4, 12,
15, 17, 11, 10 };
for (int i=0; i<16; ++i) {
int index = permute[i];
float const * in = inOffset + vertexIndices[index]*inDesc.stride;
if (index < 0) {
in = &CP[-index-1];
}
float const * in = (index >= 0)
? inOffset + vertexIndices[index]*inDesc.stride
: &CP[(-index-1)*inDesc.length];
for (int k=0; k<inDesc.length; ++k) {
outQ[k] += BU[i] * in[k];

View File

@ -63,10 +63,15 @@ class CudaComputeContext::CudaStencilTables {
public:
CudaStencilTables(Far::StencilTables const & stencilTables) {
_sizes = createCudaBuffer(stencilTables.GetSizes());
_offsets = createCudaBuffer(stencilTables.GetOffsets());
_indices = createCudaBuffer(stencilTables.GetControlIndices());
_weights = createCudaBuffer(stencilTables.GetWeights());
_numStencils = stencilTables.GetNumStencils();
if (_numStencils > 0) {
_sizes = createCudaBuffer(stencilTables.GetSizes());
_offsets = createCudaBuffer(stencilTables.GetOffsets());
_indices = createCudaBuffer(stencilTables.GetControlIndices());
_weights = createCudaBuffer(stencilTables.GetWeights());
} else {
_sizes = _offsets = _indices = _weights = NULL;
}
}
~CudaStencilTables() {
@ -96,11 +101,16 @@ public:
return _weights;
}
int GetNumStencils() const {
return _numStencils;
}
private:
void * _sizes,
* _offsets,
* _indices,
* _weights;
int _numStencils;
};
// ----------------------------------------------------------------------------
@ -144,6 +154,16 @@ CudaComputeContext::HasVaryingStencilTables() const {
return _varyingStencilTables ? _varyingStencilTables->IsValid() : false;
}
int
CudaComputeContext::GetNumStencilsInVertexStencilTables() const {
return _vertexStencilTables ? _vertexStencilTables->GetNumStencils() : 0;
}
int
CudaComputeContext::GetNumStencilsInVaryingStencilTables() const {
return _varyingStencilTables ? _varyingStencilTables->GetNumStencils() : 0;
}
// ----------------------------------------------------------------------------
void *

View File

@ -77,6 +77,12 @@ public:
return _numControlVertices;
}
/// Returns the number of stencils in vertex stencil tables
int GetNumStencilsInVertexStencilTables() const;
/// Returns the number of stencils in varying stencil tables
int GetNumStencilsInVaryingStencilTables() const;
/// Returns the Cuda buffer containing vertex-stencil stencil sizes
void * GetVertexStencilTablesSizes() const;

View File

@ -26,6 +26,7 @@
#include <cuda_runtime.h>
#include <string.h>
#include <cassert>
extern "C" {
@ -46,7 +47,7 @@ namespace Osd {
void
CudaComputeController::ApplyStencilTableKernel(
Far::KernelBatch const &batch, ComputeContext const *context) const {
ComputeContext const *context) const {
assert(context);
@ -55,18 +56,23 @@ CudaComputeController::ApplyStencilTableKernel(
int length = _currentBindState.vertexDesc.length,
stride = _currentBindState.vertexDesc.stride;
int start = 0;
int end = context->GetNumStencilsInVertexStencilTables();
float const * src = _currentBindState.GetVertexBufferAtOffset();
float * dst = const_cast<float *>(src) +
context->GetNumControlVertices() * stride;
CudaComputeStencils(src, dst, length, stride,
(unsigned char const *)context->GetVertexStencilTablesSizes(),
(int const *)context->GetVertexStencilTablesOffsets(),
(int const *)context->GetVertexStencilTablesIndices(),
(float const *)context->GetVertexStencilTablesWeights(),
batch.start,
batch.end);
if (end > start) {
CudaComputeStencils(src, dst, length, stride,
(unsigned char const *)context->GetVertexStencilTablesSizes(),
(int const *)context->GetVertexStencilTablesOffsets(),
(int const *)context->GetVertexStencilTablesIndices(),
(float const *)context->GetVertexStencilTablesWeights(),
start,
end);
}
}
if (context->HasVaryingStencilTables()) {
@ -74,18 +80,23 @@ CudaComputeController::ApplyStencilTableKernel(
int length = _currentBindState.varyingDesc.length,
stride = _currentBindState.varyingDesc.stride;
int start = 0;
int end = context->GetNumStencilsInVaryingStencilTables();
float const * src = _currentBindState.GetVaryingBufferAtOffset();
float * dst = const_cast<float *>(src) +
context->GetNumControlVertices() * stride;
CudaComputeStencils(src, dst, length, stride,
(unsigned char const *)context->GetVaryingStencilTablesSizes(),
(int const *)context->GetVaryingStencilTablesOffsets(),
(int const *)context->GetVaryingStencilTablesIndices(),
(float const *)context->GetVaryingStencilTablesWeights(),
batch.start,
batch.end);
if (end > start) {
CudaComputeStencils(src, dst, length, stride,
(unsigned char const *)context->GetVaryingStencilTablesSizes(),
(int const *)context->GetVaryingStencilTablesOffsets(),
(int const *)context->GetVaryingStencilTablesIndices(),
(float const *)context->GetVaryingStencilTablesWeights(),
start,
end);
}
}
}

View File

@ -27,7 +27,6 @@
#include "../version.h"
#include "../far/kernelBatchDispatcher.h"
#include "../osd/cudaComputeContext.h"
#include "../osd/vertexDescriptor.h"
@ -77,17 +76,14 @@ public:
///
template<class VERTEX_BUFFER, class VARYING_BUFFER>
void Compute( CudaComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER * vertexBuffer,
VARYING_BUFFER * varyingBuffer,
VertexBufferDescriptor const * vertexDesc=NULL,
VertexBufferDescriptor const * varyingDesc=NULL ){
if (batches.empty()) return;
bind(vertexBuffer, varyingBuffer, vertexDesc, varyingDesc);
Far::KernelBatchDispatcher::Apply(this, context, batches, /*maxlevel*/ -1);
ApplyStencilTableKernel(context);
unbind();
}
@ -103,10 +99,9 @@ public:
///
template<class VERTEX_BUFFER>
void Compute(CudaComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER *vertexBuffer) {
Compute<VERTEX_BUFFER>(context, batches, vertexBuffer, (VERTEX_BUFFER*)0);
Compute<VERTEX_BUFFER>(context, vertexBuffer, (VERTEX_BUFFER*)0);
}
/// Waits until all running subdivision kernels finish.
@ -114,10 +109,7 @@ public:
protected:
friend class Far::KernelBatchDispatcher;
void ApplyStencilTableKernel(Far::KernelBatch const &batch,
ComputeContext const *context) const;
void ApplyStencilTableKernel(ComputeContext const *context) const;
template<class VERTEX_BUFFER, class VARYING_BUFFER>
void bind( VERTEX_BUFFER * vertexBuffer,

View File

@ -114,17 +114,26 @@ public:
D3D11StencilTables(Far::StencilTables const & stencilTables,
ID3D11DeviceContext *deviceContext) {
// convert unsigned char sizes buffer to ints (HLSL does not have uint8 type)
std::vector<int> const sizes(stencilTables.GetSizes().begin(),
stencilTables.GetSizes().end());
_numStencils = stencilTables.GetNumStencils();
if (_numStencils > 0) {
// convert unsigned char sizes buffer to ints
// (HLSL does not have uint8 type)
std::vector<int> const sizes(stencilTables.GetSizes().begin(),
stencilTables.GetSizes().end());
_sizes.initialize(sizes, DXGI_FORMAT_R32_SINT, deviceContext);
_offsets.initialize(stencilTables.GetOffsets(), DXGI_FORMAT_R32_SINT, deviceContext);
_indices.initialize(stencilTables.GetControlIndices(), DXGI_FORMAT_R32_SINT, deviceContext);
_weights.initialize(stencilTables.GetWeights(), DXGI_FORMAT_R32_FLOAT, deviceContext);
_sizes.initialize(sizes,
DXGI_FORMAT_R32_SINT,
deviceContext);
_offsets.initialize(stencilTables.GetOffsets(),
DXGI_FORMAT_R32_SINT,
deviceContext);
_indices.initialize(stencilTables.GetControlIndices(),
DXGI_FORMAT_R32_SINT,
deviceContext);
_weights.initialize(stencilTables.GetWeights(),
DXGI_FORMAT_R32_FLOAT,
deviceContext);
}
}
bool IsValid() const {
@ -148,6 +157,10 @@ public:
return _weights;
}
int GetNumStencils() const {
return _numStencils;
}
void Bind(ID3D11DeviceContext * deviceContext) const {
ID3D11ShaderResourceView *SRViews[] = {
_sizes.srv,
@ -170,6 +183,8 @@ private:
_offsets,
_indices,
_weights;
int _numStencils;
};
// ----------------------------------------------------------------------------
@ -217,6 +232,16 @@ D3D11ComputeContext::HasVaryingStencilTables() const {
return _varyingStencilTables ? _varyingStencilTables->IsValid() : false;
}
int
D3D11ComputeContext::GetNumStencilsInVertexStencilTables() const {
return _vertexStencilTables ? _vertexStencilTables->GetNumStencils() : 0;
}
int
D3D11ComputeContext::GetNumStencilsInVaryingStencilTables() const {
return _varyingStencilTables ? _varyingStencilTables->GetNumStencils() : 0;
}
// ----------------------------------------------------------------------------
void

View File

@ -78,6 +78,12 @@ public:
return _numControlVertices;
}
/// Returns the number of stencils in vertex stencil table
int GetNumStencilsInVertexStencilTables() const;
/// Returns the number of stencils in varying stencil table
int GetNumStencilsInVaryingStencilTables() const;
/// Binds D3D11 buffers containing stencils for 'vertex' interpolation
///
/// @param deviceContext The D3D device

View File

@ -155,11 +155,11 @@ public:
}
void ApplyStencilTableKernel(ID3D11DeviceContext *deviceContext,
Far::KernelBatch const &batch, int offset, int numCVs) {
int offset, int numCVs, int start, int end) {
KernelUniformArgs args;
args.uniformStart = batch.start;
args.uniformEnd = batch.end;
args.uniformStart = start;
args.uniformEnd = end;
args.uniformOffset = offset;
args.uniformNumCVs = numCVs;
@ -299,7 +299,7 @@ D3D11ComputeController::unbindBuffer() {
void
D3D11ComputeController::ApplyStencilTableKernel(
Far::KernelBatch const &batch, D3D11ComputeContext const *context) const {
D3D11ComputeContext const *context, int numStencils) const {
assert(context);
@ -307,8 +307,12 @@ D3D11ComputeController::ApplyStencilTableKernel(
D3D11ComputeController::KernelBundle * bundle =
const_cast<D3D11ComputeController::KernelBundle *>(_currentBindState.kernelBundle);
bundle->ApplyStencilTableKernel(_deviceContext,
batch, _currentBindState.desc.offset, context->GetNumControlVertices());
bundle->ApplyStencilTableKernel(
_deviceContext,
_currentBindState.desc.offset,
context->GetNumControlVertices(),
0,
numStencils);
}

View File

@ -27,7 +27,6 @@
#include "../version.h"
#include "../far/kernelBatchDispatcher.h"
#include "../osd/d3d11ComputeContext.h"
#include "../osd/vertexDescriptor.h"
@ -69,9 +68,6 @@ public:
///
/// @param context The D3D11Context to apply refinement operations to
///
/// @param batches Vector of batches of vertices organized by operative
/// kernel
///
/// @param vertexBuffer Vertex-interpolated data buffer
///
/// @param vertexDesc The descriptor of vertex elements to be refined.
@ -86,20 +82,18 @@ public:
///
template<class VERTEX_BUFFER, class VARYING_BUFFER>
void Compute( D3D11ComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER * vertexBuffer,
VARYING_BUFFER * varyingBuffer,
VertexBufferDescriptor const * vertexDesc=NULL,
VertexBufferDescriptor const * varyingDesc=NULL ){
if (batches.empty()) return;
if (vertexBuffer) {
bind(vertexBuffer, vertexDesc);
context->BindVertexStencilTables(_deviceContext);
Far::KernelBatchDispatcher::Apply(this, context, batches, /*maxlevel*/ -1);
ApplyStencilTableKernel(
context, context->GetNumStencilsInVertexStencilTables());
}
if (varyingBuffer) {
@ -107,7 +101,8 @@ public:
context->BindVaryingStencilTables(_deviceContext);
Far::KernelBatchDispatcher::Apply(this, context, batches, /*maxlevel*/ -1);
ApplyStencilTableKernel(
context, context->GetNumStencilsInVaryingStencilTables());
}
context->UnbindStencilTables(_deviceContext);
@ -119,17 +114,13 @@ public:
///
/// @param context The D3D11Context to apply refinement operations to
///
/// @param batches Vector of batches of vertices organized by operative
/// kernel
///
/// @param vertexBuffer Vertex-interpolated data buffer
///
template<class VERTEX_BUFFER>
void Compute(D3D11ComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER *vertexBuffer) {
Compute<VERTEX_BUFFER>(context, batches, vertexBuffer, (VERTEX_BUFFER*)0);
Compute<VERTEX_BUFFER>(context, vertexBuffer, (VERTEX_BUFFER*)0);
}
/// Waits until all running subdivision kernels finish.
@ -137,10 +128,8 @@ public:
protected:
friend class Far::KernelBatchDispatcher;
void ApplyStencilTableKernel(Far::KernelBatch const &batch,
ComputeContext const *context) const;
void ApplyStencilTableKernel(ComputeContext const *context,
int numStencils) const;
template<class BUFFER>
void bind( BUFFER * buffer,

View File

@ -74,7 +74,6 @@ D3D11DrawRegistryBase::_CreateDrawSourceConfig(
sconfig->commonShader.source += ptexShaderSource;
}
{
std::ostringstream ss;
ss << (int)desc.GetMaxValence();
@ -84,122 +83,58 @@ D3D11DrawRegistryBase::_CreateDrawSourceConfig(
sconfig->commonShader.AddDefine("OSD_NUM_ELEMENTS", ss.str());
}
if (desc.GetPattern() == Far::PatchDescriptor::NON_TRANSITION) {
switch (desc.GetType()) {
case Far::PatchDescriptor::REGULAR:
sconfig->vertexShader.source = bsplineShaderSource;
sconfig->vertexShader.target = "vs_5_0";
sconfig->vertexShader.entry = "vs_main_patches";
sconfig->hullShader.source = bsplineShaderSource;
sconfig->hullShader.target = "hs_5_0";
sconfig->hullShader.entry = "hs_main_patches";
sconfig->domainShader.source = bsplineShaderSource;
sconfig->domainShader.target = "ds_5_0";
sconfig->domainShader.entry = "ds_main_patches";
break;
case Far::PatchDescriptor::SINGLE_CREASE:
sconfig->vertexShader.source = bsplineShaderSource;
sconfig->vertexShader.target = "vs_5_0";
sconfig->vertexShader.entry = "vs_main_patches";
sconfig->hullShader.source = bsplineShaderSource;
sconfig->hullShader.target = "hs_5_0";
sconfig->hullShader.entry = "hs_main_patches";
sconfig->hullShader.AddDefine("OSD_PATCH_SINGLE_CREASE");
sconfig->domainShader.source = bsplineShaderSource;
sconfig->domainShader.target = "ds_5_0";
sconfig->domainShader.entry = "ds_main_patches";
sconfig->domainShader.AddDefine("OSD_PATCH_SINGLE_CREASE");
break;
case Far::PatchDescriptor::BOUNDARY:
sconfig->vertexShader.source = bsplineShaderSource;
sconfig->vertexShader.target = "vs_5_0";
sconfig->vertexShader.entry = "vs_main_patches";
sconfig->hullShader.source = bsplineShaderSource;
sconfig->hullShader.target = "hs_5_0";
sconfig->hullShader.entry = "hs_main_patches";
sconfig->hullShader.AddDefine("OSD_PATCH_BOUNDARY");
sconfig->domainShader.source = bsplineShaderSource;
sconfig->domainShader.target = "ds_5_0";
sconfig->domainShader.entry = "ds_main_patches";
break;
case Far::PatchDescriptor::CORNER:
sconfig->vertexShader.source = bsplineShaderSource;
sconfig->vertexShader.target = "vs_5_0";
sconfig->vertexShader.entry = "vs_main_patches";
sconfig->hullShader.source = bsplineShaderSource;
sconfig->hullShader.target = "hs_5_0";
sconfig->hullShader.entry = "hs_main_patches";
sconfig->hullShader.AddDefine("OSD_PATCH_CORNER");
sconfig->domainShader.source = bsplineShaderSource;
sconfig->domainShader.target = "ds_5_0";
sconfig->domainShader.entry = "ds_main_patches";
break;
case Far::PatchDescriptor::GREGORY:
sconfig->vertexShader.source = gregoryShaderSource;
sconfig->vertexShader.target = "vs_5_0";
sconfig->vertexShader.entry = "vs_main_patches";
sconfig->hullShader.source = gregoryShaderSource;
sconfig->hullShader.target = "hs_5_0";
sconfig->hullShader.entry = "hs_main_patches";
sconfig->domainShader.source = gregoryShaderSource;
sconfig->domainShader.target = "ds_5_0";
sconfig->domainShader.entry = "ds_main_patches";
break;
case Far::PatchDescriptor::GREGORY_BOUNDARY:
sconfig->vertexShader.source = gregoryShaderSource;
sconfig->vertexShader.target = "vs_5_0";
sconfig->vertexShader.entry = "vs_main_patches";
sconfig->vertexShader.AddDefine("OSD_PATCH_GREGORY_BOUNDARY");
sconfig->hullShader.source = gregoryShaderSource;
sconfig->hullShader.target = "hs_5_0";
sconfig->hullShader.entry = "hs_main_patches";
sconfig->hullShader.AddDefine("OSD_PATCH_GREGORY_BOUNDARY");
sconfig->domainShader.source = gregoryShaderSource;
sconfig->domainShader.target = "ds_5_0";
sconfig->domainShader.entry = "ds_main_patches";
sconfig->domainShader.AddDefine("OSD_PATCH_GREGORY_BOUNDARY");
break;
default: // POINTS, LINES, QUADS, TRIANGLES
// do nothing
break;
}
} else { // pattern != NON_TRANSITION
sconfig->vertexShader.source = bsplineShaderSource;
switch (desc.GetType()) {
case Far::PatchDescriptor::REGULAR:
case Far::PatchDescriptor::BOUNDARY:
case Far::PatchDescriptor::CORNER:
sconfig->commonShader.AddDefine("OSD_PATCH_BSPLINE");
sconfig->commonShader.AddDefine("OSD_PATCH_ENABLE_SINGLE_CREASE");
sconfig->vertexShader.source =
std::string(transitionShaderSource) + bsplineShaderSource;
sconfig->vertexShader.target = "vs_5_0";
sconfig->vertexShader.entry = "vs_main_patches";
sconfig->hullShader.source =
std::string(transitionShaderSource) + bsplineShaderSource;
sconfig->hullShader.target = "hs_5_0";
sconfig->hullShader.entry = "hs_main_patches";
sconfig->hullShader.AddDefine("OSD_PATCH_TRANSITION");
sconfig->domainShader.source =
std::string(transitionShaderSource) + bsplineShaderSource;
sconfig->domainShader.target = "ds_5_0";
sconfig->domainShader.entry = "ds_main_patches";
sconfig->domainShader.AddDefine("OSD_PATCH_TRANSITION");
int pattern = desc.GetPattern() - 1;
int rotation = desc.GetRotation();
int subpatch = desc.GetSubPatch();
std::ostringstream ss;
ss << "OSD_TRANSITION_PATTERN" << pattern << subpatch;
sconfig->hullShader.AddDefine(ss.str());
sconfig->domainShader.AddDefine(ss.str());
ss.str("");
ss << rotation;
sconfig->hullShader.AddDefine("OSD_TRANSITION_ROTATE", ss.str());
sconfig->domainShader.AddDefine("OSD_TRANSITION_ROTATE", ss.str());
if (desc.GetType() == Far::PatchDescriptor::SINGLE_CREASE) {
sconfig->hullShader.AddDefine("OSD_PATCH_SINGLE_CREASE");
sconfig->domainShader.AddDefine("OSD_PATCH_SINGLE_CREASE");
} else if (desc.GetType() == Far::PatchDescriptor::BOUNDARY) {
sconfig->hullShader.AddDefine("OSD_PATCH_BOUNDARY");
} else if (desc.GetType() == Far::PatchDescriptor::CORNER) {
sconfig->hullShader.AddDefine("OSD_PATCH_CORNER");
}
break;
case Far::PatchDescriptor::GREGORY:
sconfig->commonShader.AddDefine("OSD_PATCH_GREGORY");
sconfig->vertexShader.source = gregoryShaderSource;
sconfig->vertexShader.target = "vs_5_0";
sconfig->vertexShader.entry = "vs_main_patches";
sconfig->hullShader.source = gregoryShaderSource;
sconfig->hullShader.target = "hs_5_0";
sconfig->hullShader.entry = "hs_main_patches";
sconfig->domainShader.source = gregoryShaderSource;
sconfig->domainShader.target = "ds_5_0";
sconfig->domainShader.entry = "ds_main_patches";
break;
case Far::PatchDescriptor::GREGORY_BOUNDARY:
sconfig->commonShader.AddDefine("OSD_PATCH_GREGORY_BOUNDARY");
sconfig->vertexShader.source = gregoryShaderSource;
sconfig->vertexShader.target = "vs_5_0";
sconfig->vertexShader.entry = "vs_main_patches";
sconfig->vertexShader.AddDefine("OSD_PATCH_GREGORY_BOUNDARY");
sconfig->hullShader.source = gregoryShaderSource;
sconfig->hullShader.target = "hs_5_0";
sconfig->hullShader.entry = "hs_main_patches";
sconfig->hullShader.AddDefine("OSD_PATCH_GREGORY_BOUNDARY");
sconfig->domainShader.source = gregoryShaderSource;
sconfig->domainShader.target = "ds_5_0";
sconfig->domainShader.entry = "ds_main_patches";
sconfig->domainShader.AddDefine("OSD_PATCH_GREGORY_BOUNDARY");
break;
case Far::PatchDescriptor::GREGORY_BASIS:
// XXXdyu-patch-drawing gregory basis for d3d11
break;
default: // POINTS, LINES, QUADS, TRIANGLES
// do nothing
break;
}
return sconfig;

180
opensubdiv/osd/d3d11Mesh.h Normal file → Executable file
View File

@ -31,6 +31,7 @@
#include "../osd/d3d11ComputeController.h"
#include "../osd/d3d11DrawContext.h"
#include "../osd/d3d11VertexBuffer.h"
#include "../far/endCapLegacyGregoryPatchFactory.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
@ -63,22 +64,27 @@ public:
_computeContext(0),
_computeController(computeController),
_drawContext(0),
_numVertices(0),
_d3d11DeviceContext(d3d11DeviceContext)
{
D3D11MeshInterface::refineMesh(*_refiner, level, bits.test(MeshAdaptive), bits.test(MeshUseSingleCreasePatch));
int numElements =
initializeVertexBuffers(numVertexElements, numVaryingElements, bits);
initializeContext(numVertexElements,
numVaryingElements,
numVertexElements, /* interleaved stride */
level, bits);
initializeComputeContext(numVertexElements, numVaryingElements);
initializeVertexBuffers(_numVertices,
numVertexElements,
numVaryingElements);
initializeDrawContext(numElements, level, bits);
// for classic gregory patch -- will retire
_drawContext->UpdateVertexTexture(_vertexBuffer, _d3d11DeviceContext);
}
Mesh(ComputeController * computeController,
Far::TopologyRefiner * refiner,
Far::PatchTables * patchTables,
Far::KernelBatchVector const & kernelBatches,
VertexBuffer * vertexBuffer,
VertexBuffer * varyingBuffer,
ComputeContext * computeContext,
@ -87,12 +93,12 @@ public:
_refiner(refiner),
_patchTables(patchTables),
_kernelBatches(kernelBatches),
_vertexBuffer(vertexBuffer),
_varyingBuffer(varyingBuffer),
_computeContext(computeContext),
_computeController(computeController),
_drawContext(drawContext),
_numVertices(0),
_d3d11DeviceContext(d3d11DeviceContext)
{
_drawContext->UpdateVertexTexture(_vertexBuffer, _d3d11DeviceContext);
@ -107,10 +113,7 @@ public:
delete _drawContext;
}
virtual int GetNumVertices() const {
assert(_refiner);
return D3D11MeshInterface::getNumVertices(*_refiner);
}
virtual int GetNumVertices() const { return _numVertices; }
virtual void UpdateVertexBuffer(float const *vertexData, int startVertex, int numVerts) {
_vertexBuffer->UpdateData(vertexData, startVertex, numVerts, _d3d11DeviceContext);
@ -119,13 +122,14 @@ public:
_varyingBuffer->UpdateData(varyingData, startVertex, numVerts, _d3d11DeviceContext);
}
virtual void Refine() {
_computeController->Compute(_computeContext, _kernelBatches, _vertexBuffer, _varyingBuffer);
_computeController->Compute(_computeContext, _vertexBuffer, _varyingBuffer);
}
virtual void Refine(VertexBufferDescriptor const *vertexDesc,
VertexBufferDescriptor const *varyingDesc,
bool interleaved) {
_computeController->Compute(_computeContext, _kernelBatches,
_vertexBuffer, (interleaved ? _vertexBuffer : _varyingBuffer),
_computeController->Compute(_computeContext,
_vertexBuffer,
(interleaved ? _vertexBuffer : _varyingBuffer),
vertexDesc, varyingDesc);
}
virtual void Synchronize() {
@ -162,8 +166,9 @@ public:
private:
void initializeComputeContext(int numVertexElements,
int numVaryingElements ) {
void initializeContext(int numVertexElements,
int numVaryingElements,
int numElements, int level, MeshBitset bits) {
assert(_refiner);
@ -176,8 +181,6 @@ private:
if (numVertexElements>0) {
vertexStencils = Far::StencilTablesFactory::Create(*_refiner, options);
_kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils));
}
if (numVaryingElements>0) {
@ -187,55 +190,51 @@ private:
varyingStencils = Far::StencilTablesFactory::Create(*_refiner, options);
}
_computeContext = ComputeContext::Create(vertexStencils, varyingStencils);
Far::PatchTablesFactory::Options poptions(level);
poptions.generateFVarTables = bits.test(MeshFVarData);
poptions.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch);
// TODO: add gregory basis shader for DX11
Far::EndCapLegacyGregoryPatchFactory *gregoryPatchFactory = new Far::EndCapLegacyGregoryPatchFactory(*_refiner);
_patchTables = Far::PatchTablesFactoryT<Far::EndCapLegacyGregoryPatchFactory>::Create(*_refiner, poptions, gregoryPatchFactory);
gregoryPatchFactory->AddGregoryPatchTables(_patchTables);
_drawContext = DrawContext::Create(_patchTables,
_d3d11DeviceContext,
numElements);
_computeContext = ComputeContext::Create(vertexStencils,
varyingStencils);
// numvertices = coarse verts + refined verts + gregory basis verts
_numVertices = vertexStencils->GetNumControlVertices()
+ vertexStencils->GetNumStencils();
delete gregoryPatchFactory;
delete vertexStencils;
delete varyingStencils;
}
void initializeDrawContext(int numElements, int level, MeshBitset bits) {
assert(_refiner and _vertexBuffer);
Far::PatchTablesFactory::Options options(level);
options.generateFVarTables = bits.test(MeshFVarData);
options.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch);
_patchTables = Far::PatchTablesFactory::Create(*_refiner, options);
_drawContext = DrawContext::Create(
_patchTables, _d3d11DeviceContext, numElements);
_drawContext->UpdateVertexTexture(_vertexBuffer, _d3d11DeviceContext);
}
int initializeVertexBuffers(int numVertexElements,
int numVaryingElements, MeshBitset bits) {
void initializeVertexBuffers(int numVertices,
int numVertexElements,
int numVaryingElements) {
ID3D11Device * pd3d11Device;
_d3d11DeviceContext->GetDevice(&pd3d11Device);
int numVertices = D3D11MeshInterface::getNumVertices(*_refiner);
int numElements = numVertexElements +
(bits.test(MeshInterleaveVarying) ? numVaryingElements : 0);
if (numVertexElements) {
_vertexBuffer =
VertexBuffer::Create(numElements, numVertices, pd3d11Device);
VertexBuffer::Create(numVertexElements, numVertices, pd3d11Device);
}
if (numVaryingElements>0 and (not bits.test(MeshInterleaveVarying))) {
if (numVaryingElements) {
_varyingBuffer =
VertexBuffer::Create(numVaryingElements, numVertices, pd3d11Device);
}
return numElements;
}
Far::TopologyRefiner * _refiner;
Far::PatchTables * _patchTables;
Far::KernelBatchVector _kernelBatches;
VertexBuffer *_vertexBuffer;
VertexBuffer *_varyingBuffer;
@ -243,6 +242,7 @@ private:
ComputeContext *_computeContext;
ComputeController *_computeController;
DrawContext *_drawContext;
int _numVertices;
ID3D11DeviceContext *_d3d11DeviceContext;
};
@ -271,22 +271,29 @@ public:
_computeContext(0),
_computeController(computeController),
_drawContext(0),
_numVertices(0),
_d3d11DeviceContext(d3d11DeviceContext)
{
D3D11MeshInterface::refineMesh(*_refiner, level, bits.test(MeshAdaptive), bits.test(MeshUseSingleCreasePatch));
D3D11MeshInterface::refineMesh(*_refiner, level,
bits.test(MeshAdaptive),
bits.test(MeshUseSingleCreasePatch));
int numElements =
initializeVertexBuffers(numVertexElements, numVaryingElements, bits);
initializeContext(numVertexElements,
numVaryingElements,
numVertexElements, /* interleaved stride */
level, bits);
initializeComputeContext(numVertexElements, numVaryingElements);
initializeVertexBuffers(_numVertices,
numVertexElements,
numVaryingElements);
initializeDrawContext(numElements, level, bits);
// for classic gregory patch -- will retire
_drawContext->UpdateVertexTexture(_vertexBuffer, _d3d11DeviceContext);
}
Mesh(ComputeController * computeController,
Far::TopologyRefiner * refiner,
Far::PatchTables * patchTables,
Far::KernelBatchVector const & kernelBatches,
VertexBuffer * vertexBuffer,
VertexBuffer * varyingBuffer,
ComputeContext * computeContext,
@ -295,12 +302,12 @@ public:
_refiner(refiner),
_patchTables(patchTables),
_kernelBatches(kernelBatches),
_vertexBuffer(vertexBuffer),
_varyingBuffer(varyingBuffer),
_computeContext(computeContext),
_computeController(computeController),
_drawContext(drawContext),
_numVertices(0),
_d3d11DeviceContext(d3d11DeviceContext)
{
_drawContext->UpdateVertexTexture(_vertexBuffer, _d3d11DeviceContext);
@ -315,7 +322,7 @@ public:
delete _drawContext;
}
virtual int GetNumVertices() const { return _refiner->GetNumVerticesTotal(); }
virtual int GetNumVertices() const { return _numVertices; }
virtual void UpdateVertexBuffer(float const *vertexData, int startVertex, int numVerts) {
_vertexBuffer->UpdateData(vertexData, startVertex, numVerts, _d3d11DeviceContext);
@ -324,12 +331,12 @@ public:
_varyingBuffer->UpdateData(varyingData, startVertex, numVerts, _d3d11DeviceContext);
}
virtual void Refine() {
_computeController->Compute(_computeContext, _kernelBatches, _vertexBuffer, _varyingBuffer);
_computeController->Compute(_computeContext, _vertexBuffer, _varyingBuffer);
}
virtual void Refine(VertexBufferDescriptor const *vertexDesc,
VertexBufferDescriptor const *varyingDesc,
bool interleaved) {
_computeController->Compute(_computeContext, _kernelBatches,
_computeController->Compute(_computeContext,
_vertexBuffer, (interleaved ? _vertexBuffer : _varyingBuffer),
vertexDesc, varyingDesc);
}
@ -368,8 +375,9 @@ public:
private:
void initializeComputeContext(int numVertexElements,
int numVaryingElements ) {
void initializeContext(int numVertexElements,
int numVaryingElements,
int numElements, int level, MeshBitset bits) {
assert(_refiner);
@ -382,8 +390,6 @@ private:
if (numVertexElements>0) {
vertexStencils = Far::StencilTablesFactory::Create(*_refiner, options);
_kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils));
}
if (numVaryingElements>0) {
@ -393,55 +399,54 @@ private:
varyingStencils = Far::StencilTablesFactory::Create(*_refiner, options);
}
Far::PatchTablesFactory::Options poptions(level);
poptions.generateFVarTables = bits.test(MeshFVarData);
poptions.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch);
Far::EndCapLegacyGregoryPatchFactory *gregoryPatchFactory = new Far::EndCapLegacyGregoryPatchFactory(*_refiner);
_patchTables = Far::PatchTablesFactoryT<Far::EndCapLegacyGregoryPatchFactory>::Create(*_refiner, poptions, gregoryPatchFactory);
gregoryPatchFactory->AddGregoryPatchTables(_patchTables);
_drawContext = DrawContext::Create(_patchTables,
_d3d11DeviceContext,
numElements);
_computeContext =
ComputeContext::Create(_d3d11DeviceContext, vertexStencils, varyingStencils);
// numvertices = coarse verts + refined verts + gregory basis verts
if (vertexStencils) {
_numVertices = vertexStencils->GetNumControlVertices()
+ vertexStencils->GetNumStencils();
} else {
// if no stencils (torus), ask refiner.
_numVertices = _refiner->GetNumVertices(0);
}
delete vertexStencils;
delete varyingStencils;
}
void initializeDrawContext(int numElements, int level, MeshBitset bits) {
assert(_refiner and _vertexBuffer);
Far::PatchTablesFactory::Options options(level);
options.generateFVarTables = bits.test(MeshFVarData);
options.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch);
_patchTables = Far::PatchTablesFactory::Create(*_refiner, options);
_drawContext = DrawContext::Create(
_patchTables, _d3d11DeviceContext, numElements);
_drawContext->UpdateVertexTexture(_vertexBuffer, _d3d11DeviceContext);
}
int initializeVertexBuffers(int numVertexElements,
int numVaryingElements, MeshBitset bits) {
void initializeVertexBuffers(int numVertices,
int numVertexElements,
int numVaryingElements) {
ID3D11Device * pd3d11Device;
_d3d11DeviceContext->GetDevice(&pd3d11Device);
int numVertices = D3D11MeshInterface::getNumVertices(*_refiner);
int numElements = numVertexElements +
(bits.test(MeshInterleaveVarying) ? numVaryingElements : 0);
if (numVertexElements) {
_vertexBuffer =
VertexBuffer::Create(numElements, numVertices, pd3d11Device);
VertexBuffer::Create(numVertexElements, numVertices, pd3d11Device);
}
if (numVaryingElements>0 and (not bits.test(MeshInterleaveVarying))) {
if (numVaryingElements) {
_varyingBuffer =
VertexBuffer::Create(numVaryingElements, numVertices, pd3d11Device);
}
return numElements;
}
Far::TopologyRefiner * _refiner;
Far::PatchTables * _patchTables;
Far::KernelBatchVector _kernelBatches;
VertexBuffer *_vertexBuffer;
VertexBuffer *_varyingBuffer;
@ -449,6 +454,7 @@ private:
ComputeContext *_computeContext;
ComputeController *_computeController;
DrawContext *_drawContext;
int _numVertices;
ID3D11DeviceContext *_d3d11DeviceContext;
};

View File

@ -39,37 +39,21 @@ void
DrawContext::ConvertPatchArrays(Far::PatchTables const &patchTables,
PatchArrayVector &osdPatchArrays, int maxValence, int numElements) {
// create patch arrays for drawing (while duplicating subpatches for transition patch arrays)
static int subPatchCounts[] = { 1, 3, 4, 4, 4, 2 }; // number of subpatches for patterns
int numTotalPatchArrays = 0;
for (int array=0; array < patchTables.GetNumPatchArrays(); ++array) {
Far::PatchDescriptor::TransitionPattern pattern =
patchTables.GetPatchArrayDescriptor(array).GetPattern();
numTotalPatchArrays += subPatchCounts[(int)pattern];
}
int narrays = patchTables.GetNumPatchArrays();
// allocate drawing patch arrays
osdPatchArrays.clear();
osdPatchArrays.reserve(numTotalPatchArrays);
osdPatchArrays.reserve(narrays);
int narrays = patchTables.GetNumPatchArrays();
for (int array=0, pidx=0, vidx=0, qidx=0; array<narrays; ++array) {
Far::PatchDescriptor srcDesc = patchTables.GetPatchArrayDescriptor(array);
int npatches = patchTables.GetNumPatches(array),
nsubpatches = subPatchCounts[(int)srcDesc.GetPattern()],
nverts = srcDesc.GetNumControlVertices();
for (int i = 0; i < nsubpatches; ++i) {
PatchDescriptor desc(srcDesc, maxValence, i, numElements);
osdPatchArrays.push_back(PatchArray(desc, npatches, vidx, pidx, qidx));
}
PatchDescriptor desc(srcDesc, maxValence, numElements);
osdPatchArrays.push_back(PatchArray(desc, npatches, vidx, pidx, qidx));
vidx += npatches * nverts;
pidx += npatches;

View File

@ -68,17 +68,11 @@ public:
///
/// @param maxValence Highest vertex valence in the primitive
///
/// @param subPatch Index of the triangulated sub-patch for the given
/// transition pattern. Transition patches need to be
/// split into multiple sub-patches in order to be
/// rendered with hardware tessellation.
///
/// @param numElements The size of the vertex and varying data per-vertex
/// (in floats)
///
PatchDescriptor(Far::PatchDescriptor farDesc, unsigned char maxValence,
unsigned char subPatch, unsigned char numElements) :
_farDesc(farDesc), _maxValence(maxValence), _subPatch(subPatch), _numElements(numElements) { }
PatchDescriptor(Far::PatchDescriptor farDesc, unsigned char maxValence, unsigned char numElements) :
_farDesc(farDesc), _maxValence(maxValence), _numElements(numElements) { }
/// Returns the type of the patch
@ -86,16 +80,6 @@ public:
return _farDesc.GetType();
}
/// Returns the transition pattern of the patch if any (5 types)
Far::PatchDescriptor::TransitionPattern GetPattern() const {
return _farDesc.GetPattern();
}
/// Returns the rotation of the patch (4 rotations)
unsigned char GetRotation() const {
return _farDesc.GetRotation();
}
/// Returns the number of control vertices expected for a patch of the
/// type described
int GetNumControlVertices() const {
@ -107,11 +91,6 @@ public:
return _maxValence;
}
/// Returns the subpatch id
int GetSubPatch() const {
return _subPatch;
}
/// Returns the number of vertex elements
int GetNumElements() const {
return _numElements;
@ -131,7 +110,6 @@ public:
private:
Far::PatchDescriptor _farDesc;
unsigned char _maxValence;
unsigned char _subPatch;
unsigned char _numElements;
};
@ -261,9 +239,8 @@ inline bool
DrawContext::PatchDescriptor::operator < ( PatchDescriptor const other ) const
{
return _farDesc < other._farDesc or (_farDesc == other._farDesc and
(_subPatch < other._subPatch or ((_subPatch == other._subPatch) and
(_maxValence < other._maxValence or ((_maxValence == other._maxValence) and
(_numElements < other._numElements))))));
(_numElements < other._numElements))));
}
// True if the descriptors are identical
@ -271,7 +248,6 @@ inline bool
DrawContext::PatchDescriptor::operator == ( PatchDescriptor const other ) const
{
return _farDesc == other._farDesc and
_subPatch == other._subPatch and
_maxValence == other._maxValence and
_numElements == other._numElements;
}

View File

@ -84,133 +84,64 @@ GLDrawRegistryBase::_CreateDrawSourceConfig(
sconfig->commonShader.AddDefine("OSD_NUM_ELEMENTS", ss.str());
}
if (desc.GetPattern() == Far::PatchDescriptor::NON_TRANSITION) {
switch (desc.GetType()) {
case Far::PatchDescriptor::REGULAR:
sconfig->vertexShader.source = bsplineShaderSource;
sconfig->vertexShader.version = "#version 410\n";
sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_BSPLINE_SHADER");
sconfig->tessControlShader.source = bsplineShaderSource;
sconfig->tessControlShader.version = "#version 410\n";
sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_BSPLINE_SHADER");
sconfig->tessEvalShader.source = bsplineShaderSource;
sconfig->tessEvalShader.version = "#version 410\n";
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_BSPLINE_SHADER");
break;
case Far::PatchDescriptor::SINGLE_CREASE:
sconfig->vertexShader.source = bsplineShaderSource;
sconfig->vertexShader.version = "#version 410\n";
sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_BSPLINE_SHADER");
sconfig->tessControlShader.source = bsplineShaderSource;
sconfig->tessControlShader.version = "#version 410\n";
sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_BSPLINE_SHADER");
sconfig->tessControlShader.AddDefine("OSD_PATCH_SINGLE_CREASE");
sconfig->tessEvalShader.source = bsplineShaderSource;
sconfig->tessEvalShader.version = "#version 410\n";
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_BSPLINE_SHADER");
sconfig->tessEvalShader.AddDefine("OSD_PATCH_SINGLE_CREASE");
break;
case Far::PatchDescriptor::BOUNDARY:
sconfig->vertexShader.source = bsplineShaderSource;
sconfig->vertexShader.version = "#version 410\n";
sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_BSPLINE_SHADER");
sconfig->tessControlShader.source = bsplineShaderSource;
sconfig->tessControlShader.version = "#version 410\n";
sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_BSPLINE_SHADER");
sconfig->tessControlShader.AddDefine("OSD_PATCH_BOUNDARY");
sconfig->tessEvalShader.source = bsplineShaderSource;
sconfig->tessEvalShader.version = "#version 410\n";
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_BSPLINE_SHADER");
break;
case Far::PatchDescriptor::CORNER:
sconfig->vertexShader.source = bsplineShaderSource;
sconfig->vertexShader.version = "#version 410\n";
sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_BSPLINE_SHADER");
sconfig->tessControlShader.source = bsplineShaderSource;
sconfig->tessControlShader.version = "#version 410\n";
sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_BSPLINE_SHADER");
sconfig->tessControlShader.AddDefine("OSD_PATCH_CORNER");
sconfig->tessEvalShader.source = bsplineShaderSource;
sconfig->tessEvalShader.version = "#version 410\n";
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_BSPLINE_SHADER");
break;
case Far::PatchDescriptor::GREGORY:
sconfig->vertexShader.source = gregoryShaderSource;
sconfig->vertexShader.version = "#version 410\n";
sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_GREGORY_SHADER");
sconfig->tessControlShader.source = gregoryShaderSource;
sconfig->tessControlShader.version = "#version 410\n";
sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_GREGORY_SHADER");
sconfig->tessEvalShader.source = gregoryShaderSource;
sconfig->tessEvalShader.version = "#version 410\n";
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_GREGORY_SHADER");
break;
case Far::PatchDescriptor::GREGORY_BOUNDARY:
sconfig->vertexShader.source = gregoryShaderSource;
sconfig->vertexShader.version = "#version 410\n";
sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_GREGORY_SHADER");
sconfig->vertexShader.AddDefine("OSD_PATCH_GREGORY_BOUNDARY");
sconfig->tessControlShader.source = gregoryShaderSource;
sconfig->tessControlShader.version = "#version 410\n";
sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_GREGORY_SHADER");
sconfig->tessControlShader.AddDefine("OSD_PATCH_GREGORY_BOUNDARY");
sconfig->tessEvalShader.source = gregoryShaderSource;
sconfig->tessEvalShader.version = "#version 410\n";
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_GREGORY_SHADER");
sconfig->tessEvalShader.AddDefine("OSD_PATCH_GREGORY_BOUNDARY");
break;
case Far::PatchDescriptor::GREGORY_BASIS:
sconfig->vertexShader.source = gregoryBasisShaderSource;
sconfig->vertexShader.version = "#version 410\n";
sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_GREGORY_BASIS_SHADER");
sconfig->tessControlShader.source = gregoryBasisShaderSource;
sconfig->tessControlShader.version = "#version 410\n";
sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_GREGORY_BASIS_SHADER");
sconfig->tessEvalShader.source = gregoryBasisShaderSource;
sconfig->tessEvalShader.version = "#version 410\n";
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_GREGORY_BASIS_SHADER");
break;
default: // POINTS, LINES, QUADS, TRIANGLES
// do nothing
break;
}
} else { // pattern != NON_TRANSITION
switch (desc.GetType()) {
case Far::PatchDescriptor::REGULAR:
case Far::PatchDescriptor::BOUNDARY:
case Far::PatchDescriptor::CORNER:
sconfig->commonShader.AddDefine("OSD_PATCH_BSPLINE");
sconfig->commonShader.AddDefine("OSD_PATCH_ENABLE_SINGLE_CREASE");
sconfig->vertexShader.source = bsplineShaderSource;
sconfig->vertexShader.version = "#version 410\n";
sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_BSPLINE_SHADER");
sconfig->tessControlShader.source =
std::string(transitionShaderSource) + bsplineShaderSource;
std::string(transitionShaderSource) + bsplineShaderSource;
sconfig->tessControlShader.version = "#version 410\n";
sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_BSPLINE_SHADER");
sconfig->tessControlShader.AddDefine("OSD_PATCH_TRANSITION");
sconfig->tessEvalShader.source =
std::string(transitionShaderSource) + bsplineShaderSource;
std::string(transitionShaderSource) + bsplineShaderSource;
sconfig->tessEvalShader.version = "#version 410\n";
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_BSPLINE_SHADER");
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TRANSITION");
int pattern = desc.GetPattern() - 1;
int rotation = desc.GetRotation();
int subpatch = desc.GetSubPatch();
std::ostringstream ss;
ss << "OSD_TRANSITION_PATTERN" << pattern << subpatch;
sconfig->tessControlShader.AddDefine(ss.str());
sconfig->tessEvalShader.AddDefine(ss.str());
ss.str("");
ss << rotation;
sconfig->tessControlShader.AddDefine("OSD_TRANSITION_ROTATE", ss.str());
sconfig->tessEvalShader.AddDefine("OSD_TRANSITION_ROTATE", ss.str());
if (desc.GetType() == Far::PatchDescriptor::SINGLE_CREASE) {
sconfig->tessControlShader.AddDefine("OSD_PATCH_SINGLE_CREASE");
sconfig->tessEvalShader.AddDefine("OSD_PATCH_SINGLE_CREASE");
} else if (desc.GetType() == Far::PatchDescriptor::BOUNDARY) {
sconfig->tessControlShader.AddDefine("OSD_PATCH_BOUNDARY");
} else if (desc.GetType() == Far::PatchDescriptor::CORNER) {
sconfig->tessControlShader.AddDefine("OSD_PATCH_CORNER");
}
break;
case Far::PatchDescriptor::GREGORY:
sconfig->commonShader.AddDefine("OSD_PATCH_GREGORY");
sconfig->vertexShader.source = gregoryShaderSource;
sconfig->vertexShader.version = "#version 410\n";
sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_GREGORY_SHADER");
sconfig->tessControlShader.source = gregoryShaderSource;
sconfig->tessControlShader.version = "#version 410\n";
sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_GREGORY_SHADER");
sconfig->tessEvalShader.source = gregoryShaderSource;
sconfig->tessEvalShader.version = "#version 410\n";
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_GREGORY_SHADER");
break;
case Far::PatchDescriptor::GREGORY_BOUNDARY:
sconfig->commonShader.AddDefine("OSD_PATCH_GREGORY_BOUNDARY");
sconfig->vertexShader.source = gregoryShaderSource;
sconfig->vertexShader.version = "#version 410\n";
sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_GREGORY_SHADER");
sconfig->tessControlShader.source = gregoryShaderSource;
sconfig->tessControlShader.version = "#version 410\n";
sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_GREGORY_SHADER");
sconfig->tessControlShader.AddDefine("OSD_PATCH_GREGORY_BOUNDARY");
sconfig->tessEvalShader.source = gregoryShaderSource;
sconfig->tessEvalShader.version = "#version 410\n";
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_GREGORY_SHADER");
break;
case Far::PatchDescriptor::GREGORY_BASIS:
sconfig->commonShader.AddDefine("OSD_PATCH_GREGORY_BASIS");
sconfig->vertexShader.source = gregoryBasisShaderSource;
sconfig->vertexShader.version = "#version 410\n";
sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_GREGORY_BASIS_SHADER");
sconfig->tessControlShader.source = gregoryBasisShaderSource;
sconfig->tessControlShader.version = "#version 410\n";
sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_GREGORY_BASIS_SHADER");
sconfig->tessEvalShader.source = gregoryBasisShaderSource;
sconfig->tessEvalShader.version = "#version 410\n";
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_GREGORY_BASIS_SHADER");
break;
default: // POINTS, LINES, QUADS, TRIANGLES
// do nothing
break;
}
return sconfig;

View File

@ -30,6 +30,9 @@
#include "../osd/mesh.h"
#include "../osd/glDrawContext.h"
#include "../osd/vertexDescriptor.h"
#include "../far/endCapGregoryBasisPatchFactory.h"
#include "../far/endCapLegacyGregoryPatchFactory.h"
#include "../far/endCapRegularPatchFactory.h"
#ifdef OPENSUBDIV_HAS_OPENCL
# include "../osd/clComputeController.h"
@ -65,7 +68,8 @@ public:
_varyingBuffer(0),
_computeContext(0),
_computeController(computeController),
_drawContext(0)
_drawContext(0),
_numVertices(0)
{
GLMeshInterface::refineMesh(*_refiner, level,
@ -77,17 +81,12 @@ public:
int numVaryingElementsNonInterleaved =
(bits.test(MeshInterleaveVarying) ? 0 : numVaryingElements);
initializeContext(numVertexElements, numVaryingElements,
// numVertices is computed from stencilTables (may or may not includes gregory basis vertices)
initializeContext(numVertexElements,
numVaryingElements,
numVertexElementsInterleaved, level, bits);
int numVertices = GLMeshInterface::getNumVertices(*_refiner);
// FIXME: need a better API for numTotalVertices.
if (_patchTables->GetEndCapVertexStencilTables()) {
numVertices += _patchTables->GetEndCapVertexStencilTables()->GetNumStencils();
}
initializeVertexBuffers(numVertices,
initializeVertexBuffers(_numVertices,
numVertexElementsInterleaved,
numVaryingElementsNonInterleaved);
@ -98,7 +97,6 @@ public:
Mesh(ComputeController * computeController,
Far::TopologyRefiner * refiner,
Far::PatchTables * patchTables,
Far::KernelBatchVector const & kernelBatches,
VertexBuffer * vertexBuffer,
VertexBuffer * varyingBuffer,
ComputeContext * computeContext,
@ -106,12 +104,12 @@ public:
_refiner(refiner),
_patchTables(patchTables),
_kernelBatches(kernelBatches),
_vertexBuffer(vertexBuffer),
_varyingBuffer(varyingBuffer),
_computeContext(computeContext),
_computeController(computeController),
_drawContext(drawContext)
_drawContext(drawContext),
_numVertices(0)
{
_drawContext->UpdateVertexTexture(_vertexBuffer);
}
@ -125,11 +123,7 @@ public:
delete _drawContext;
}
virtual int GetNumVertices() const {
assert(_refiner);
return GLMeshInterface::getNumVertices(*_refiner);
}
virtual int GetNumVertices() const { return _numVertices; }
virtual void UpdateVertexBuffer(float const *vertexData, int startVertex, int numVerts) {
_vertexBuffer->UpdateData(vertexData, startVertex, numVerts);
@ -140,14 +134,15 @@ public:
}
virtual void Refine() {
_computeController->Compute(_computeContext, _kernelBatches, _vertexBuffer, _varyingBuffer);
_computeController->Compute(_computeContext, _vertexBuffer, _varyingBuffer);
}
virtual void Refine(VertexBufferDescriptor const * vertexDesc,
VertexBufferDescriptor const * varyingDesc,
bool interleaved) {
_computeController->Compute(_computeContext, _kernelBatches,
_vertexBuffer, (interleaved ? _vertexBuffer : _varyingBuffer),
_computeController->Compute(_computeContext,
_vertexBuffer,
(interleaved ? _vertexBuffer : _varyingBuffer),
vertexDesc, varyingDesc);
}
@ -212,54 +207,73 @@ private:
varyingStencils = Far::StencilTablesFactory::Create(*_refiner, options);
}
assert(_refiner);
Far::PatchTablesFactory::Options poptions(level);
poptions.generateFVarTables = bits.test(MeshFVarData);
poptions.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch);
if (bits.test(MeshUseGregoryBasis)) {
poptions.adaptiveStencilTables = vertexStencils;
poptions.adaptiveVaryingStencilTables = varyingStencils;
}
if (bits.test(MeshEndCapRegular) and bits.test(MeshAdaptive)) {
// use regular endcap
Far::EndCapRegularPatchFactory *endCapFactory =
new Far::EndCapRegularPatchFactory(*_refiner);
_patchTables = Far::PatchTablesFactoryT<Far::EndCapRegularPatchFactory>::Create(*_refiner, poptions,
endCapFactory);
if (endCapFactory) {
if (Far::StencilTables const *vertexStencilsWithGregoryBasis =
endCapFactory->CreateVertexStencilTables(vertexStencils, true)) {
delete vertexStencils;
vertexStencils = vertexStencilsWithGregoryBasis;
}
_patchTables = Far::PatchTablesFactory::Create(*_refiner, poptions);
if (varyingStencils) {
if (Far::StencilTables const *varyingStencilsWithGregoryBasis =
endCapFactory->CreateVaryingStencilTables(varyingStencils, true)) {
delete varyingStencils;
varyingStencils = varyingStencilsWithGregoryBasis;
}
}
}
delete endCapFactory;
} else if (bits.test(MeshEndCapGregoryBasis) and bits.test(MeshAdaptive)) {
// use gregory stencils
Far::EndCapGregoryBasisPatchFactory *gregoryBasisFactory =
new Far::EndCapGregoryBasisPatchFactory(*_refiner, /*share verts=*/true);
_patchTables = Far::PatchTablesFactoryT<Far::EndCapGregoryBasisPatchFactory>::Create(*_refiner, poptions, gregoryBasisFactory);
if (gregoryBasisFactory) {
if (Far::StencilTables const *vertexStencilsWithGregoryBasis =
gregoryBasisFactory->CreateVertexStencilTables(vertexStencils, true)) {
delete vertexStencils;
vertexStencils = vertexStencilsWithGregoryBasis;
}
if (varyingStencils) {
if (Far::StencilTables const *varyingStencilsWithGregoryBasis =
gregoryBasisFactory->CreateVaryingStencilTables(varyingStencils, true)) {
delete varyingStencils;
varyingStencils = varyingStencilsWithGregoryBasis;
}
}
}
delete gregoryBasisFactory;
} else if (bits.test(MeshEndCapLegacyGregory) and bits.test(MeshAdaptive)) {
// use legacy gregory
Far::EndCapLegacyGregoryPatchFactory *gregoryPatchFactory =
new Far::EndCapLegacyGregoryPatchFactory(*_refiner);
_patchTables = Far::PatchTablesFactoryT<Far::EndCapLegacyGregoryPatchFactory>::Create(*_refiner, poptions, gregoryPatchFactory);
gregoryPatchFactory->AddGregoryPatchTables(_patchTables);
delete gregoryPatchFactory;
} else {
_patchTables = Far::PatchTablesFactory::Create(*_refiner, poptions);
}
_drawContext = DrawContext::Create(_patchTables, numElements);
// XXX: factory API fix needed
// merge greogry basis stencils
Far::StencilTables const * endCapVertexStencils =
_patchTables->GetEndCapVertexStencilTables();
if (endCapVertexStencils) {
Far::StencilTables const * endCapVaryingStencils =
_patchTables->GetEndCapVaryingStencilTables();
// concatinate vertexStencils and endCapStencils.
// note that endCapStensils is owned by patchTable.
Far::StencilTables const *inStencils[] = {
vertexStencils, endCapVertexStencils
};
Far::StencilTables const *concatStencils =
Far::StencilTablesFactory::Create(2, inStencils);
Far::StencilTables const *inVaryingStencils[] = {
varyingStencils, endCapVaryingStencils
};
Far::StencilTables const *concatVaryingStencils =
Far::StencilTablesFactory::Create(2, inVaryingStencils);
delete vertexStencils;
vertexStencils = concatStencils;
delete varyingStencils;
varyingStencils = concatVaryingStencils;
}
_kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils));
_computeContext = ComputeContext::Create(vertexStencils,
varyingStencils);
// numvertices = coarse verts + refined verts + gregory basis verts
_numVertices = vertexStencils->GetNumControlVertices()
+ vertexStencils->GetNumStencils();
delete vertexStencils;
delete varyingStencils;
}
@ -279,7 +293,6 @@ private:
Far::TopologyRefiner * _refiner;
Far::PatchTables * _patchTables;
Far::KernelBatchVector _kernelBatches;
VertexBuffer *_vertexBuffer;
VertexBuffer *_varyingBuffer;
@ -288,6 +301,8 @@ private:
ComputeController *_computeController;
DrawContext *_drawContext;
int _numVertices;
};
#ifdef OPENSUBDIV_HAS_OPENCL
@ -317,6 +332,7 @@ public:
_computeContext(0),
_computeController(computeController),
_drawContext(0),
_numVertices(0),
_clContext(clContext),
_clQueue(clQueue)
{
@ -332,17 +348,11 @@ public:
int numVaryingElementsNonInterleaved =
(bits.test(MeshInterleaveVarying) ? 0 : numVaryingElements);
initializeContext(numVertexElements, numVaryingElements,
initializeContext(numVertexElements,
numVaryingElements,
numVertexElementsInterleaved, level, bits);
int numVertices = GLMeshInterface::getNumVertices(*_refiner);
// FIXME: need better API for total number of vertices.
if (_patchTables->GetEndCapVertexStencilTables()) {
numVertices += _patchTables->GetEndCapVertexStencilTables()->GetNumStencils();
}
initializeVertexBuffers(numVertices,
initializeVertexBuffers(_numVertices,
numVertexElementsInterleaved,
numVaryingElementsNonInterleaved);
@ -353,7 +363,6 @@ public:
Mesh(ComputeController * computeController,
Far::TopologyRefiner * refiner,
Far::PatchTables * patchTables,
Far::KernelBatchVector const & kernelBatches,
VertexBuffer * vertexBuffer,
VertexBuffer * varyingBuffer,
ComputeContext * computeContext,
@ -363,12 +372,12 @@ public:
_refiner(refiner),
_patchTables(patchTables),
_kernelBatches(kernelBatches),
_vertexBuffer(vertexBuffer),
_varyingBuffer(varyingBuffer),
_computeContext(computeContext),
_computeController(computeController),
_drawContext(drawContext),
_numVertices(0),
_clContext(clContext),
_clQueue(clQueue)
{
@ -384,7 +393,7 @@ public:
delete _drawContext;
}
virtual int GetNumVertices() const { return _refiner->GetNumVerticesTotal(); }
virtual int GetNumVertices() const { return _numVertices; }
virtual void UpdateVertexBuffer(float const *vertexData, int startVertex, int numVerts) {
_vertexBuffer->UpdateData(vertexData, startVertex, numVerts, _clQueue);
@ -395,14 +404,15 @@ public:
}
virtual void Refine() {
_computeController->Compute(_computeContext, _kernelBatches, _vertexBuffer, _varyingBuffer);
_computeController->Compute(_computeContext, _vertexBuffer, _varyingBuffer);
}
virtual void Refine(VertexBufferDescriptor const *vertexDesc,
VertexBufferDescriptor const *varyingDesc,
bool interleaved) {
_computeController->Compute(_computeContext, _kernelBatches,
_vertexBuffer, (interleaved ? _vertexBuffer : _varyingBuffer),
_computeController->Compute(_computeContext,
_vertexBuffer,
(interleaved ? _vertexBuffer : _varyingBuffer),
vertexDesc, varyingDesc);
}
@ -467,58 +477,76 @@ private:
_computeContext = ComputeContext::Create(_clContext, vertexStencils, varyingStencils);
assert(_refiner);
Far::PatchTablesFactory::Options poptions(level);
poptions.generateFVarTables = bits.test(MeshFVarData);
poptions.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch);
// use gregory stencils
if (bits.test(MeshUseGregoryBasis)) {
poptions.adaptiveStencilTables = vertexStencils;
poptions.adaptiveVaryingStencilTables = varyingStencils;
}
_patchTables = Far::PatchTablesFactory::Create(*_refiner, poptions);
if (bits.test(MeshEndCapRegular) and bits.test(MeshAdaptive)) {
// use regular endcap
Far::EndCapRegularPatchFactory *endCapFactory =
new Far::EndCapRegularPatchFactory(*_refiner);
_patchTables = Far::PatchTablesFactoryT<Far::EndCapRegularPatchFactory>::Create(*_refiner, poptions,
endCapFactory);
if (endCapFactory) {
if (Far::StencilTables const *vertexStencilsWithGregoryBasis =
endCapFactory->CreateVertexStencilTables(vertexStencils, true)) {
delete vertexStencils;
vertexStencils = vertexStencilsWithGregoryBasis;
}
if (varyingStencils) {
if (Far::StencilTables const *varyingStencilsWithGregoryBasis =
endCapFactory->CreateVaryingStencilTables(varyingStencils, true)) {
delete varyingStencils;
varyingStencils = varyingStencilsWithGregoryBasis;
}
}
}
delete endCapFactory;
} else if (bits.test(MeshEndCapGregoryBasis) and bits.test(MeshAdaptive)) {
// use gregory stencils
Far::EndCapGregoryBasisPatchFactory *gregoryBasisFactory =
new Far::EndCapGregoryBasisPatchFactory(*_refiner, /*share verts=*/true);
_patchTables = Far::PatchTablesFactoryT<Far::EndCapGregoryBasisPatchFactory>::Create(*_refiner, poptions, gregoryBasisFactory);
if (gregoryBasisFactory) {
if (Far::StencilTables const *vertexStencilsWithGregoryBasis =
gregoryBasisFactory->CreateVertexStencilTables(vertexStencils, true)) {
delete vertexStencils;
vertexStencils = vertexStencilsWithGregoryBasis;
}
if (varyingStencils) {
if (Far::StencilTables const *varyingStencilsWithGregoryBasis =
gregoryBasisFactory->CreateVaryingStencilTables(varyingStencils, true)) {
delete varyingStencils;
varyingStencils = varyingStencilsWithGregoryBasis;
}
}
}
delete gregoryBasisFactory;
} else if (bits.test(MeshEndCapLegacyGregory) and bits.test(MeshAdaptive)) {
// use legacy gregory
Far::EndCapLegacyGregoryPatchFactory *gregoryPatchFactory =
new Far::EndCapLegacyGregoryPatchFactory(*_refiner);
_patchTables = Far::PatchTablesFactoryT<Far::EndCapLegacyGregoryPatchFactory>::Create(*_refiner, poptions, gregoryPatchFactory);
gregoryPatchFactory->AddGregoryPatchTables(_patchTables);
delete gregoryPatchFactory;
} else {
_patchTables = Far::PatchTablesFactory::Create(*_refiner, poptions);
}
_drawContext = DrawContext::Create(_patchTables, numElements);
Far::StencilTables const *endCapVertexStencils =
_patchTables->GetEndCapVertexStencilTables();
if (endCapVertexStencils) {
Far::StencilTables const *endCapVaryingStencils =
_patchTables->GetEndCapVaryingStencilTables();
// concatinate vertexStencils and endCapStencils.
// note that endCapStensils is owned by patchTable.
Far::StencilTables const *inStencils[] = {
vertexStencils, endCapVertexStencils
};
Far::StencilTables const *concatStencils =
Far::StencilTablesFactory::Create(2, inStencils);
_kernelBatches.push_back(Far::StencilTablesFactory::Create(*concatStencils));
Far::StencilTables const *inVaryingStencils[] = {
varyingStencils, endCapVaryingStencils
};
Far::StencilTables const *concatVaryingStencils =
Far::StencilTablesFactory::Create(2, inVaryingStencils);
delete vertexStencils;
vertexStencils = concatStencils;
delete varyingStencils;
varyingStencils = concatVaryingStencils;
}
_kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils));
_computeContext = ComputeContext::Create(_clContext,
vertexStencils,
varyingStencils);
// numvertices = coarse verts + refined verts + gregory basis verts
_numVertices = vertexStencils->GetNumControlVertices()
+ vertexStencils->GetNumStencils();
delete vertexStencils;
delete varyingStencils;
}
@ -538,7 +566,6 @@ private:
Far::TopologyRefiner * _refiner;
Far::PatchTables * _patchTables;
Far::KernelBatchVector _kernelBatches;
VertexBuffer *_vertexBuffer;
VertexBuffer *_varyingBuffer;
@ -547,6 +574,7 @@ private:
ComputeController *_computeController;
DrawContext *_drawContext;
int _numVertices;
cl_context _clContext;
cl_command_queue _clQueue;

View File

@ -67,17 +67,22 @@ class GLSLComputeContext::GLSLStencilTables {
public:
GLSLStencilTables(Far::StencilTables const & stencilTables) {
_sizes = createGLSLBuffer(stencilTables.GetSizes());
_offsets = createGLSLBuffer(stencilTables.GetOffsets());
_indices = createGLSLBuffer(stencilTables.GetControlIndices());
_weights = createGLSLBuffer(stencilTables.GetWeights());
_numStencils = stencilTables.GetNumStencils();
if (_numStencils > 0) {
_sizes = createGLSLBuffer(stencilTables.GetSizes());
_offsets = createGLSLBuffer(stencilTables.GetOffsets());
_indices = createGLSLBuffer(stencilTables.GetControlIndices());
_weights = createGLSLBuffer(stencilTables.GetWeights());
} else {
_sizes = _offsets = _indices = _weights = 0;
}
}
~GLSLStencilTables() {
glDeleteBuffers(1, &_sizes);
glDeleteBuffers(1, &_offsets);
glDeleteBuffers(1, &_weights);
glDeleteBuffers(1, &_indices);
if (_sizes) glDeleteBuffers(1, &_sizes);
if (_offsets) glDeleteBuffers(1, &_offsets);
if (_weights) glDeleteBuffers(1, &_weights);
if (_indices) glDeleteBuffers(1, &_indices);
}
bool IsValid() const {
@ -100,6 +105,10 @@ public:
return _weights;
}
int GetNumStencils() const {
return _numStencils;
}
void Bind() const {
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, _sizes);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, _offsets);
@ -122,6 +131,7 @@ private:
_offsets,
_indices,
_weights;
int _numStencils;
};
// -----------------------------------------------------------------------------
@ -130,7 +140,8 @@ GLSLComputeContext::GLSLComputeContext(
Far::StencilTables const * vertexStencilTables,
Far::StencilTables const * varyingStencilTables) :
_vertexStencilTables(0), _varyingStencilTables(0),
_numControlVertices(0) {
_numControlVertices(0),
_numStencils(0) {
if (vertexStencilTables) {
_vertexStencilTables = new GLSLStencilTables(*vertexStencilTables);
@ -165,8 +176,17 @@ GLSLComputeContext::HasVaryingStencilTables() const {
return _varyingStencilTables ? _varyingStencilTables->IsValid() : false;
}
// ----------------------------------------------------------------------------
int
GLSLComputeContext::GetNumStencilsInVertexStencilTables() const {
return _vertexStencilTables ? _vertexStencilTables->GetNumStencils() : false;
}
int
GLSLComputeContext::GetNumStencilsInVaryingStencilTables() const {
return _varyingStencilTables ? _varyingStencilTables->GetNumStencils() : false;
}
// ----------------------------------------------------------------------------
void
GLSLComputeContext::BindVertexStencilTables() const {

View File

@ -76,10 +76,16 @@ public:
return _numControlVertices;
}
/// Returns the Cuda buffer containing vertex-stencil stencil sizes
/// Returns the number of stencils in vertex stencil table
int GetNumStencilsInVertexStencilTables() const;
/// Returns the number of stencils in varying stencil table
int GetNumStencilsInVaryingStencilTables() const;
/// Returns the GL buffer containing vertex-stencil stencil sizes
GLuint GetVertexStencilTablesSizes() const;
/// Returns the Cuda buffer containing vertex-stencil stencil offsets
/// Returns the GL buffer containing vertex-stencil stencil offsets
GLuint GetVertexStencilTablesOffsets() const;
/// Binds GL buffers containing stencils for 'vertex' interpolation
@ -104,6 +110,7 @@ private:
* _varyingStencilTables;
int _numControlVertices;
int _numStencils;
};
} // end namespace Osd

View File

@ -24,7 +24,6 @@
#include "../osd/glslComputeController.h"
#include "../osd/vertexDescriptor.h"
//#include "../osd/debug.h"
#include "../osd/opengl.h"
#include "../far/error.h"
@ -119,8 +118,6 @@ public:
glDeleteShader(shader);
_subStencilKernel = glGetSubroutineIndex(_program, GL_COMPUTE_SHADER, "computeStencil");
// set uniform locations for compute kernels
_uniformSizes = glGetUniformLocation(_program, "sterncilSizes");
_uniformOffsets = glGetUniformLocation(_program, "sterncilOffsets");
@ -138,12 +135,10 @@ public:
return true;
}
void ApplyStencilTableKernel(Far::KernelBatch const &batch, int offset, int numCVs) const {
void ApplyStencilTableKernel(int offset, int numCVs,
int start, int end) const {
// select stencil GLSL subroutine
glUniformSubroutinesuiv(GL_COMPUTE_SHADER, 1, &_subStencilKernel);
dispatchCompute(offset, numCVs, batch.start, batch.end);
dispatchCompute(offset, numCVs, start, end);
}
struct Match {
@ -191,8 +186,6 @@ private:
GLuint _program;
GLuint _subStencilKernel; // stencil compute kernel GLSL subroutine
GLuint _uniformSizes, // uniform paramaeters for kernels
_uniformOffsets,
_uniformIndices,
@ -214,12 +207,20 @@ private:
void
GLSLComputeController::ApplyStencilTableKernel(
Far::KernelBatch const &batch, ComputeContext const *context) const {
ComputeContext const *context, int numStencils) const {
assert(context);
// Note: GLSLComputeContext has a state, knowing whether vertex or
// varying stencil tables are being bound. GetNumStencils() reflects it.
// This structure will likely be revisited.
int start = 0;
int end = numStencils;
_currentBindState.kernelBundle->ApplyStencilTableKernel(
batch, _currentBindState.desc.offset, context->GetNumControlVertices());
_currentBindState.desc.offset, context->GetNumControlVertices(),
start, end);
}
// ----------------------------------------------------------------------------

View File

@ -27,11 +27,11 @@
#include "../version.h"
#include "../far/kernelBatchDispatcher.h"
#include "../osd/glslComputeContext.h"
#include "../osd/vertexDescriptor.h"
#include <vector>
#include <cassert>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
@ -79,28 +79,27 @@ public:
///
template<class VERTEX_BUFFER, class VARYING_BUFFER>
void Compute( GLSLComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER * vertexBuffer,
VARYING_BUFFER * varyingBuffer,
VertexBufferDescriptor const * vertexDesc=NULL,
VertexBufferDescriptor const * varyingDesc=NULL ){
if (batches.empty()) return;
if (vertexBuffer) {
bind(vertexBuffer, vertexDesc);
context->BindVertexStencilTables();
Far::KernelBatchDispatcher::Apply(this, context, batches, /*maxlevel*/ -1);
ApplyStencilTableKernel(
context, context->GetNumStencilsInVertexStencilTables());
}
if (varyingBuffer) {
bind(varyingBuffer, varyingDesc);
context->BindVaryingStencilTables();
Far::KernelBatchDispatcher::Apply(this, context, batches, /*maxlevel*/ -1);
ApplyStencilTableKernel(
context, context->GetNumStencilsInVaryingStencilTables());
}
context->UnbindStencilTables();
@ -119,10 +118,9 @@ public:
///
template<class VERTEX_BUFFER>
void Compute(GLSLComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER *vertexBuffer) {
Compute<VERTEX_BUFFER>(context, batches, vertexBuffer, (VERTEX_BUFFER*)0);
Compute<VERTEX_BUFFER>(context, vertexBuffer, (VERTEX_BUFFER*)0);
}
/// Waits until all running subdivision kernels finish.
@ -130,10 +128,8 @@ public:
protected:
friend class Far::KernelBatchDispatcher;
void ApplyStencilTableKernel(Far::KernelBatch const &batch,
ComputeContext const *context) const;
void ApplyStencilTableKernel(ComputeContext const *context,
int numStencils) const;
template<class BUFFER>
void bind( BUFFER * buffer,

View File

@ -22,9 +22,6 @@
// language governing permissions and limitations under the Apache License.
//
subroutine void computeKernelType();
subroutine uniform computeKernelType computeKernel;
//------------------------------------------------------------------------------
uniform int batchStart = 0;
@ -76,8 +73,7 @@ void addWithWeight(inout Vertex v, const Vertex src, float weight) {
}
//------------------------------------------------------------------------------
subroutine(computeKernelType)
void computeStencil() {
void main() {
int current = int(gl_GlobalInvocationID.x) + batchStart;
@ -90,7 +86,7 @@ void computeStencil() {
int offset = _offsets[current],
size = int(_sizes[current]);
for (int i=0; i<size; ++i) {
addWithWeight(dst, readVertex( _indices[offset+i] ), _weights[offset+i]);
}
@ -101,11 +97,3 @@ void computeStencil() {
}
//------------------------------------------------------------------------------
void main()
{
// call subroutine
computeKernel();
}
//------------------------------------------------------------------------------

View File

@ -65,14 +65,6 @@ uniform mat4 Mi = mat4(
0.f, 0.f, 1.f, 0.f
);
// Boundary / Corner
uniform mat4x3 B = mat4x3(
1.f, 0.f, 0.f,
4.f/6.f, 2.f/6.f, 0.f,
2.f/6.f, 4.f/6.f, 0.f,
1.f/6.f, 4.f/6.f, 1.f/6.f
);
layout(vertices = 16) out;
in block {
@ -82,7 +74,7 @@ in block {
out block {
ControlVertex v;
#if defined OSD_PATCH_SINGLE_CREASE
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
vec4 P1;
vec4 P2;
float sharpness;
@ -92,6 +84,35 @@ out block {
#define ID gl_InvocationID
void
reflectBoundaryEdges(inout vec3 cpt[16], int patchParam)
{
if (((patchParam >> 4) & 1) != 0) {
cpt[0] = 2*cpt[4] - cpt[8];
cpt[1] = 2*cpt[5] - cpt[9];
cpt[2] = 2*cpt[6] - cpt[10];
cpt[3] = 2*cpt[7] - cpt[11];
}
if (((patchParam >> 4) & 2) != 0) {
cpt[3] = 2*cpt[2] - cpt[1];
cpt[7] = 2*cpt[6] - cpt[5];
cpt[11] = 2*cpt[10] - cpt[9];
cpt[15] = 2*cpt[14] - cpt[13];
}
if (((patchParam >> 4) & 4) != 0) {
cpt[12] = 2*cpt[8] - cpt[4];
cpt[13] = 2*cpt[9] - cpt[5];
cpt[14] = 2*cpt[10] - cpt[6];
cpt[15] = 2*cpt[11] - cpt[7];
}
if (((patchParam >> 4) & 8) != 0) {
cpt[0] = 2*cpt[1] - cpt[2];
cpt[4] = 2*cpt[5] - cpt[6];
cpt[8] = 2*cpt[9] - cpt[10];
cpt[12] = 2*cpt[13] - cpt[14];
}
}
// compute single-crease patch matrix
mat4
ComputeMatrixSimplified(float sharpness)
@ -117,100 +138,67 @@ void main()
int i = ID%4;
int j = ID/4;
#if defined OSD_PATCH_BOUNDARY
vec3 H[3];
for (int l=0; l<3; ++l) {
H[l] = vec3(0,0,0);
for (int k=0; k<4; ++k) {
H[l] += Q[i][k] * inpt[l*4 + k].v.position.xyz;
}
vec3 position[16];
for (int i=0; i<16; ++i) {
position[i] = inpt[i].v.position.xyz;
}
vec3 pos = vec3(0,0,0);
for (int k=0; k<3; ++k) {
pos += B[j][k]*H[k];
}
int patchParam = GetPatchParam();
outpt[ID].v.position = vec4(pos, 1.0);
reflectBoundaryEdges(position, patchParam);
#elif defined OSD_PATCH_CORNER
vec3 H[3];
for (int l=0; l<3; ++l) {
H[l] = vec3(0,0,0);
for (int k=0; k<3; ++k) {
H[l] += B[3-i][2-k] * inpt[l*3 + k].v.position.xyz;
}
}
vec3 pos = vec3(0,0,0);
for (int k=0; k<3; ++k) {
pos += B[j][k]*H[k];
}
outpt[ID].v.position = vec4(pos, 1.0);
#else // not OSD_PATCH_BOUNDARY, not OSD_PATCH_CORNER
vec3 H[4];
for (int l=0; l<4; ++l) {
H[l] = vec3(0,0,0);
for (int k=0; k<4; ++k) {
H[l] += Q[i][k] * inpt[l*4 + k].v.position.xyz;
H[l] += Q[i][k] * position[l*4 + k].xyz;
}
}
#if defined OSD_PATCH_SINGLE_CREASE
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
float sharpness = GetSharpness();
float Sf = floor(sharpness);
float Sc = ceil(sharpness);
float Sr = fract(sharpness);
mat4 Mf = ComputeMatrixSimplified(Sf);
mat4 Mc = ComputeMatrixSimplified(Sc);
mat4 Mj = (1-Sr) * Mf + Sr * Mi;
mat4 Ms = (1-Sr) * Mf + Sr * Mc;
if (sharpness > 0) {
float Sf = floor(sharpness);
float Sc = ceil(sharpness);
float Sr = fract(sharpness);
mat4 Mf = ComputeMatrixSimplified(Sf);
mat4 Mc = ComputeMatrixSimplified(Sc);
mat4 Mj = (1-Sr) * Mf + Sr * Mi;
mat4 Ms = (1-Sr) * Mf + Sr * Mc;
vec3 P = vec3(0);
vec3 P1 = vec3(0);
vec3 P2 = vec3(0);
for (int k=0; k<4; ++k) {
P += Mi[j][k]*H[k]; // 0 to 1-2^(-Sf)
P1 += Mj[j][k]*H[k]; // 1-2^(-Sf) to 1-2^(-Sc)
P2 += Ms[j][k]*H[k]; // 1-2^(-Sc) to 1
}
outpt[ID].v.position = vec4(P, 1.0);
outpt[ID].P1 = vec4(P1, 1.0);
outpt[ID].P2 = vec4(P2, 1.0);
outpt[ID].sharpness = sharpness;
#else // REGULAR
vec3 pos = vec3(0,0,0);
for (int k=0; k<4; ++k) {
pos += Q[j][k]*H[k];
vec3 P = vec3(0);
vec3 P1 = vec3(0);
vec3 P2 = vec3(0);
for (int k=0; k<4; ++k) {
P += Mi[j][k]*H[k]; // 0 to 1-2^(-Sf)
P1 += Mj[j][k]*H[k]; // 1-2^(-Sf) to 1-2^(-Sc)
P2 += Ms[j][k]*H[k]; // 1-2^(-Sc) to 1
}
outpt[ID].v.position = vec4(P, 1.0);
outpt[ID].P1 = vec4(P1, 1.0);
outpt[ID].P2 = vec4(P2, 1.0);
outpt[ID].sharpness = sharpness;
} else {
vec3 pos = vec3(0,0,0);
for (int k=0; k<4; ++k) {
pos += Q[j][k]*H[k];
}
outpt[ID].v.position = vec4(pos, 1.0);
outpt[ID].P1 = vec4(0);
outpt[ID].P2 = vec4(0);
outpt[ID].sharpness = 0;
}
outpt[ID].v.position = vec4(pos, 1.0);
#endif
#endif
#if defined OSD_PATCH_BOUNDARY
const int p[16] = int[]( 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 );
#elif defined OSD_PATCH_CORNER
const int p[16] = int[]( 0, 1, 2, 2, 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8 );
#else
const int p[16] = int[]( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 );
{
vec3 pos = vec3(0,0,0);
for (int k=0; k<4; ++k) {
pos += Q[j][k]*H[k];
}
outpt[ID].v.position = vec4(pos, 1.0);
}
#endif
#if OSD_TRANSITION_ROTATE == 0
const int r[16] = int[]( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 );
#elif OSD_TRANSITION_ROTATE == 1
const int r[16] = int[]( 12, 8, 4, 0, 13, 9, 5, 1, 14, 10, 6, 2, 15, 11, 7, 3 );
#elif OSD_TRANSITION_ROTATE == 2
const int r[16] = int[]( 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 );
#elif OSD_TRANSITION_ROTATE == 3
const int r[16] = int[]( 3, 7, 11, 15, 2, 6, 10, 14, 1, 5, 9, 13, 0, 4, 8, 12 );
#endif
OSD_USER_VARYING_PER_CONTROL_POINT(ID, p[r[ID]]);
OSD_USER_VARYING_PER_CONTROL_POINT(ID, ID);
int patchLevel = GetPatchLevel();
@ -221,38 +209,33 @@ void main()
OSD_COMPUTE_PTEX_COORD_TESSCONTROL_SHADER;
#if defined OSD_ENABLE_SCREENSPACE_TESSELLATION
// Wait for all basis conversion to be finished
barrier();
#endif
if (ID == 0) {
OSD_PATCH_CULL(OSD_PATCH_INPUT_SIZE);
#ifdef OSD_PATCH_TRANSITION
vec3 cp[OSD_PATCH_INPUT_SIZE];
for(int k = 0; k < OSD_PATCH_INPUT_SIZE; ++k) cp[k] = inpt[k].v.position.xyz;
SetTransitionTessLevels(cp, patchLevel);
vec4 outerLevel = vec4(0);
vec2 innerLevel = vec2(0);
#if defined OSD_ENABLE_SCREENSPACE_TESSELLATION
// Gather bezier control points to compute limit surface tess levels
vec3 cpBezier[16];
for (int i=0; i<16; ++i) {
cpBezier[i] = outpt[i].v.position.xyz;
}
GetTransitionTessLevels(cpBezier, patchParam, outerLevel, innerLevel);
#else
#if defined OSD_PATCH_BOUNDARY
const int p[4] = int[]( 1, 2, 5, 6 );
#elif defined OSD_PATCH_CORNER
const int p[4] = int[]( 1, 2, 4, 5 );
#else
const int p[4] = int[]( 5, 6, 9, 10 );
#endif
#ifdef OSD_ENABLE_SCREENSPACE_TESSELLATION
gl_TessLevelOuter[0] = TessAdaptive(inpt[p[0]].v.position.xyz, inpt[p[2]].v.position.xyz);
gl_TessLevelOuter[1] = TessAdaptive(inpt[p[0]].v.position.xyz, inpt[p[1]].v.position.xyz);
gl_TessLevelOuter[2] = TessAdaptive(inpt[p[1]].v.position.xyz, inpt[p[3]].v.position.xyz);
gl_TessLevelOuter[3] = TessAdaptive(inpt[p[2]].v.position.xyz, inpt[p[3]].v.position.xyz);
gl_TessLevelInner[0] = max(gl_TessLevelOuter[1], gl_TessLevelOuter[3]);
gl_TessLevelInner[1] = max(gl_TessLevelOuter[0], gl_TessLevelOuter[2]);
#else
gl_TessLevelInner[0] = GetTessLevel(patchLevel);
gl_TessLevelInner[1] = GetTessLevel(patchLevel);
gl_TessLevelOuter[0] = GetTessLevel(patchLevel);
gl_TessLevelOuter[1] = GetTessLevel(patchLevel);
gl_TessLevelOuter[2] = GetTessLevel(patchLevel);
gl_TessLevelOuter[3] = GetTessLevel(patchLevel);
#endif
GetTransitionTessLevels(position, patchParam, outerLevel, innerLevel);
#endif
gl_TessLevelOuter[0] = outerLevel[0];
gl_TessLevelOuter[1] = outerLevel[1];
gl_TessLevelOuter[2] = outerLevel[2];
gl_TessLevelOuter[3] = outerLevel[3];
gl_TessLevelInner[0] = innerLevel[0];
gl_TessLevelInner[1] = innerLevel[1];
}
}
@ -269,15 +252,17 @@ void main()
layout(quads) in;
#endif
/* XXXdyu-patch-drawing support for frational spacing
#if defined OSD_FRACTIONAL_ODD_SPACING
layout(fractional_odd_spacing) in;
#elif defined OSD_FRACTIONAL_EVEN_SPACING
layout(fractional_even_spacing) in;
#endif
*/
in block {
ControlVertex v;
#if defined OSD_PATCH_SINGLE_CREASE
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
vec4 P1;
vec4 P2;
float sharpness;
@ -287,16 +272,15 @@ in block {
out block {
OutputVertex v;
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
float sharpness;
#endif
OSD_USER_VARYING_DECLARE
} outpt;
void main()
{
#ifdef OSD_PATCH_TRANSITION
vec2 UV = GetTransitionSubpatchUV();
#else
vec2 UV = gl_TessCoord.xy;
#endif
vec2 UV = GetTransitionParameterization();
#ifdef OSD_COMPUTE_NORMAL_DERIVATIVES
float B[4], D[4], C[4];
@ -311,52 +295,60 @@ void main()
Univar4x4(UV.x, B, D);
#endif
#if defined OSD_PATCH_SINGLE_CREASE
// ----------------------------------------------------------------
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
// sharpness
float sharpness = inpt[0].sharpness;
float s0 = 1.0 - pow(2.0f, -floor(sharpness));
float s1 = 1.0 - pow(2.0f, -ceil(sharpness));
#endif
if (sharpness != 0) {
float s0 = 1.0 - pow(2.0f, -floor(sharpness));
float s1 = 1.0 - pow(2.0f, -ceil(sharpness));
for (int i=0; i<4; ++i) {
for (int j=0; j<4; ++j) {
#if defined OSD_PATCH_SINGLE_CREASE
#if OSD_TRANSITION_ROTATE == 1
int k = 4*(3-j) + i;
float s = 1-UV.x;
#elif OSD_TRANSITION_ROTATE == 2
int k = 4*(3-i) + (3-j);
float s = 1-UV.y;
#elif OSD_TRANSITION_ROTATE == 3
int k = 4*j + (3-i);
float s = UV.x;
#else // ROTATE=0 or non-transition
int k = 4*i + j;
float s = UV.y;
#endif
vec3 A = (s < s0) ?
inpt[k].v.position.xyz :
((s < s1) ?
inpt[k].P1.xyz :
inpt[k].P2.xyz);
for (int i=0; i<4; ++i) {
for (int j=0; j<4; ++j) {
int k = 4*i + j;
float s = UV.y;
#else // !SINGLE_CREASE
#if OSD_TRANSITION_ROTATE == 1
vec3 A = inpt[4*(3-j) + i].v.position.xyz;
#elif OSD_TRANSITION_ROTATE == 2
vec3 A = inpt[4*(3-i) + (3-j)].v.position.xyz;
#elif OSD_TRANSITION_ROTATE == 3
vec3 A = inpt[4*j + (3-i)].v.position.xyz;
#else // OSD_TRANSITION_ROTATE == 0, or non-transition patch
vec3 A = inpt[4*i + j].v.position.xyz;
#endif
#endif
BUCP[i] += A * B[j];
DUCP[i] += A * D[j];
vec3 A = (s < s0) ?
inpt[k].v.position.xyz :
((s < s1) ?
inpt[k].P1.xyz :
inpt[k].P2.xyz);
BUCP[i] += A * B[j];
DUCP[i] += A * D[j];
#ifdef OSD_COMPUTE_NORMAL_DERIVATIVES
CUCP[i] += A * C[j];
CUCP[i] += A * C[j];
#endif
}
}
outpt.sharpness = sharpness;
} else {
for (int i=0; i<4; ++i) {
for (int j=0; j<4; ++j) {
vec3 A = inpt[4*i + j].v.position.xyz;
BUCP[i] += A * B[j];
DUCP[i] += A * D[j];
#ifdef OSD_COMPUTE_NORMAL_DERIVATIVES
CUCP[i] += A * C[j];
#endif
}
}
outpt.sharpness = 0;
}
#else
// ----------------------------------------------------------------
for (int i=0; i<4; ++i) {
for (int j=0; j<4; ++j) {
vec3 A = inpt[4*i + j].v.position.xyz;
BUCP[i] += A * B[j];
DUCP[i] += A * D[j];
#ifdef OSD_COMPUTE_NORMAL_DERIVATIVES
CUCP[i] += A * C[j];
#endif
}
}
#endif
// ----------------------------------------------------------------
vec3 WorldPos = vec3(0);
vec3 Tangent = vec3(0);
@ -403,7 +395,10 @@ void main()
Nu = Nu/length(n) - n * (dot(Nu,n)/pow(dot(n,n), 1.5));
Nv = Nv/length(n) - n * (dot(Nv,n)/pow(dot(n,n), 1.5));
OSD_COMPUTE_PTEX_COMPATIBLE_DERIVATIVES(OSD_TRANSITION_ROTATE);
outpt.v.tangent = Tangent;
outpt.v.bitangent = BiTangent;
outpt.v.Nu = Nu;
outpt.v.Nv = Nv;
#else
Univar4x4(UV.y, B, D);
@ -418,7 +413,8 @@ void main()
vec3 normal = normalize(cross(Tangent, BiTangent));
OSD_COMPUTE_PTEX_COMPATIBLE_TANGENT(OSD_TRANSITION_ROTATE);
outpt.v.tangent = Tangent;
outpt.v.bitangent = BiTangent;
#endif
outpt.v.position = vec4(WorldPos, 1.0f);
@ -428,15 +424,7 @@ void main()
outpt.v.patchCoord = inpt[0].v.patchCoord;
#if OSD_TRANSITION_ROTATE == 1
outpt.v.patchCoord.xy = vec2(UV.y, 1.0-UV.x);
#elif OSD_TRANSITION_ROTATE == 2
outpt.v.patchCoord.xy = vec2(1.0-UV.x, 1.0-UV.y);
#elif OSD_TRANSITION_ROTATE == 3
outpt.v.patchCoord.xy = vec2(1.0-UV.y, UV.x);
#else // OSD_TRANNSITION_ROTATE == 0, or non-transition patch
outpt.v.patchCoord.xy = vec2(UV.x, UV.y);
#endif
OSD_COMPUTE_PTEX_COORD_TESSEVAL_SHADER;

View File

@ -170,7 +170,7 @@ float TessAdaptive(vec3 p0, vec3 p1)
// length of the projected edge itself to avoid problems near silhouettes.
vec3 center = (p0 + p1) / 2.0;
float diameter = distance(p0, p1);
return max(1.0, OsdTessLevel() * GetPostProjectionSphereExtent(center, diameter));
return round(max(1.0, OsdTessLevel() * GetPostProjectionSphereExtent(center, diameter)));
}
#ifndef OSD_DISPLACEMENT_CALLBACK
@ -183,10 +183,13 @@ float TessAdaptive(vec3 p0, vec3 p1)
uniform isamplerBuffer OsdPatchParamBuffer;
#define GetPatchParam() \
(texelFetch(OsdPatchParamBuffer, GetPrimitiveID()).y)
#define GetPatchLevel() \
(texelFetch(OsdPatchParamBuffer, GetPrimitiveID()).y & 0xf)
#define GetSharpness() \
#define GetSharpness() \
(intBitsToFloat(texelFetch(OsdPatchParamBuffer, GetPrimitiveID()).z))
#define OSD_COMPUTE_PTEX_COORD_TESSCONTROL_SHADER \
@ -194,12 +197,11 @@ uniform isamplerBuffer OsdPatchParamBuffer;
ivec2 ptexIndex = texelFetch(OsdPatchParamBuffer, \
GetPrimitiveID()).xy; \
int faceID = ptexIndex.x; \
int lv = 1 << ((ptexIndex.y & 0xf) - ((ptexIndex.y >> 4) & 1)); \
int u = (ptexIndex.y >> 17) & 0x3ff; \
int v = (ptexIndex.y >> 7) & 0x3ff; \
int rotation = (ptexIndex.y >> 5) & 0x3; \
int lv = 1 << ((ptexIndex.y & 0x7) - ((ptexIndex.y >> 3) & 1)); \
int u = (ptexIndex.y >> 22) & 0x3ff; \
int v = (ptexIndex.y >> 12) & 0x3ff; \
outpt[ID].v.patchCoord.w = faceID+0.5; \
outpt[ID].v.ptexInfo = ivec4(u, v, lv, rotation); \
outpt[ID].v.ptexInfo = ivec4(u, v, lv, 0); \
}
#define OSD_COMPUTE_PTEX_COORD_TESSEVAL_SHADER \
@ -207,57 +209,8 @@ uniform isamplerBuffer OsdPatchParamBuffer;
vec2 uv = outpt.v.patchCoord.xy; \
ivec2 p = inpt[0].v.ptexInfo.xy; \
int lv = inpt[0].v.ptexInfo.z; \
int rot = inpt[0].v.ptexInfo.w; \
outpt.v.tessCoord.xy = uv; \
uv.xy = float(rot==0)*uv.xy \
+ float(rot==1)*vec2(1.0-uv.y, uv.x) \
+ float(rot==2)*vec2(1.0-uv.x, 1.0-uv.y) \
+ float(rot==3)*vec2(uv.y, 1.0-uv.x); \
outpt.v.patchCoord.xy = (uv * vec2(1.0)/lv) + vec2(p.x, p.y)/lv; \
}
#define OSD_COMPUTE_PTEX_COMPATIBLE_TANGENT(ROTATE) \
{ \
int rot = (inpt[0].v.ptexInfo.w + 4 - ROTATE)%4; \
if (rot == 1) { \
outpt.v.tangent = -BiTangent; \
outpt.v.bitangent = Tangent; \
} else if (rot == 2) { \
outpt.v.tangent = -Tangent; \
outpt.v.bitangent = -BiTangent; \
} else if (rot == 3) { \
outpt.v.tangent = BiTangent; \
outpt.v.bitangent = -Tangent; \
} else { \
outpt.v.tangent = Tangent; \
outpt.v.bitangent = BiTangent; \
} \
}
#define OSD_COMPUTE_PTEX_COMPATIBLE_DERIVATIVES(ROTATE) \
{ \
int rot = (inpt[0].v.ptexInfo.w + 4 - ROTATE)%4; \
if (rot == 1) { \
outpt.v.tangent = -BiTangent; \
outpt.v.bitangent = Tangent; \
outpt.v.Nu = -Nv; \
outpt.v.Nv = Nv; \
} else if (rot == 2) { \
outpt.v.tangent = -Tangent; \
outpt.v.bitangent = -BiTangent; \
outpt.v.Nu = -Nu; \
outpt.v.Nv = -Nv; \
} else if (rot == 3) { \
outpt.v.tangent = BiTangent; \
outpt.v.bitangent = -Tangent; \
outpt.v.Nu = Nv; \
outpt.v.Nv = -Nu; \
} else { \
outpt.v.tangent = Tangent; \
outpt.v.bitangent = BiTangent; \
outpt.v.Nu = Nu; \
outpt.v.Nv = Nv; \
} \
outpt.v.patchCoord.xy = (uv * vec2(1.0)/lv) + vec2(p.x, p.y)/lv;\
}
// ----------------------------------------------------------------------------
@ -452,3 +405,32 @@ Univar4x4(in float u, out float B[4], out float D[4], out float C[4])
C[2] = A1 - A2;
C[3] = A2;
}
// ----------------------------------------------------------------------------
vec3
EvalBezier(vec3 cp[16], vec2 uv)
{
vec3 BUCP[4] = vec3[4](vec3(0,0,0), vec3(0,0,0), vec3(0,0,0), vec3(0,0,0));
float B[4], D[4];
Univar4x4(uv.x, B, D);
for (int i=0; i<4; ++i) {
for (int j=0; j<4; ++j) {
vec3 A = cp[4*i + j];
BUCP[i] += A * B[j];
}
}
vec3 position = vec3(0);
Univar4x4(uv.y, B, D);
for (int k=0; k<4; ++k) {
position += B[k] * BUCP[k];
}
return position;
}
// ----------------------------------------------------------------------------

View File

@ -441,11 +441,13 @@ void main()
layout(quads) in;
layout(cw) in;
/* XXXdyu-patch-drawing support for frational spacing
#if defined OSD_FRACTIONAL_ODD_SPACING
layout(fractional_odd_spacing) in;
#elif defined OSD_FRACTIONAL_EVEN_SPACING
layout(fractional_even_spacing) in;
#endif
*/
in block {
GregEvalVertex v;

View File

@ -119,11 +119,13 @@ void main()
layout(quads) in;
layout(cw) in;
/* XXXdyu-patch-drawing support for frational spacing
#if defined OSD_FRACTIONAL_ODD_SPACING
layout(fractional_odd_spacing) in;
#elif defined OSD_FRACTIONAL_EVEN_SPACING
layout(fractional_even_spacing) in;
#endif
*/
in block {
ControlVertex v;

View File

@ -22,431 +22,190 @@
// language governing permissions and limitations under the Apache License.
//
#if defined(OSD_TRANSITION_PATTERN00) || defined(OSD_TRANSITION_PATTERN01) || defined(OSD_TRANSITION_PATTERN02) || defined(OSD_TRANSITION_PATTERN10) || defined(OSD_TRANSITION_PATTERN11) || defined(OSD_TRANSITION_PATTERN12) || defined(OSD_TRANSITION_PATTERN13) || defined(OSD_TRANSITION_PATTERN21) || defined(OSD_TRANSITION_PATTERN22) || defined(OSD_TRANSITION_PATTERN23)
#define OSD_TRANSITION_TRIANGLE_SUBPATCH
#else
#undef OSD_TRANSITION_TRIANGLE_SUBPATCH
#endif
//----------------------------------------------------------
// Patches.TessControlTransition
//----------------------------------------------------------
#ifdef OSD_PATCH_TESS_CONTROL_BSPLINE_SHADER
patch out vec4 tessOuterLo, tessOuterHi;
void
SetTransitionTessLevels(vec3 cp[OSD_PATCH_INPUT_SIZE], int patchLevel)
GetTessLevelsUniform(vec3 cp[16], int patchParam)
{
#ifdef OSD_ENABLE_SCREENSPACE_TESSELLATION
// These tables map the 9, 12, or 16 input control points onto the
// canonical 16 control points for a regular patch.
#if defined OSD_PATCH_BOUNDARY
const int p[16] = int[]( 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 );
#elif defined OSD_PATCH_CORNER
const int p[16] = int[]( 0, 1, 2, 2, 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8 );
#else
const int p[16] = int[]( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 );
#endif
float tessAmount = GetTessLevel(GetPatchLevel());
#if OSD_TRANSITION_ROTATE == 0
const int r[16] = int[]( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 );
#elif OSD_TRANSITION_ROTATE == 1
const int r[16] = int[]( 12, 8, 4, 0, 13, 9, 5, 1, 14, 10, 6, 2, 15, 11, 7, 3 );
#elif OSD_TRANSITION_ROTATE == 2
const int r[16] = int[]( 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 );
#elif OSD_TRANSITION_ROTATE == 3
const int r[16] = int[]( 3, 7, 11, 15, 2, 6, 10, 14, 1, 5, 9, 13, 0, 4, 8, 12 );
#endif
tessOuterLo = vec4(tessAmount);
tessOuterHi = vec4(0);
}
// Expand and rotate control points using remapping tables above
vec3 pv0 = cp[p[r[0]]];
vec3 pv1 = cp[p[r[1]]];
vec3 pv2 = cp[p[r[2]]];
vec3 pv3 = cp[p[r[3]]];
//
// Organization of B-spline and Bezier control points.
//
// Each patch is defined by 16 control points (labeled 0-15).
//
// The patch will be evaluated across the domain from (0,0) at
// the lower-left to (1,1) at the upper-right. When computing
// adaptive tessellation metrics, we consider refined vertex-vertex
// and edge-vertex points along the transition edges of the patch
// (labeled vv* and ev* respectively).
//
// The two segments of each transition edge are labeled Lo and Hi,
// with the Lo segment occuring before the Hi segment along the
// transition edge's domain parameterization. These Lo and Hi segment
// tessellation levels determine how domain evaluation coordinates
// are remapped along transition edges. The Hi segment value will
// be zero for a non-transition edge.
//
// (0,1) (1,1)
//
// vv3 ev23 vv2
// | Lo3 | Hi3 |
// --O-----------O-----+-----O-----------O--
// | 12 | 13 14 | 15 |
// | | | |
// | | | |
// Hi0 | | | | Hi2
// | | | |
// O-----------O-----------O-----------O
// | 8 | 9 10 | 11 |
// | | | |
// ev03 --+ | | +-- ev12
// | | | |
// | 4 | 5 6 | 7 |
// O-----------O-----------O-----------O
// | | | |
// Lo0 | | | | Lo2
// | | | |
// | | | |
// | 0 | 1 2 | 3 |
// --O-----------O-----+-----O-----------O--
// | Lo1 | Hi1 |
// vv0 ev01 vv1
//
// (0,0) (1,0)
//
vec3 pv4 = cp[p[r[4]]];
vec3 pv5 = cp[p[r[5]]];
vec3 pv6 = cp[p[r[6]]];
vec3 pv7 = cp[p[r[7]]];
vec3 pv8 = cp[p[r[8]]];
vec3 pv9 = cp[p[r[9]]];
vec3 pv10 = cp[p[r[10]]];
vec3 pv11 = cp[p[r[11]]];
vec3 pv12 = cp[p[r[12]]];
vec3 pv13 = cp[p[r[13]]];
vec3 pv14 = cp[p[r[14]]];
vec3 pv15 = cp[p[r[15]]];
// Each edge of a transition patch is adjacent to one or two
// patches at the next refined level of subdivision.
// Compute the corresponding vertex-vertex and edge-vertex refined
// points along the edges of the patch using Catmull-Clark subdivision
// stencil weights.
void
GetTessLevelsRefinedPoints(vec3 cp[16], int patchParam)
{
// Each edge of a transition patch is adjacent to one or two patches
// at the next refined level of subdivision. We compute the corresponding
// vertex-vertex and edge-vertex refined points along the edges of the
// patch using Catmull-Clark subdivision stencil weights.
// For simplicity, we let the optimizer discard unused computation.
vec3 vv0 = (pv0 + pv2 + pv8 + pv10) * 0.015625 +
(pv1 + pv4 + pv6 + pv9) * 0.09375 + pv5 * 0.5625;
vec3 ev01 = (pv1 + pv2 + pv9 + pv10) * 0.0625 + (pv5 + pv6) * 0.375;
vec3 vv1 = (pv1 + pv3 + pv9 + pv11) * 0.015625 +
(pv2 + pv5 + pv7 + pv10) * 0.09375 + pv6 * 0.5625;
vec3 ev12 = (pv5 + pv7 + pv9 + pv11) * 0.0625 + (pv6 + pv10) * 0.375;
vec3 vv0 = (cp[0] + cp[2] + cp[8] + cp[10]) * 0.015625 +
(cp[1] + cp[4] + cp[6] + cp[9]) * 0.09375 + cp[5] * 0.5625;
vec3 ev01 = (cp[1] + cp[2] + cp[9] + cp[10]) * 0.0625 +
(cp[5] + cp[6]) * 0.375;
vec3 vv2 = (pv5 + pv7 + pv13 + pv15) * 0.015625 +
(pv6 + pv9 + pv11 + pv14) * 0.09375 + pv10 * 0.5625;
vec3 ev23 = (pv5 + pv6 + pv13 + pv14) * 0.0625 + (pv9 + pv10) * 0.375;
vec3 vv1 = (cp[1] + cp[3] + cp[9] + cp[11]) * 0.015625 +
(cp[2] + cp[5] + cp[7] + cp[10]) * 0.09375 + cp[6] * 0.5625;
vec3 ev12 = (cp[5] + cp[7] + cp[9] + cp[11]) * 0.0625 +
(cp[6] + cp[10]) * 0.375;
vec3 vv3 = (pv4 + pv6 + pv12 + pv14) * 0.015625 +
(pv5 + pv8 + pv10 + pv13) * 0.09375 + pv9 * 0.5625;
vec3 ev30 = (pv4 + pv6 + pv8 + pv10) * 0.0625 + (pv5 + pv9) * 0.375;
vec3 vv2 = (cp[5] + cp[7] + cp[13] + cp[15]) * 0.015625 +
(cp[6] + cp[9] + cp[11] + cp[14]) * 0.09375 + cp[10] * 0.5625;
vec3 ev23 = (cp[5] + cp[6] + cp[13] + cp[14]) * 0.0625 +
(cp[9] + cp[10]) * 0.375;
// The vertices along boundaries and at corners are refined specially.
#if defined OSD_PATCH_BOUNDARY
#if OSD_TRANSITION_ROTATE == 0
vv0 = (pv4 + pv6) * 0.125 + pv5 * 0.75;
vv1 = (pv5 + pv7) * 0.125 + pv6 * 0.75;
#elif OSD_TRANSITION_ROTATE == 1
vv1 = (pv2 + pv10) * 0.125 + pv6 * 0.75;
vv2 = (pv6 + pv14) * 0.125 + pv10 * 0.75;
#elif OSD_TRANSITION_ROTATE == 2
vv2 = (pv9 + pv11) * 0.125 + pv10 * 0.75;
vv3 = (pv8 + pv10) * 0.125 + pv9 * 0.75;
#elif OSD_TRANSITION_ROTATE == 3
vv3 = (pv5 + pv13) * 0.125 + pv9 * 0.75;
vv0 = (pv1 + pv9) * 0.125 + pv5 * 0.75;
#endif
#elif defined OSD_PATCH_CORNER
#if OSD_TRANSITION_ROTATE == 0
vv0 = (pv4 + pv6) * 0.125 + pv5 * 0.75;
vv1 = pv6;
vv2 = (pv6 + pv14) * 0.125 + pv10 * 0.75;
#elif OSD_TRANSITION_ROTATE == 1
vv1 = (pv2 + pv10) * 0.125 + pv6 * 0.75;
vv2 = pv10;
vv3 = (pv8 + pv10) * 0.125 + pv9 * 0.75;
#elif OSD_TRANSITION_ROTATE == 2
vv2 = (pv9 + pv11) * 0.125 + pv10 * 0.75;
vv3 = pv9;
vv0 = (pv1 + pv9) * 0.125 + pv5 * 0.75;
#elif OSD_TRANSITION_ROTATE == 3
vv3 = (pv5 + pv13) * 0.125 + pv9 * 0.75;
vv0 = pv5;
vv1 = (pv5 + pv7) * 0.125 + pv6 * 0.75;
#endif
#elif defined OSD_PATCH_SINGLE_CREASE
// apply smooth, sharp or fractional-semisharp (linear interpolate) rules
float weight = min(1, GetSharpness());
vec3 vv3 = (cp[4] + cp[6] + cp[12] + cp[14]) * 0.015625 +
(cp[5] + cp[8] + cp[10] + cp[13]) * 0.09375 + cp[9] * 0.5625;
vec3 ev03 = (cp[4] + cp[6] + cp[8] + cp[10]) * 0.0625 +
(cp[5] + cp[9]) * 0.375;
// XXX: current rotation of single-crease patch is inconsistent
// to boundary patch. should be fixed.
#if OSD_TRANSITION_ROTATE == 2
vv0 = mix(vv0, (pv4 + pv6) * 0.125 + pv5 * 0.75, weight);
vv1 = mix(vv1, (pv5 + pv7) * 0.125 + pv6 * 0.75, weight);
#elif OSD_TRANSITION_ROTATE == 3
vv1 = mix(vv1, (pv2 + pv10) * 0.125 + pv6 * 0.75, weight);
vv2 = mix(vv2, (pv6 + pv14) * 0.125 + pv10 * 0.75, weight);
#elif OSD_TRANSITION_ROTATE == 0
vv2 = mix(vv2, (pv9 + pv11) * 0.125 + pv10 * 0.75, weight);
vv3 = mix(vv3, (pv8 + pv10) * 0.125 + pv9 * 0.75, weight);
#elif OSD_TRANSITION_ROTATE == 1
vv3 = mix(vv3, (pv5 + pv13) * 0.125 + pv9 * 0.75, weight);
vv0 = mix(vv0, (pv1 + pv9) * 0.125 + pv5 * 0.75, weight);
tessOuterLo = vec4(1);
tessOuterHi = vec4(0);
if (((patchParam >> 11) & 1) != 0) {
tessOuterLo[0] = TessAdaptive(vv0, ev03);
tessOuterHi[0] = TessAdaptive(vv3, ev03);
} else {
tessOuterLo[0] = TessAdaptive(cp[5], cp[9]);
}
if (((patchParam >> 8) & 1) != 0) {
tessOuterLo[1] = TessAdaptive(vv0, ev01);
tessOuterHi[1] = TessAdaptive(vv1, ev01);
} else {
tessOuterLo[1] = TessAdaptive(cp[5], cp[6]);
}
if (((patchParam >> 9) & 1) != 0) {
tessOuterLo[2] = TessAdaptive(vv1, ev12);
tessOuterHi[2] = TessAdaptive(vv2, ev12);
} else {
tessOuterLo[2] = TessAdaptive(cp[6], cp[10]);
}
if (((patchParam >> 10) & 1) != 0) {
tessOuterLo[3] = TessAdaptive(vv3, ev23);
tessOuterHi[3] = TessAdaptive(vv2, ev23);
} else {
tessOuterLo[3] = TessAdaptive(cp[9], cp[10]);
}
}
void
GetTessLevelsLimitPoints(vec3 cpBezier[16], int patchParam)
{
// Each edge of a transition patch is adjacent to one or two patches
// at the next refined level of subdivision. When the patch control
// points have been converted to the Bezier basis, the control points
// at the four corners are on the limit surface (since a Bezier patch
// interpolates its corner control points). We can compute an adaptive
// tessellation level for transition edges on the limit surface by
// evaluating a limit position at the mid point of each transition edge.
tessOuterLo = vec4(1);
tessOuterHi = vec4(0);
if (((patchParam >> 11) & 1) != 0) {
vec3 ev03 = EvalBezier(cpBezier, vec2(0.0, 0.5));
tessOuterLo[0] = TessAdaptive(cpBezier[0], ev03);
tessOuterHi[0] = TessAdaptive(cpBezier[12], ev03);
} else {
tessOuterLo[0] = TessAdaptive(cpBezier[0], cpBezier[12]);
}
if (((patchParam >> 8) & 1) != 0) {
vec3 ev01 = EvalBezier(cpBezier, vec2(0.5, 0.0));
tessOuterLo[1] = TessAdaptive(cpBezier[0], ev01);
tessOuterHi[1] = TessAdaptive(cpBezier[3], ev01);
} else {
tessOuterLo[1] = TessAdaptive(cpBezier[0], cpBezier[3]);
}
if (((patchParam >> 9) & 1) != 0) {
vec3 ev12 = EvalBezier(cpBezier, vec2(1.0, 0.5));
tessOuterLo[2] = TessAdaptive(cpBezier[3], ev12);
tessOuterHi[2] = TessAdaptive(cpBezier[15], ev12);
} else {
tessOuterLo[2] = TessAdaptive(cpBezier[3], cpBezier[15]);
}
if (((patchParam >> 10) & 1) != 0) {
vec3 ev23 = EvalBezier(cpBezier, vec2(0.5, 1.0));
tessOuterLo[3] = TessAdaptive(cpBezier[12], ev23);
tessOuterHi[3] = TessAdaptive(cpBezier[15], ev23);
} else {
tessOuterLo[3] = TessAdaptive(cpBezier[12], cpBezier[15]);
}
}
void
GetTransitionTessLevels(vec3 cp[16], int patchParam,
inout vec4 outerLevel, inout vec2 innerLevel)
{
#if defined OSD_ENABLE_SCREENSPACE_TESSELLATION
GetTessLevelsLimitPoints(cp, patchParam);
#elif defined OSD_ENABLE_SCREENSPACE_TESSELLATION_REFINED
GetTessLevelsRefinedPoints(cp, patchParam);
#else
GetTessLevelsUniform(cp, patchParam);
#endif
#endif
// Outer levels are the sum of the Lo and Hi segments where the Hi
// segments will have a length of zero for non-transition edges.
outerLevel = tessOuterLo + tessOuterHi;
#ifdef OSD_TRANSITION_PATTERN00
gl_TessLevelOuter[0] = TessAdaptive(ev01, pv9) * 0.5;
gl_TessLevelOuter[1] = TessAdaptive(ev01, pv10) * 0.5;
gl_TessLevelOuter[2] = TessAdaptive(pv9, pv10);
gl_TessLevelInner[0] =
(gl_TessLevelOuter[0] + gl_TessLevelOuter[1] + gl_TessLevelOuter[2]) * 0.5;
#endif
#ifdef OSD_TRANSITION_PATTERN01
gl_TessLevelOuter[0] = TessAdaptive(ev01, vv1);
gl_TessLevelOuter[1] = TessAdaptive(pv6, pv10);
gl_TessLevelOuter[2] = TessAdaptive(ev01, pv10) * 0.5;
gl_TessLevelInner[0] =
(gl_TessLevelOuter[0] + gl_TessLevelOuter[1] + gl_TessLevelOuter[2]) * 0.25;
#endif
#ifdef OSD_TRANSITION_PATTERN02
gl_TessLevelOuter[0] = TessAdaptive(ev01, vv0);
gl_TessLevelOuter[1] = TessAdaptive(ev01, pv9) * 0.5;
gl_TessLevelOuter[2] = TessAdaptive(pv5, pv9);
gl_TessLevelInner[0] =
(gl_TessLevelOuter[0] + gl_TessLevelOuter[1] + gl_TessLevelOuter[2]) * 0.25;
#endif
#ifdef OSD_TRANSITION_PATTERN10
gl_TessLevelOuter[0] = TessAdaptive(pv6, pv10);
gl_TessLevelOuter[1] = TessAdaptive(ev01, pv10);
gl_TessLevelOuter[2] = TessAdaptive(ev01, vv1);
gl_TessLevelInner[0] = (gl_TessLevelOuter[0] + gl_TessLevelOuter[1]) * 0.25;
#endif
#ifdef OSD_TRANSITION_PATTERN11
gl_TessLevelOuter[0] = TessAdaptive(pv9, pv10);
gl_TessLevelOuter[1] = TessAdaptive(ev30, vv3);
gl_TessLevelOuter[2] = TessAdaptive(ev30, pv10);
gl_TessLevelInner[0] = (gl_TessLevelOuter[0] + gl_TessLevelOuter[2]) * 0.25;
#endif
#ifdef OSD_TRANSITION_PATTERN12
gl_TessLevelOuter[0] = TessAdaptive(ev30, vv0);
gl_TessLevelOuter[1] = TessAdaptive(ev01, vv0);
gl_TessLevelOuter[2] = TessAdaptive(ev01, ev30);
gl_TessLevelInner[0] =
(gl_TessLevelOuter[0] + gl_TessLevelOuter[1] + gl_TessLevelOuter[2]) * 0.25;
#endif
#ifdef OSD_TRANSITION_PATTERN13
gl_TessLevelOuter[0] = TessAdaptive(ev01, pv10);
gl_TessLevelOuter[1] = TessAdaptive(ev30, pv10);
gl_TessLevelOuter[2] = TessAdaptive(ev01, ev30);
gl_TessLevelInner[0] =
(gl_TessLevelOuter[0] + gl_TessLevelOuter[1] + gl_TessLevelOuter[2]) * 0.25;
#endif
#ifdef OSD_TRANSITION_PATTERN20
gl_TessLevelOuter[0] = TessAdaptive(pv5, pv6);
gl_TessLevelOuter[1] = TessAdaptive(ev12, vv1);
gl_TessLevelOuter[2] = TessAdaptive(ev12, ev30);
gl_TessLevelOuter[3] = TessAdaptive(ev30, vv0);
gl_TessLevelInner[0] = max(gl_TessLevelOuter[1], gl_TessLevelOuter[3]);
gl_TessLevelInner[1] = max(gl_TessLevelOuter[0], gl_TessLevelOuter[2]);
#endif
#ifdef OSD_TRANSITION_PATTERN21
gl_TessLevelOuter[0] = TessAdaptive(ev23, ev30) * 0.5;
gl_TessLevelOuter[1] = TessAdaptive(ev23, vv3);
gl_TessLevelOuter[2] = TessAdaptive(ev30, vv3);
gl_TessLevelInner[0] = (gl_TessLevelOuter[1] + gl_TessLevelOuter[2]) * 0.5;
#endif
#ifdef OSD_TRANSITION_PATTERN22
gl_TessLevelOuter[0] = TessAdaptive(ev12, vv2);
gl_TessLevelOuter[1] = TessAdaptive(ev23, vv2);
gl_TessLevelOuter[2] = TessAdaptive(ev12, ev23) * 0.5;
gl_TessLevelInner[0] = (gl_TessLevelOuter[0] + gl_TessLevelOuter[1]) * 0.5;
#endif
#ifdef OSD_TRANSITION_PATTERN23
gl_TessLevelOuter[0] = TessAdaptive(ev12, ev30);
gl_TessLevelOuter[1] = TessAdaptive(ev12, ev23) * 0.5;
gl_TessLevelOuter[2] = TessAdaptive(ev23, ev30) * 0.5;
gl_TessLevelInner[0] =
(gl_TessLevelOuter[0] + gl_TessLevelOuter[1] + gl_TessLevelOuter[2]) * 0.5;
#endif
#ifdef OSD_TRANSITION_PATTERN30
gl_TessLevelOuter[0] = TessAdaptive(ev30, ev12) * 0.5;
gl_TessLevelOuter[1] = TessAdaptive(ev30, vv0);
gl_TessLevelOuter[2] = TessAdaptive(ev01, vv0);
gl_TessLevelOuter[3] = TessAdaptive(ev01, ev23) * 0.5;
gl_TessLevelInner[0] = max(gl_TessLevelOuter[1], gl_TessLevelOuter[3]);
gl_TessLevelInner[1] = max(gl_TessLevelOuter[0], gl_TessLevelOuter[2]);
#endif
#ifdef OSD_TRANSITION_PATTERN31
gl_TessLevelOuter[0] = TessAdaptive(ev01, ev23) * 0.5;
gl_TessLevelOuter[1] = TessAdaptive(ev23, vv3);
gl_TessLevelOuter[2] = TessAdaptive(ev30, vv3);
gl_TessLevelOuter[3] = TessAdaptive(ev30, ev12) * 0.5;
gl_TessLevelInner[0] = max(gl_TessLevelOuter[1], gl_TessLevelOuter[3]);
gl_TessLevelInner[1] = max(gl_TessLevelOuter[0], gl_TessLevelOuter[2]);
#endif
#ifdef OSD_TRANSITION_PATTERN32
gl_TessLevelOuter[0] = TessAdaptive(ev23, ev01) * 0.5;
gl_TessLevelOuter[1] = TessAdaptive(ev01, vv1);
gl_TessLevelOuter[2] = TessAdaptive(ev12, vv1);
gl_TessLevelOuter[3] = TessAdaptive(ev12, ev30) * 0.5;
gl_TessLevelInner[0] = max(gl_TessLevelOuter[1], gl_TessLevelOuter[3]);
gl_TessLevelInner[1] = max(gl_TessLevelOuter[0], gl_TessLevelOuter[2]);
#endif
#ifdef OSD_TRANSITION_PATTERN33
gl_TessLevelOuter[0] = TessAdaptive(ev12, ev30) * 0.5;
gl_TessLevelOuter[1] = TessAdaptive(ev12, vv2);
gl_TessLevelOuter[2] = TessAdaptive(ev23, vv2);
gl_TessLevelOuter[3] = TessAdaptive(ev01, ev23) * 0.5;
gl_TessLevelInner[0] = max(gl_TessLevelOuter[1], gl_TessLevelOuter[3]);
gl_TessLevelInner[1] = max(gl_TessLevelOuter[0], gl_TessLevelOuter[2]);
#endif
#ifdef OSD_TRANSITION_PATTERN40
gl_TessLevelOuter[0] = TessAdaptive(ev01, vv0);
gl_TessLevelOuter[1] = TessAdaptive(ev01, ev23);
gl_TessLevelOuter[2] = TessAdaptive(ev23, vv3);
gl_TessLevelOuter[3] = TessAdaptive(pv5, pv9);
gl_TessLevelInner[0] = max(gl_TessLevelOuter[1], gl_TessLevelOuter[3]);
gl_TessLevelInner[1] = max(gl_TessLevelOuter[0], gl_TessLevelOuter[2]);
#endif
#ifdef OSD_TRANSITION_PATTERN41
gl_TessLevelOuter[0] = TessAdaptive(ev01, vv1);
gl_TessLevelOuter[1] = TessAdaptive(pv6, pv10);
gl_TessLevelOuter[2] = TessAdaptive(ev23, vv2);
gl_TessLevelOuter[3] = TessAdaptive(ev01, ev23);
gl_TessLevelInner[0] = max(gl_TessLevelOuter[1], gl_TessLevelOuter[3]);
gl_TessLevelInner[1] = max(gl_TessLevelOuter[0], gl_TessLevelOuter[2]);
#endif
#else // OSD_ENABLE_SCREENSPACE_TESSELLATION
float TessAmount = GetTessLevel(patchLevel);
#ifdef OSD_TRANSITION_PATTERN00
float side = sqrt(1.25)*TessAmount;
gl_TessLevelOuter[0] = side;
gl_TessLevelOuter[1] = side;
gl_TessLevelOuter[2] = TessAmount;
gl_TessLevelInner[0] = TessAmount;
#endif
#ifdef OSD_TRANSITION_PATTERN01
float side = sqrt(1.25)*TessAmount;
gl_TessLevelOuter[0] = TessAmount/2.0;
gl_TessLevelOuter[1] = TessAmount;
gl_TessLevelOuter[2] = side;
gl_TessLevelInner[0] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN02
float side = sqrt(1.25)*TessAmount;
gl_TessLevelOuter[0] = TessAmount/2.0;
gl_TessLevelOuter[1] = side;
gl_TessLevelOuter[2] = TessAmount;
gl_TessLevelInner[0] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN10
float side = sqrt(1.25) * TessAmount;
gl_TessLevelOuter[0] = TessAmount;
gl_TessLevelOuter[1] = side;
gl_TessLevelOuter[2] = TessAmount/2.0;
gl_TessLevelInner[0] = TessAmount/2;
#endif
#ifdef OSD_TRANSITION_PATTERN11
float side = sqrt(1.25) * TessAmount;
gl_TessLevelOuter[0] = TessAmount;
gl_TessLevelOuter[1] = TessAmount/2.0;
gl_TessLevelOuter[2] = side;
gl_TessLevelInner[0] = TessAmount/2;
#endif
#ifdef OSD_TRANSITION_PATTERN12
float side = sqrt(0.125) * TessAmount;
gl_TessLevelOuter[0] = TessAmount/2.0;
gl_TessLevelOuter[1] = TessAmount/2.0;
gl_TessLevelOuter[2] = side;
gl_TessLevelInner[0] = TessAmount/2;
#endif
#ifdef OSD_TRANSITION_PATTERN13
float side1 = sqrt(1.25) * TessAmount;
float side2 = sqrt(0.125) * TessAmount;
gl_TessLevelOuter[0] = side1;
gl_TessLevelOuter[1] = side1;
gl_TessLevelOuter[2] = side2;
gl_TessLevelInner[0] = TessAmount/2.0*1.414;
#endif
#ifdef OSD_TRANSITION_PATTERN20
gl_TessLevelOuter[0] = TessAmount;
gl_TessLevelOuter[1] = TessAmount/2.0;
gl_TessLevelOuter[2] = TessAmount;
gl_TessLevelOuter[3] = TessAmount/2.0;
gl_TessLevelInner[0] = TessAmount/2.0;
gl_TessLevelInner[1] = TessAmount;
#endif
#ifdef OSD_TRANSITION_PATTERN21
float side = sqrt(0.125) * TessAmount;
gl_TessLevelOuter[0] = side;
gl_TessLevelOuter[1] = TessAmount/2.0;
gl_TessLevelOuter[2] = TessAmount/2.0;
gl_TessLevelInner[0] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN22
float side = sqrt(0.125) * TessAmount;
gl_TessLevelOuter[0] = TessAmount/2.0;
gl_TessLevelOuter[1] = TessAmount/2.0;
gl_TessLevelOuter[2] = side;
gl_TessLevelInner[0] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN23
float side = sqrt(0.125) * TessAmount;
gl_TessLevelOuter[0] = TessAmount;
gl_TessLevelOuter[1] = side;
gl_TessLevelOuter[2] = side;
gl_TessLevelInner[0] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN30
gl_TessLevelOuter[0] = gl_TessLevelOuter[1] =
gl_TessLevelOuter[2] = gl_TessLevelOuter[3] = TessAmount/2.0;
gl_TessLevelInner[0] = gl_TessLevelInner[1] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN31
gl_TessLevelOuter[0] = gl_TessLevelOuter[1] =
gl_TessLevelOuter[2] = gl_TessLevelOuter[3] = TessAmount/2.0;
gl_TessLevelInner[0] = gl_TessLevelInner[1] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN32
gl_TessLevelOuter[0] = gl_TessLevelOuter[1] =
gl_TessLevelOuter[2] = gl_TessLevelOuter[3] = TessAmount/2.0;
gl_TessLevelInner[0] = gl_TessLevelInner[1] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN33
gl_TessLevelOuter[0] = gl_TessLevelOuter[1] =
gl_TessLevelOuter[2] = gl_TessLevelOuter[3] = TessAmount/2.0;
gl_TessLevelInner[0] = gl_TessLevelInner[1] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN40
gl_TessLevelOuter[0] = TessAmount/2.0;
gl_TessLevelOuter[1] = TessAmount;
gl_TessLevelOuter[2] = TessAmount/2.0;
gl_TessLevelOuter[3] = TessAmount;
gl_TessLevelInner[0] = TessAmount;
gl_TessLevelInner[1] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN41
gl_TessLevelOuter[0] = TessAmount/2.0;
gl_TessLevelOuter[1] = TessAmount;
gl_TessLevelOuter[2] = TessAmount/2.0;
gl_TessLevelOuter[3] = TessAmount;
gl_TessLevelInner[0] = TessAmount;
gl_TessLevelInner[1] = TessAmount/2.0;
#endif
#endif // OSD_ENABLE_SCREENSPACE_TESSELLATION
// Inner levels are the average the corresponding outer levels.
innerLevel[0] = (outerLevel[1] + outerLevel[3]) * 0.5;
innerLevel[1] = (outerLevel[0] + outerLevel[2]) * 0.5;
}
#endif
@ -456,142 +215,36 @@ SetTransitionTessLevels(vec3 cp[OSD_PATCH_INPUT_SIZE], int patchLevel)
//----------------------------------------------------------
#ifdef OSD_PATCH_TESS_EVAL_BSPLINE_SHADER
vec2
GetTransitionSubpatchUV()
patch in vec4 tessOuterLo, tessOuterHi;
float
GetTransitionSplit(float t, float n0, float n1)
{
#ifdef OSD_TRANSITION_TRIANGLE_SUBPATCH
vec3 uvw = gl_TessCoord.xyz;
#else
vec2 uv = gl_TessCoord.xy;
#endif
vec2 UV = vec2(0, 0);
float ti = round(t * (n0 + n1));
// OSD_TRANSITION_PATTERN0*
// +-------------+
// | /\\ |
// | 1 / \\ 2 |
// | / \\ |
// | / \\ |
// | / 0 \\ |
// |/ \\|
// +-------------+
#ifdef OSD_TRANSITION_PATTERN00
UV.x = 1.0-uvw.y-uvw.z/2;
UV.y = 1.0-uvw.z;
#endif
#ifdef OSD_TRANSITION_PATTERN01
UV.x = 1.0-uvw.y/2;
UV.y = uvw.x;
#endif
#ifdef OSD_TRANSITION_PATTERN02
UV.x = uvw.z/2;
UV.y = uvw.x;
#endif
// OSD_TRANSITION_PATTERN1*
// +-------------+
// | 0 /\\ 2 |
// | / \\ |
// | / 3 \\ |
// | / / |
// | / / 1 |
// |/ / |
// +-------------+
#ifdef OSD_TRANSITION_PATTERN10
UV.x = 1.0-uvw.x/2.0;
UV.y = uvw.z;
#endif
#ifdef OSD_TRANSITION_PATTERN11
UV.x = uvw.y;
UV.y = 1.0-uvw.x/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN12
UV.x = uvw.x/2.0;
UV.y = uvw.y/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN13
UV.x = 1.0-uvw.x-uvw.y/2.0;
UV.y = 1.0-uvw.y-uvw.x/2.0;
#endif
// OSD_TRANSITION_PATTERN2*
// +-------------+
// | |
// | 0 |
// | |
// |-------------|
// |\\ 3 / |
// | \\ / |
// | 1 \\ / 2 |
// +-------------+
#ifdef OSD_TRANSITION_PATTERN20
UV.x = 1.0-uv.y;
UV.y = uv.x/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN21
UV.x = uvw.z/2.0;
UV.y = 1.0-uvw.y/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN22
UV.x = 1.0-uvw.x/2.0;
UV.y = 1.0-uvw.y/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN23
UV.x = 1.0-uvw.y-uvw.x/2;
UV.y = 0.5+uvw.x/2.0;
#endif
// OSD_TRANSITION_PATTERN3*
// +-------------+
// | | |
// | 1 | 0 |
// | | |
// |------|------|
// | | |
// | 3 | 2 |
// | | |
// +-------------+
#ifdef OSD_TRANSITION_PATTERN30
UV.x = uv.y/2.0;
UV.y = 0.5 - uv.x/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN31
UV.x = 0.5 - uv.x/2.0;
UV.y = 1.0 - uv.y/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN32
UV.x = 0.5 + uv.x/2.0;
UV.y = uv.y/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN33
UV.x = 1.0 - uv.y/2.0;
UV.y = 0.5 + uv.x/2.0;
#endif
// OSD_TRANSITION_PATTERN4*
// +-------------+
// | | |
// | | |
// | | |
// | 1 | 0 |
// | | |
// | | |
// | | |
// +-------------+
#ifdef OSD_TRANSITION_PATTERN40
UV.x = 0.5 - uv.y/2.0;
UV.y = uv.x;
#endif
#ifdef OSD_TRANSITION_PATTERN41
UV.x = 1.0 - uv.y/2.0;
UV.y = uv.x;
#endif
if (ti <= n0) {
return 0.5 * (ti / n0);
} else {
return 0.5 * ((ti - n0) / n1) + 0.5;
}
}
vec2
GetTransitionParameterization()
{
vec2 UV = gl_TessCoord.xy;
if (UV.x == 0 && tessOuterHi[0] > 0) {
UV.y = GetTransitionSplit(UV.y, tessOuterLo[0], tessOuterHi[0]);
} else
if (UV.y == 0 && tessOuterHi[1] > 0) {
UV.x = GetTransitionSplit(UV.x, tessOuterLo[1], tessOuterHi[1]);
} else
if (UV.x == 1 && tessOuterHi[2] > 0) {
UV.y = GetTransitionSplit(UV.y, tessOuterLo[2], tessOuterHi[2]);
} else
if (UV.y == 1 && tessOuterHi[3] > 0) {
UV.x = GetTransitionSplit(UV.x, tessOuterLo[3], tessOuterHi[3]);
}
return UV;
}

View File

@ -82,17 +82,22 @@ class GLSLTransformFeedbackComputeContext::GLStencilTables {
public:
GLStencilTables(Far::StencilTables const & stencilTables) {
_sizes = createGLTextureBuffer(stencilTables.GetSizes(), GL_R8UI);
_offsets = createGLTextureBuffer(stencilTables.GetOffsets(), GL_R32I);
_indices = createGLTextureBuffer(stencilTables.GetControlIndices(), GL_R32I);
_weights = createGLTextureBuffer(stencilTables.GetWeights(), GL_R32F);
_numStencils = stencilTables.GetNumStencils();
if (_numStencils > 0) {
_sizes = createGLTextureBuffer(stencilTables.GetSizes(), GL_R8UI);
_offsets = createGLTextureBuffer(stencilTables.GetOffsets(), GL_R32I);
_indices = createGLTextureBuffer(stencilTables.GetControlIndices(), GL_R32I);
_weights = createGLTextureBuffer(stencilTables.GetWeights(), GL_R32F);
} else {
_sizes = _offsets = _indices = _weights = 0;
}
}
~GLStencilTables() {
glDeleteTextures(1, &_sizes);
glDeleteTextures(1, &_offsets);
glDeleteTextures(1, &_weights);
glDeleteTextures(1, &_indices);
if (_sizes) glDeleteTextures(1, &_sizes);
if (_offsets) glDeleteTextures(1, &_offsets);
if (_weights) glDeleteTextures(1, &_weights);
if (_indices) glDeleteTextures(1, &_indices);
}
bool IsValid() const {
@ -115,12 +120,18 @@ public:
return _weights;
}
int GetNumStencils() const {
return _numStencils;
}
private:
GLuint _sizes,
_offsets,
_indices,
_weights;
int _numStencils;
};
// -----------------------------------------------------------------------------
@ -164,8 +175,17 @@ GLSLTransformFeedbackComputeContext::HasVaryingStencilTables() const {
return _varyingStencilTables ? _varyingStencilTables->IsValid() : false;
}
// ----------------------------------------------------------------------------
int
GLSLTransformFeedbackComputeContext::GetNumStencilsInVertexStencilTables() const {
return _vertexStencilTables ? _vertexStencilTables->GetNumStencils() : 0;
}
int
GLSLTransformFeedbackComputeContext::GetNumStencilsInVaryingStencilTables() const {
return _varyingStencilTables ? _varyingStencilTables->GetNumStencils() : 0;
}
// ----------------------------------------------------------------------------
GLuint
GLSLTransformFeedbackComputeContext::GetVertexStencilTablesSizes() const {
return _vertexStencilTables ? _vertexStencilTables->GetSizes() : 0;

View File

@ -59,7 +59,7 @@ public:
/// interpolation
///
static GLSLTransformFeedbackComputeContext * Create(Far::StencilTables const * vertexStencilTables,
Far::StencilTables const * varyingStencilTables=0);
Far::StencilTables const * varyingStencilTables=0);
/// Destructor
virtual ~GLSLTransformFeedbackComputeContext();
@ -75,6 +75,12 @@ public:
return _numControlVertices;
}
/// Returns the number of stencils in vertex stencil table
int GetNumStencilsInVertexStencilTables() const;
/// Returns the number of stencils in varying stencil table
int GetNumStencilsInVaryingStencilTables() const;
/// Returns the GL texture buffer containing vertex-stencil stencil sizes
GLuint GetVertexStencilTablesSizes() const;

View File

@ -87,7 +87,7 @@ public:
_uniformWeights(0),
_uniformStart(0),
_uniformEnd(0),
_uniformOffset(0) { }
_uniformPrimvarOffset(0) { }
~KernelBundle() {
if (_program) {
@ -95,9 +95,8 @@ public:
}
}
void UseProgram(int primvarOffset) const {
void UseProgram() const {
glUseProgram(_program);
glUniform1i(_uniformOffset, primvarOffset);
}
bool Compile(VertexBufferDescriptor const & desc) {
@ -117,7 +116,7 @@ public:
<< "#define STRIDE " << desc.stride << "\n";
std::string defineStr = defines.str();
const char *shaderSources[4] = {"#version 420\n", 0, 0, 0};
const char *shaderSources[4] = {"#version 410\n", 0, 0, 0};
shaderSources[1] = defineStr.c_str();
shaderSources[2] = shaderDefines;
@ -138,15 +137,19 @@ public:
// outVertexData[2]
// (gl_SkipComponents1)
//
// note that "primvarOffset" in shader is still needed to read
// interleaved components even if gl_SkipComponents is used.
//
char attrName[32];
for (int i = 0; i < desc.offset; ++i) {
int primvarOffset = (desc.offset % desc.stride);
for (int i = 0; i < primvarOffset; ++i) {
outputs.push_back("gl_SkipComponents1");
}
for (int i = 0; i < desc.length; ++i) {
snprintf(attrName, 32, "outVertexBuffer[%d]", i);
outputs.push_back(attrName);
}
for (int i = desc.offset + desc.length; i < desc.stride; ++i) {
for (int i = primvarOffset + desc.length; i < desc.stride; ++i) {
outputs.push_back("gl_SkipComponents1");
}
@ -178,9 +181,6 @@ public:
glDeleteShader(shader);
_subStencilKernel = glGetSubroutineIndex(
_program, GL_VERTEX_SHADER, "computeStencil");
// set uniform locations for compute kernels
_primvarBuffer = glGetUniformLocation(_program, "vertexBuffer");
@ -192,7 +192,7 @@ public:
_uniformStart = glGetUniformLocation(_program, "batchStart");
_uniformEnd = glGetUniformLocation(_program, "batchEnd");
_uniformOffset = glGetUniformLocation(_program, "primvarOffset");
_uniformPrimvarOffset = glGetUniformLocation(_program, "primvarOffset");
OSD_DEBUG_CHECK_GL_ERROR("KernelBundle::Compile");
@ -225,14 +225,16 @@ public:
// set batch range
glUniform1i(_uniformStart, start);
glUniform1i(_uniformEnd, end);
glUniform1i(_uniformOffset, offset);
glUniform1i(_uniformPrimvarOffset, offset);
int count = end - start,
stride = _desc.stride*sizeof(float);
// note: offset includes both "batching offset" and "primvar offset".
//
glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER,
0, primvarBuffer,
(start + numCVs)*stride + offset*sizeof(float),
(start + numCVs)*stride + (offset - offset%stride)*sizeof(float),
count*stride);
glBeginTransformFeedback(GL_POINTS);
@ -246,13 +248,12 @@ public:
//OSD_DEBUG_CHECK_GL_ERROR("TransformPrimvarBuffer\n");
}
void ApplyStencilTableKernel(Far::KernelBatch const &batch,
GLuint primvarBuffer, int offset, int numCVs) const {
glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &_subStencilKernel);
void ApplyStencilTableKernel(GLuint primvarBuffer,
int offset, int numCVs,
int start, int end) const {
TransformPrimvarBuffer(primvarBuffer,
offset, numCVs, batch.start, batch.end);
offset, numCVs, start, end);
}
struct Match {
@ -271,8 +272,6 @@ private:
GLuint _program;
GLuint _subStencilKernel; // stencil compute kernel GLSL subroutine
GLint _primvarBuffer;
GLint _uniformSizes, // uniform paramaeters for kernels
@ -283,7 +282,7 @@ private:
_uniformStart, // batch
_uniformEnd,
_uniformOffset; // GL primvar buffer descriptor
_uniformPrimvarOffset;
VertexBufferDescriptor _desc; // primvar buffer descriptor
};
@ -294,7 +293,7 @@ GLSLTransformFeedbackComputeController::bindBufferAndProgram(
GLuint & feedbackTexture) {
glEnable(GL_RASTERIZER_DISCARD);
_currentBindState.kernelBundle->UseProgram(/*primvarOffset*/0);
_currentBindState.kernelBundle->UseProgram();
if (not feedbackTexture) {
glGenTextures(1, &feedbackTexture);
@ -385,14 +384,18 @@ GLSLTransformFeedbackComputeController::getKernel(
void
GLSLTransformFeedbackComputeController::ApplyStencilTableKernel(
Far::KernelBatch const &batch,
GLSLTransformFeedbackComputeContext const *context) const {
GLSLTransformFeedbackComputeContext const *context, int numStencils) const {
assert(context);
_currentBindState.kernelBundle->ApplyStencilTableKernel(batch,
int start = 0;
int end = numStencils;
_currentBindState.kernelBundle->ApplyStencilTableKernel(
_currentBindState.buffer, _currentBindState.desc.offset,
context->GetNumControlVertices());
context->GetNumControlVertices(),
start,
end);
}

View File

@ -27,11 +27,11 @@
#include "../version.h"
#include "../far/kernelBatchDispatcher.h"
#include "../osd/glslTransformFeedbackComputeContext.h"
#include "../osd/vertexDescriptor.h"
#include <vector>
#include <cassert>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
@ -67,9 +67,6 @@ public:
/// @param context The GLSLTransformFeedbackComputeContext to apply
/// refinement operations to
///
/// @param batches Vector of batches of vertices organized by operative
/// kernel
///
/// @param vertexBuffer Vertex-interpolated data buffer
///
/// @param vertexDesc The descriptor of vertex elements to be refined.
@ -84,21 +81,19 @@ public:
///
template<class VERTEX_BUFFER, class VARYING_BUFFER>
void Compute( GLSLTransformFeedbackComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER * vertexBuffer,
VARYING_BUFFER * varyingBuffer,
VertexBufferDescriptor const * vertexDesc=NULL,
VertexBufferDescriptor const * varyingDesc=NULL ){
if (batches.empty()) return;
if (vertexBuffer) {
bind(vertexBuffer, vertexDesc, _vertexTexture);
bindContextStencilTables(context, false);
Far::KernelBatchDispatcher::Apply(this, context, batches, /*maxlevel*/ -1);
ApplyStencilTableKernel(
context, context->GetNumStencilsInVertexStencilTables());
}
if (varyingBuffer) {
@ -107,7 +102,8 @@ public:
bindContextStencilTables(context, true);
Far::KernelBatchDispatcher::Apply(this, context, batches, /*maxlevel*/ -1);
ApplyStencilTableKernel(
context, context->GetNumStencilsInVaryingStencilTables());
}
unbind();
}
@ -117,17 +113,13 @@ public:
/// @param context The GLSLTransformFeedbackComputeContext to apply
/// refinement operations to
///
/// @param batches Vector of batches of vertices organized by operative
/// kernel
///
/// @param vertexBuffer Vertex-interpolated data buffer
///
template<class VERTEX_BUFFER>
void Compute(GLSLTransformFeedbackComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER *vertexBuffer) {
Compute<VERTEX_BUFFER>(context, batches, vertexBuffer, (VERTEX_BUFFER*)0);
Compute<VERTEX_BUFFER>(context, vertexBuffer, (VERTEX_BUFFER*)0);
}
/// Waits until all running subdivision kernels finish.
@ -135,10 +127,8 @@ public:
protected:
friend class Far::KernelBatchDispatcher;
void ApplyStencilTableKernel(Far::KernelBatch const &batch,
ComputeContext const *context) const;
void ApplyStencilTableKernel(ComputeContext const *context,
int numStencils) const;
template<class BUFFER>
void bind( BUFFER * buffer, VertexBufferDescriptor const * desc,

View File

@ -22,9 +22,6 @@
// language governing permissions and limitations under the Apache License.
//
subroutine void computeKernelType();
subroutine uniform computeKernelType computeKernel;
//------------------------------------------------------------------------------
uniform samplerBuffer vertexBuffer;
@ -81,8 +78,7 @@ void writeVertex(Vertex v) {
}
//------------------------------------------------------------------------------
subroutine(computeKernelType)
void computeStencil() {
void main() {
int current = gl_VertexID + batchStart;
@ -108,11 +104,3 @@ void computeStencil() {
}
//------------------------------------------------------------------------------
void main() {
// call subroutine
computeKernel();
}
//------------------------------------------------------------------------------

View File

@ -22,12 +22,6 @@
// language governing permissions and limitations under the Apache License.
//
#ifdef OSD_TRANSITION_TRIANGLE_SUBPATCH
#define HS_DOMAIN "tri"
#else
#define HS_DOMAIN "quad"
#endif
#if defined OSD_FRACTIONAL_ODD_SPACING
#define HS_PARTITION "fractional_odd"
#elif defined OSD_FRACTIONAL_EVEN_SPACING
@ -67,13 +61,34 @@ static float4x4 Mi = {
0.f, 0.f, 1.f, 0.f
};
// Boundary / Corner
static float4x3 B = {
1.f, 0.f, 0.f,
4.f/6.f, 2.f/6.f, 0.f,
2.f/6.f, 4.f/6.f, 0.f,
1.f/6.f, 4.f/6.f, 1.f/6.f
};
void
reflectBoundaryEdges(inout float3 cpt[16], int patchParam)
{
if (((patchParam >> 4) & 1) != 0) {
cpt[0] = 2*cpt[4] - cpt[8];
cpt[1] = 2*cpt[5] - cpt[9];
cpt[2] = 2*cpt[6] - cpt[10];
cpt[3] = 2*cpt[7] - cpt[11];
}
if (((patchParam >> 4) & 2) != 0) {
cpt[3] = 2*cpt[2] - cpt[1];
cpt[7] = 2*cpt[6] - cpt[5];
cpt[11] = 2*cpt[10] - cpt[9];
cpt[15] = 2*cpt[14] - cpt[13];
}
if (((patchParam >> 4) & 4) != 0) {
cpt[12] = 2*cpt[8] - cpt[4];
cpt[13] = 2*cpt[9] - cpt[5];
cpt[14] = 2*cpt[10] - cpt[6];
cpt[15] = 2*cpt[11] - cpt[7];
}
if (((patchParam >> 4) & 8) != 0) {
cpt[0] = 2*cpt[1] - cpt[2];
cpt[4] = 2*cpt[5] - cpt[6];
cpt[8] = 2*cpt[9] - cpt[10];
cpt[12] = 2*cpt[13] - cpt[14];
}
}
// compute single-crease patch matrix
float4x4
@ -96,62 +111,48 @@ ComputeMatrixSimplified(float sharpness)
}
#ifdef OSD_PATCH_TRANSITION
HS_CONSTANT_TRANSITION_FUNC_OUT
#else
HS_CONSTANT_FUNC_OUT
#endif
HS_CONSTANT_FUNC_OUT
HSConstFunc(
InputPatch<HullVertex, OSD_PATCH_INPUT_SIZE> patch,
OutputPatch<HullVertex, 16> bezierPatch,
uint primitiveID : SV_PrimitiveID)
{
#ifdef OSD_PATCH_TRANSITION
HS_CONSTANT_TRANSITION_FUNC_OUT output;
#else
HS_CONSTANT_FUNC_OUT output;
#endif
int patchParam = GetPatchParam(primitiveID);
int patchLevel = GetPatchLevel(primitiveID);
#ifdef OSD_TRANSITION_TRIANGLE_SUBPATCH
OSD_PATCH_CULL_TRIANGLE(OSD_PATCH_INPUT_SIZE);
#else
float3 position[16];
for (int p=0; p<16; ++p) {
position[p] = bezierPatch[p].position.xyz;
}
reflectBoundaryEdges(position, patchParam);
OSD_PATCH_CULL(OSD_PATCH_INPUT_SIZE);
#endif
#ifdef OSD_PATCH_TRANSITION
float3 cp[OSD_PATCH_INPUT_SIZE];
for(int k = 0; k < OSD_PATCH_INPUT_SIZE; ++k) cp[k] = patch[k].position.xyz;
SetTransitionTessLevels(output, cp, patchLevel, primitiveID);
#else
#if defined OSD_PATCH_BOUNDARY
const int p[4] = { 1, 2, 5, 6 };
#elif defined OSD_PATCH_CORNER
const int p[4] = { 1, 2, 4, 5 };
#else
const int p[4] = { 5, 6, 9, 10 };
#endif
float4 outerLevel = float4(0,0,0,0);
float4 innerLevel = float4(0,0,0,0);
float4 tessOuterLo = float4(0,0,0,0);
float4 tessOuterHi = float4(0,0,0,0);
GetTransitionTessLevels(position, patchParam, patchLevel,
outerLevel, innerLevel,
tessOuterLo, tessOuterHi);
#ifdef OSD_ENABLE_SCREENSPACE_TESSELLATION
output.tessLevelOuter[0] = TessAdaptive(patch[p[0]].position.xyz, patch[p[2]].position.xyz);
output.tessLevelOuter[1] = TessAdaptive(patch[p[0]].position.xyz, patch[p[1]].position.xyz);
output.tessLevelOuter[2] = TessAdaptive(patch[p[1]].position.xyz, patch[p[3]].position.xyz);
output.tessLevelOuter[3] = TessAdaptive(patch[p[2]].position.xyz, patch[p[3]].position.xyz);
output.tessLevelInner[0] = max(output.tessLevelOuter[1], output.tessLevelOuter[3]);
output.tessLevelInner[1] = max(output.tessLevelOuter[0], output.tessLevelOuter[2]);
#else
output.tessLevelInner[0] = GetTessLevel(patchLevel);
output.tessLevelInner[1] = GetTessLevel(patchLevel);
output.tessLevelOuter[0] = GetTessLevel(patchLevel);
output.tessLevelOuter[1] = GetTessLevel(patchLevel);
output.tessLevelOuter[2] = GetTessLevel(patchLevel);
output.tessLevelOuter[3] = GetTessLevel(patchLevel);
#endif
#endif
output.tessLevelOuter[0] = outerLevel[0];
output.tessLevelOuter[1] = outerLevel[1];
output.tessLevelOuter[2] = outerLevel[2];
output.tessLevelOuter[3] = outerLevel[3];
output.tessLevelInner[0] = innerLevel[0];
output.tessLevelInner[1] = innerLevel[1];
output.tessOuterLo = tessOuterLo;
output.tessOuterHi = tessOuterHi;
return output;
}
[domain(HS_DOMAIN)]
[domain("quad")]
[partitioning(HS_PARTITION)]
[outputtopology("triangle_cw")]
[outputcontrolpoints(16)]
@ -164,76 +165,61 @@ HullVertex hs_main_patches(
int i = ID%4;
int j = ID/4;
#if defined OSD_PATCH_BOUNDARY
float3 H[3];
for (int l=0; l<3; ++l) {
H[l] = float3(0,0,0);
for (int k=0; k<4; ++k) {
H[l] += Q[i][k] * patch[l*4 + k].position.xyz;
}
float3 position[16];
for (int p=0; p<16; ++p) {
position[p] = patch[p].position.xyz;
}
float3 pos = float3(0,0,0);
for (int k=0; k<3; ++k) {
pos += B[j][k]*H[k];
}
int patchParam = GetPatchParam(primitiveID);
#elif defined OSD_PATCH_CORNER
float3 H[3];
for (int l=0; l<3; ++l) {
H[l] = float3(0,0,0);
for (int k=0; k<3; ++k) {
H[l] += B[3-i][2-k] * patch[l*3 + k].position.xyz;
}
}
reflectBoundaryEdges(position, patchParam);
float3 pos = float3(0,0,0);
for (int k=0; k<3; ++k) {
pos += B[j][k]*H[k];
}
#else // not OSD_PATCH_BOUNDARY, not OSD_PATCH_CORNER
float3 H[4];
for (int l=0; l<4; ++l) {
H[l] = float3(0,0,0);
for(int k=0; k<4; ++k) {
H[l] += Q[i][k] * patch[l*4 + k].position.xyz;
H[l] += Q[i][k] * position[l*4 + k];
}
}
#if defined OSD_PATCH_SINGLE_CREASE
HullVertex output;
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
float sharpness = GetSharpness(primitiveID);
float Sf = floor(sharpness);
float Sc = ceil(sharpness);
float Sr = frac(sharpness);
float4x4 Mf = ComputeMatrixSimplified(Sf);
float4x4 Mc = ComputeMatrixSimplified(Sc);
float4x4 Mj = (1-Sr) * Mf + Sr * Mi;
float4x4 Ms = (1-Sr) * Mf + Sr * Mc;
if (sharpness > 0) {
float Sf = floor(sharpness);
float Sc = ceil(sharpness);
float Sr = frac(sharpness);
float4x4 Mf = ComputeMatrixSimplified(Sf);
float4x4 Mc = ComputeMatrixSimplified(Sc);
float4x4 Mj = (1-Sr) * Mf + Sr * Mi;
float4x4 Ms = (1-Sr) * Mf + Sr * Mc;
float3 pos = float3(0,0,0);
float3 P1 = float3(0,0,0);
float3 P2 = float3(0,0,0);
for (int k=0; k<4; ++k) {
pos += Mi[j][k]*H[k]; // 0 to 1-2^(-Sf)
P1 += Mj[j][k]*H[k]; // 1-2^(-Sf) to 1-2^(-Sc)
P2 += Ms[j][k]*H[k]; // 1-2^(-Sc) to 1
float3 pos = float3(0,0,0);
float3 P1 = float3(0,0,0);
float3 P2 = float3(0,0,0);
for (int k=0; k<4; ++k) {
pos += Mi[j][k]*H[k]; // 0 to 1-2^(-Sf)
P1 += Mj[j][k]*H[k]; // 1-2^(-Sf) to 1-2^(-Sc)
P2 += Ms[j][k]*H[k]; // 1-2^(-Sc) to 1
}
output.position = float4(pos, 1.0);
output.P1 = float4(P1, 1.0);
output.P2 = float4(P2, 1.0);
output.sharpness = sharpness;
} else {
float3 pos = float3(0,0,0);
for (int k=0; k<4; ++k){
pos += Q[j][k]*H[k];
}
output.position = float4(pos, 1.0);
output.sharpness = 0;
}
#else
float3 pos = float3(0,0,0);
for (int k=0; k<4; ++k){
pos += Q[j][k]*H[k];
}
#endif
#endif
HullVertex output;
output.position = float4(pos, 1.0);
#if defined OSD_PATCH_SINGLE_CREASE
output.P1 = float4(P1, 1.0);
output.P2 = float4(P2, 1.0);
output.sharpness = sharpness;
#endif
int patchLevel = GetPatchLevel(primitiveID);
@ -252,26 +238,14 @@ HullVertex hs_main_patches(
// Patches.DomainBSpline
//----------------------------------------------------------
[domain(HS_DOMAIN)]
[domain("quad")]
void ds_main_patches(
#ifdef OSD_PATCH_TRANSITION
in HS_CONSTANT_TRANSITION_FUNC_OUT input,
#else
in HS_CONSTANT_FUNC_OUT input,
#endif
in OutputPatch<HullVertex, 16> patch,
#ifdef OSD_TRANSITION_TRIANGLE_SUBPATCH
in float3 domainCoord : SV_DomainLocation,
#else
in float2 domainCoord : SV_DomainLocation,
#endif
out OutputVertex output )
{
#ifdef OSD_PATCH_TRANSITION
float2 UV = GetTransitionSubpatchUV(domainCoord);
#else
float2 UV = domainCoord;
#endif
float2 UV = GetTransitionParameterization(input, domainCoord);
#ifdef OSD_COMPUTE_NORMAL_DERIVATIVES
float B[4], D[4], C[4];
@ -286,52 +260,60 @@ void ds_main_patches(
Univar4x4(UV.x, B, D);
#endif
#if defined OSD_PATCH_SINGLE_CREASE
// ----------------------------------------------------------------
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
// sharpness
float sharpness = patch[0].sharpness;
float s0 = 1.0 - pow(2.0f, -floor(sharpness));
float s1 = 1.0 - pow(2.0f, -ceil(sharpness));
#endif
if (sharpness != 0) {
float s0 = 1.0 - pow(2.0f, -floor(sharpness));
float s1 = 1.0 - pow(2.0f, -ceil(sharpness));
for (int i=0; i<4; ++i) {
for (int j=0; j<4; ++j) {
#if defined OSD_PATCH_SINGLE_CREASE
#if OSD_TRANSITION_ROTATE == 1
int k = 4*(3-j) + i;
float s = 1-UV.x;
#elif OSD_TRANSITION_ROTATE == 2
int k = 4*(3-i) + (3-j);
float s = 1-UV.y;
#elif OSD_TRANSITION_ROTATE == 3
int k = 4*j + (3-i);
float s = UV.x;
#else // ROTATE=0 or non-transition
int k = 4*i + j;
float s = UV.y;
#endif
float3 A = (s < s0) ?
patch[k].position.xyz :
((s < s1) ?
patch[k].P1.xyz :
patch[k].P2.xyz);
for (int i=0; i<4; ++i) {
for (int j=0; j<4; ++j) {
int k = 4*i + j;
float s = UV.y;
#else // !SINGLE_CREASE
#if OSD_TRANSITION_ROTATE == 1
float3 A = patch[4*(3-j) + i].position.xyz;
#elif OSD_TRANSITION_ROTATE == 2
float3 A = patch[4*(3-i) + (3-j)].position.xyz;
#elif OSD_TRANSITION_ROTATE == 3
float3 A = patch[4*j + (3-i)].position.xyz;
#else // OSD_TRANSITION_ROTATE == 0, or non-transition patch
float3 A = patch[4*i + j].position.xyz;
#endif
#endif
BUCP[i] += A * B[j];
DUCP[i] += A * D[j];
float3 A = (s < s0) ?
patch[k].position.xyz :
((s < s1) ?
patch[k].P1.xyz :
patch[k].P2.xyz);
BUCP[i] += A * B[j];
DUCP[i] += A * D[j];
#ifdef OSD_COMPUTE_NORMAL_DERIVATIVES
CUCP[i] += A * C[j];
CUCP[i] += A * C[j];
#endif
}
}
output.sharpness = sharpness;
} else {
for (int i=0; i<4; ++i) {
for (int j=0; j<4; ++j) {
float3 A = patch[4*i + j].position.xyz;
BUCP[i] += A * B[j];
DUCP[i] += A * D[j];
#ifdef OSD_COMPUTE_NORMAL_DERIVATIVES
CUCP[i] += A * C[j];
#endif
}
}
output.sharpness = 0;
}
#else
// ----------------------------------------------------------------
for (int i=0; i<4; ++i) {
for (int j=0; j<4; ++j) {
float3 A = patch[4*i + j].position.xyz;
BUCP[i] += A * B[j];
DUCP[i] += A * D[j];
#ifdef OSD_COMPUTE_NORMAL_DERIVATIVES
CUCP[i] += A * C[j];
#endif
}
}
#endif
// ----------------------------------------------------------------
float3 WorldPos = float3(0,0,0);
float3 Tangent = float3(0,0,0);
@ -378,7 +360,10 @@ void ds_main_patches(
Nu = Nu/length(n) - n * (dot(Nu,n)/pow(dot(n,n), 1.5));
Nv = Nv/length(n) - n * (dot(Nv,n)/pow(dot(n,n), 1.5));
OSD_COMPUTE_PTEX_COMPATIBLE_DERIVATIVES(OSD_TRANSITION_ROTATE);
output.tangent = Tangent;
output.bitangent = BiTangent;
output.Nu = Nu;
output.Nv = Nv;
#else
Univar4x4(UV.y, B, D);
@ -393,7 +378,8 @@ void ds_main_patches(
float3 normal = normalize(cross(Tangent, BiTangent));
OSD_COMPUTE_PTEX_COMPATIBLE_TANGENT(OSD_TRANSITION_ROTATE);
output.tangent = Tangent;
output.bitangent = BiTangent;
#endif
output.position = float4(WorldPos, 1.0f);
@ -401,20 +387,13 @@ void ds_main_patches(
output.patchCoord = patch[0].patchCoord;
#if OSD_TRANSITION_ROTATE == 1
output.patchCoord.xy = float2(UV.y, 1.0-UV.x);
#elif OSD_TRANSITION_ROTATE == 2
output.patchCoord.xy = float2(1.0-UV.x, 1.0-UV.y);
#elif OSD_TRANSITION_ROTATE == 3
output.patchCoord.xy = float2(1.0-UV.y, UV.x);
#else // OSD_TRANNSITION_ROTATE == 0, or non-transition patch
output.patchCoord.xy = float2(UV.x, UV.y);
#endif
OSD_COMPUTE_PTEX_COORD_DOMAIN_SHADER;
OSD_DISPLACEMENT_CALLBACK;
output.edgeDistance = 0;
output.positionOut = mul(OsdProjectionMatrix(),
float4(output.position.xyz, 1.0f));
output.edgeDistance = 0;
}

View File

@ -26,17 +26,11 @@
// Patches.Common
//----------------------------------------------------------
#ifndef OSD_TRANSITION_ROTATE
#define OSD_TRANSITION_ROTATE 0
#endif
// XXXdyu-patch-drawing support for fractional spacing
#undef OSD_FRACTIONAL_ODD_SPACING
#undef OSD_FRACTIONAL_EVEN_SPACING
#if defined OSD_PATCH_BOUNDARY
#define OSD_PATCH_INPUT_SIZE 12
#elif defined OSD_PATCH_CORNER
#define OSD_PATCH_INPUT_SIZE 9
#else
#define OSD_PATCH_INPUT_SIZE 16
#endif
#define OSD_PATCH_INPUT_SIZE 16
#define M_PI 3.14159265359f
@ -50,7 +44,7 @@ struct HullVertex {
float4 patchCoord : PATCHCOORD; // u, v, level, faceID
int4 ptexInfo : PTEXINFO; // u offset, v offset, 2^ptexlevel, rotation
int3 clipFlag : CLIPFLAG;
#if defined OSD_PATCH_SINGLE_CREASE
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
float4 P1 : POSITION1;
float4 P2 : POSITION2;
float sharpness : BLENDWEIGHT0;
@ -69,6 +63,9 @@ struct OutputVertex {
float3 Nu : TANGENT2;
float3 Nv : TANGENT3;
#endif
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
float sharpness : BLENDWEIGHT0;
#endif
};
struct GregHullVertex {
@ -98,6 +95,8 @@ struct GregDomainVertex {
struct HS_CONSTANT_FUNC_OUT {
float tessLevelInner[2] : SV_InsideTessFactor;
float tessLevelOuter[4] : SV_TessFactor;
float4 tessOuterLo : TRANSITIONLO;
float4 tessOuterHi : TRANSITIONHI;
};
// osd shaders need following functions defined
@ -134,19 +133,22 @@ float TessAdaptive(float3 p0, float3 p1)
// length of the projected edge itself to avoid problems near silhouettes.
float3 center = (p0 + p1) / 2.0;
float diameter = distance(p0, p1);
return max(1.0, OsdTessLevel() * GetPostProjectionSphereExtent(center, diameter));
return round(max(1.0, OsdTessLevel() * GetPostProjectionSphereExtent(center, diameter)));
}
#ifndef OSD_DISPLACEMENT_CALLBACK
#define OSD_DISPLACEMENT_CALLBACK
#endif
#if defined OSD_PATCH_SINGLE_CREASE
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
Buffer<uint3> OsdPatchParamBuffer : register( t3 );
#else
Buffer<uint2> OsdPatchParamBuffer : register( t3 );
#endif
#define GetPatchParam(primitiveID) \
(OsdPatchParamBuffer[GetPrimitiveID(primitiveID)].y)
#define GetPatchLevel(primitiveID) \
(OsdPatchParamBuffer[GetPrimitiveID(primitiveID)].y & 0xf)
@ -157,12 +159,11 @@ float TessAdaptive(float3 p0, float3 p1)
{ \
int2 ptexIndex = OsdPatchParamBuffer[GetPrimitiveID(primitiveID)].xy; \
int faceID = ptexIndex.x; \
int lv = 1 << ((ptexIndex.y & 0xf) - ((ptexIndex.y >> 4) & 1)); \
int u = (ptexIndex.y >> 17) & 0x3ff; \
int v = (ptexIndex.y >> 7) & 0x3ff; \
int rotation = (ptexIndex.y >> 5) & 0x3; \
int lv = 1 << ((ptexIndex.y & 0x7) - ((ptexIndex.y >> 3) & 1)); \
int u = (ptexIndex.y >> 22) & 0x3ff; \
int v = (ptexIndex.y >> 12) & 0x3ff; \
output.patchCoord.w = faceID+0.5; \
output.ptexInfo = int4(u, v, lv, rotation); \
output.ptexInfo = int4(u, v, lv, 0); \
}
#define OSD_COMPUTE_PTEX_COORD_DOMAIN_SHADER \
@ -171,57 +172,9 @@ float TessAdaptive(float3 p0, float3 p1)
int2 p = patch[0].ptexInfo.xy; \
int lv = patch[0].ptexInfo.z; \
int rot = patch[0].ptexInfo.w; \
uv.xy = float(rot==0)*uv.xy \
+ float(rot==1)*float2(1.0-uv.y, uv.x) \
+ float(rot==2)*float2(1.0-uv.x, 1.0-uv.y) \
+ float(rot==3)*float2(uv.y, 1.0-uv.x); \
output.patchCoord.xy = (uv * float2(1.0,1.0)/lv) + float2(p.x, p.y)/lv; \
}
#define OSD_COMPUTE_PTEX_COMPATIBLE_TANGENT(ROTATE) \
{ \
int rot = (patch[0].ptexInfo.w + 4 - ROTATE)%4; \
if (rot == 1) { \
output.tangent = -BiTangent; \
output.bitangent = Tangent; \
} else if (rot == 2) { \
output.tangent = -Tangent; \
output.bitangent = -BiTangent; \
} else if (rot == 3) { \
output.tangent = BiTangent; \
output.bitangent = -Tangent; \
} else { \
output.tangent = Tangent; \
output.bitangent = BiTangent; \
} \
}
#define OSD_COMPUTE_PTEX_COMPATIBLE_DERIVATIVES(ROTATE) \
{ \
int rot = (patch[0].ptexInfo.w + 4 - ROTATE)%4; \
if (rot == 1) { \
output.tangent = -BiTangent; \
output.bitangent = Tangent; \
output.Nu = -Nv; \
output.Nv = Nv; \
} else if (rot == 2) { \
output.tangent = -Tangent; \
output.bitangent = -BiTangent; \
output.Nu = -Nu; \
output.Nv = -Nv; \
} else if (rot == 3) { \
output.tangent = BiTangent; \
output.bitangent = -Tangent; \
output.Nu = Nv; \
output.Nv = -Nu; \
} else { \
output.tangent = Tangent; \
output.bitangent = BiTangent; \
output.Nu = Nu; \
output.Nv = Nv; \
} \
}
#ifdef OSD_ENABLE_PATCH_CULL
@ -318,3 +271,32 @@ Univar4x4(in float u, out float B[4], out float D[4], out float C[4])
C[2] = A1 - A2;
C[3] = A2;
}
// ----------------------------------------------------------------------------
float3
EvalBezier(float3 cp[16], float2 uv)
{
float3 BUCP[4] = { float3(0,0,0), float3(0,0,0), float3(0,0,0), float3(0,0,0) };
float B[4], D[4];
Univar4x4(uv.x, B, D);
for (int i=0; i<4; ++i) {
for (int j=0; j<4; ++j) {
float3 A = cp[4*i + j];
BUCP[i] += A * B[j];
}
}
float3 position = float3(0,0,0);
Univar4x4(uv.y, B, D);
for (int k=0; k<4; ++k) {
position += B[k] * BUCP[k];
}
return position;
}
// ----------------------------------------------------------------------------

View File

@ -22,600 +22,227 @@
// language governing permissions and limitations under the Apache License.
//
#if defined(OSD_TRANSITION_PATTERN00) || defined(OSD_TRANSITION_PATTERN01) || defined(OSD_TRANSITION_PATTERN02) || defined(OSD_TRANSITION_PATTERN10) || defined(OSD_TRANSITION_PATTERN11) || defined(OSD_TRANSITION_PATTERN12) || defined(OSD_TRANSITION_PATTERN13) || defined(OSD_TRANSITION_PATTERN21) || defined(OSD_TRANSITION_PATTERN22) || defined(OSD_TRANSITION_PATTERN23)
#define OSD_TRANSITION_TRIANGLE_SUBPATCH
#else
#undef OSD_TRANSITION_TRIANGLE_SUBPATCH
#endif
struct HS_CONSTANT_TRANSITION_FUNC_OUT {
#ifdef OSD_TRANSITION_TRIANGLE_SUBPATCH
float tessLevelInner : SV_InsideTessFactor;
float tessLevelOuter[3] : SV_TessFactor;
#else
float tessLevelInner[2] : SV_InsideTessFactor;
float tessLevelOuter[4] : SV_TessFactor;
#endif
};
//----------------------------------------------------------
// Patches.HullTransition
//----------------------------------------------------------
void
SetTransitionTessLevels(inout HS_CONSTANT_TRANSITION_FUNC_OUT output, float3 cp[OSD_PATCH_INPUT_SIZE], int patchLevel, uint primitiveID) {
GetTessLevelsUniform(float3 cp[16], int patchParam, int patchLevel,
inout float4 tessOuterLo, inout float4 tessOuterHi)
{
float tessAmount = GetTessLevel(patchLevel);
#ifdef OSD_ENABLE_SCREENSPACE_TESSELLATION
// These tables map the 9, 12, or 16 input control points onto the
// canonical 16 control points for a regular patch.
#if defined OSD_PATCH_BOUNDARY
const int p[16] = { 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
#elif defined OSD_PATCH_CORNER
const int p[16] = { 0, 1, 2, 2, 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8 };
#else
const int p[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
#endif
tessOuterLo = float4(tessAmount,tessAmount,tessAmount,tessAmount);
tessOuterHi = float4(0,0,0,0);
}
#if OSD_TRANSITION_ROTATE == 0
const int r[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
#elif OSD_TRANSITION_ROTATE == 1
const int r[16] = { 12, 8, 4, 0, 13, 9, 5, 1, 14, 10, 6, 2, 15, 11, 7, 3 };
#elif OSD_TRANSITION_ROTATE == 2
const int r[16] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
#elif OSD_TRANSITION_ROTATE == 3
const int r[16] = { 3, 7, 11, 15, 2, 6, 10, 14, 1, 5, 9, 13, 0, 4, 8, 12 };
#endif
//
// Organization of B-spline and Bezier control points.
//
// Each patch is defined by 16 control points (labeled 0-15).
//
// The patch will be evaluated across the domain from (0,0) at
// the lower-left to (1,1) at the upper-right. When computing
// adaptive tessellation metrics, we consider refined vertex-vertex
// and edge-vertex points along the transition edges of the patch
// (labeled vv* and ev* respectively).
//
// The two segments of each transition edge are labeled Lo and Hi,
// with the Lo segment occuring before the Hi segment along the
// transition edge's domain parameterization. These Lo and Hi segment
// tessellation levels determine how domain evaluation coordinates
// are remapped along transition edges. The Hi segment value will
// be zero for a non-transition edge.
//
// (0,1) (1,1)
//
// vv3 ev23 vv2
// | Lo3 | Hi3 |
// --O-----------O-----+-----O-----------O--
// | 12 | 13 14 | 15 |
// | | | |
// | | | |
// Hi0 | | | | Hi2
// | | | |
// O-----------O-----------O-----------O
// | 8 | 9 10 | 11 |
// | | | |
// ev03 --+ | | +-- ev12
// | | | |
// | 4 | 5 6 | 7 |
// O-----------O-----------O-----------O
// | | | |
// Lo0 | | | | Lo2
// | | | |
// | | | |
// | 0 | 1 2 | 3 |
// --O-----------O-----+-----O-----------O--
// | Lo1 | Hi1 |
// vv0 ev01 vv1
//
// (0,0) (1,0)
//
// Expand and rotate control points using remapping tables above
float3 pv0 = cp[p[r[0]]];
float3 pv1 = cp[p[r[1]]];
float3 pv2 = cp[p[r[2]]];
float3 pv3 = cp[p[r[3]]];
float3 pv4 = cp[p[r[4]]];
float3 pv5 = cp[p[r[5]]];
float3 pv6 = cp[p[r[6]]];
float3 pv7 = cp[p[r[7]]];
float3 pv8 = cp[p[r[8]]];
float3 pv9 = cp[p[r[9]]];
float3 pv10 = cp[p[r[10]]];
float3 pv11 = cp[p[r[11]]];
float3 pv12 = cp[p[r[12]]];
float3 pv13 = cp[p[r[13]]];
float3 pv14 = cp[p[r[14]]];
float3 pv15 = cp[p[r[15]]];
// Each edge of a transition patch is adjacent to one or two
// patches at the next refined level of subdivision.
// Compute the corresponding vertex-vertex and edge-vertex refined
// points along the edges of the patch using Catmull-Clark subdivision
// stencil weights.
void
GetTessLevelsRefinedPoints(float3 cp[16], int patchParam,
inout float4 tessOuterLo, inout float4 tessOuterHi)
{
// Each edge of a transition patch is adjacent to one or two patches
// at the next refined level of subdivision. We compute the corresponding
// vertex-vertex and edge-vertex refined points along the edges of the
// patch using Catmull-Clark subdivision stencil weights.
// For simplicity, we let the optimizer discard unused computation.
float3 vv0 = (pv0 + pv2 + pv8 + pv10) * 0.015625 +
(pv1 + pv4 + pv6 + pv9) * 0.09375 + pv5 * 0.5625;
float3 ev01 = (pv1 + pv2 + pv9 + pv10) * 0.0625 + (pv5 + pv6) * 0.375;
float3 vv1 = (pv1 + pv3 + pv9 + pv11) * 0.015625 +
(pv2 + pv5 + pv7 + pv10) * 0.09375 + pv6 * 0.5625;
float3 ev12 = (pv5 + pv7 + pv9 + pv11) * 0.0625 + (pv6 + pv10) * 0.375;
float3 vv0 = (cp[0] + cp[2] + cp[8] + cp[10]) * 0.015625 +
(cp[1] + cp[4] + cp[6] + cp[9]) * 0.09375 + cp[5] * 0.5625;
float3 ev01 = (cp[1] + cp[2] + cp[9] + cp[10]) * 0.0625 +
(cp[5] + cp[6]) * 0.375;
float3 vv2 = (pv5 + pv7 + pv13 + pv15) * 0.015625 +
(pv6 + pv9 + pv11 + pv14) * 0.09375 + pv10 * 0.5625;
float3 ev23 = (pv5 + pv6 + pv13 + pv14) * 0.0625 + (pv9 + pv10) * 0.375;
float3 vv1 = (cp[1] + cp[3] + cp[9] + cp[11]) * 0.015625 +
(cp[2] + cp[5] + cp[7] + cp[10]) * 0.09375 + cp[6] * 0.5625;
float3 ev12 = (cp[5] + cp[7] + cp[9] + cp[11]) * 0.0625 +
(cp[6] + cp[10]) * 0.375;
float3 vv3 = (pv4 + pv6 + pv12 + pv14) * 0.015625 +
(pv5 + pv8 + pv10 + pv13) * 0.09375 + pv9 * 0.5625;
float3 ev30 = (pv4 + pv6 + pv8 + pv10) * 0.0625 + (pv5 + pv9) * 0.375;
float3 vv2 = (cp[5] + cp[7] + cp[13] + cp[15]) * 0.015625 +
(cp[6] + cp[9] + cp[11] + cp[14]) * 0.09375 + cp[10] * 0.5625;
float3 ev23 = (cp[5] + cp[6] + cp[13] + cp[14]) * 0.0625 +
(cp[9] + cp[10]) * 0.375;
// The vertices along boundaries and at corners are refined specially.
#if defined OSD_PATCH_BOUNDARY
#if OSD_TRANSITION_ROTATE == 0
vv0 = (pv4 + pv6) * 0.125 + pv5 * 0.75;
vv1 = (pv5 + pv7) * 0.125 + pv6 * 0.75;
#elif OSD_TRANSITION_ROTATE == 1
vv1 = (pv2 + pv10) * 0.125 + pv6 * 0.75;
vv2 = (pv6 + pv14) * 0.125 + pv10 * 0.75;
#elif OSD_TRANSITION_ROTATE == 2
vv2 = (pv9 + pv11) * 0.125 + pv10 * 0.75;
vv3 = (pv8 + pv10) * 0.125 + pv9 * 0.75;
#elif OSD_TRANSITION_ROTATE == 3
vv3 = (pv5 + pv13) * 0.125 + pv9 * 0.75;
vv0 = (pv1 + pv9) * 0.125 + pv5 * 0.75;
#endif
#elif defined OSD_PATCH_CORNER
#if OSD_TRANSITION_ROTATE == 0
vv0 = (pv4 + pv6) * 0.125 + pv5 * 0.75;
vv1 = pv6;
vv2 = (pv6 + pv14) * 0.125 + pv10 * 0.75;
#elif OSD_TRANSITION_ROTATE == 1
vv1 = (pv2 + pv10) * 0.125 + pv6 * 0.75;
vv2 = pv10;
vv3 = (pv8 + pv10) * 0.125 + pv9 * 0.75;
#elif OSD_TRANSITION_ROTATE == 2
vv2 = (pv9 + pv11) * 0.125 + pv10 * 0.75;
vv3 = pv9;
vv0 = (pv1 + pv9) * 0.125 + pv5 * 0.75;
#elif OSD_TRANSITION_ROTATE == 3
vv3 = (pv5 + pv13) * 0.125 + pv9 * 0.75;
vv0 = pv5;
vv1 = (pv5 + pv7) * 0.125 + pv6 * 0.75;
#endif
#elif defined OSD_PATCH_SINGLE_CREASE
// apply smooth, sharp or fractional-semisharp (linear interpolate) rules
float weight = min(1, GetSharpness(primitiveID));
float3 vv3 = (cp[4] + cp[6] + cp[12] + cp[14]) * 0.015625 +
(cp[5] + cp[8] + cp[10] + cp[13]) * 0.09375 + cp[9] * 0.5625;
float3 ev03 = (cp[4] + cp[6] + cp[8] + cp[10]) * 0.0625 +
(cp[5] + cp[9]) * 0.375;
// XXX: current rotation of single-crease patch is inconsistent
// to boundary patch. should be fixed.
#if OSD_TRANSITION_ROTATE == 2
vv0 = lerp(vv0, (pv4 + pv6) * 0.125 + pv5 * 0.75, weight);
vv1 = lerp(vv1, (pv5 + pv7) * 0.125 + pv6 * 0.75, weight);
#elif OSD_TRANSITION_ROTATE == 3
vv1 = lerp(vv1, (pv2 + pv10) * 0.125 + pv6 * 0.75, weight);
vv2 = lerp(vv2, (pv6 + pv14) * 0.125 + pv10 * 0.75, weight);
#elif OSD_TRANSITION_ROTATE == 0
vv2 = lerp(vv2, (pv9 + pv11) * 0.125 + pv10 * 0.75, weight);
vv3 = lerp(vv3, (pv8 + pv10) * 0.125 + pv9 * 0.75, weight);
#elif OSD_TRANSITION_ROTATE == 1
vv3 = lerp(vv3, (pv5 + pv13) * 0.125 + pv9 * 0.75, weight);
vv0 = lerp(vv0, (pv1 + pv9) * 0.125 + pv5 * 0.75, weight);
#endif
tessOuterLo = float4(1,1,1,1);
tessOuterHi = float4(0,0,0,0);
if (((patchParam >> 11) & 1) != 0) {
tessOuterLo[0] = TessAdaptive(vv0, ev03);
tessOuterHi[0] = TessAdaptive(vv3, ev03);
} else {
tessOuterLo[0] = TessAdaptive(cp[5], cp[9]);
}
if (((patchParam >> 8) & 1) != 0) {
tessOuterLo[1] = TessAdaptive(vv0, ev01);
tessOuterHi[1] = TessAdaptive(vv1, ev01);
} else {
tessOuterLo[1] = TessAdaptive(cp[5], cp[6]);
}
if (((patchParam >> 9) & 1) != 0) {
tessOuterLo[2] = TessAdaptive(vv1, ev12);
tessOuterHi[2] = TessAdaptive(vv2, ev12);
} else {
tessOuterLo[2] = TessAdaptive(cp[6], cp[10]);
}
if (((patchParam >> 10) & 1) != 0) {
tessOuterLo[3] = TessAdaptive(vv3, ev23);
tessOuterHi[3] = TessAdaptive(vv2, ev23);
} else {
tessOuterLo[3] = TessAdaptive(cp[9], cp[10]);
}
}
void
GetTessLevelsLimitPoints(float3 cpBezier[16], int patchParam,
inout float4 tessOuterLo, inout float4 tessOuterHi)
{
// Each edge of a transition patch is adjacent to one or two patches
// at the next refined level of subdivision. When the patch control
// points have been converted to the Bezier basis, the control points
// at the four corners are on the limit surface (since a Bezier patch
// interpolates its corner control points). We can compute an adaptive
// tessellation level for transition edges on the limit surface by
// evaluating a limit position at the mid point of each transition edge.
tessOuterLo = float4(1,1,1,1);
tessOuterHi = float4(0,0,0,0);
if (((patchParam >> 11) & 1) != 0) {
float3 ev03 = EvalBezier(cpBezier, float2(0.0, 0.5));
tessOuterLo[0] = TessAdaptive(cpBezier[0], ev03);
tessOuterHi[0] = TessAdaptive(cpBezier[12], ev03);
} else {
tessOuterLo[0] = TessAdaptive(cpBezier[0], cpBezier[12]);
}
if (((patchParam >> 8) & 1) != 0) {
float3 ev01 = EvalBezier(cpBezier, float2(0.5, 0.0));
tessOuterLo[1] = TessAdaptive(cpBezier[0], ev01);
tessOuterHi[1] = TessAdaptive(cpBezier[3], ev01);
} else {
tessOuterLo[1] = TessAdaptive(cpBezier[0], cpBezier[3]);
}
if (((patchParam >> 9) & 1) != 0) {
float3 ev12 = EvalBezier(cpBezier, float2(1.0, 0.5));
tessOuterLo[2] = TessAdaptive(cpBezier[3], ev12);
tessOuterHi[2] = TessAdaptive(cpBezier[15], ev12);
} else {
tessOuterLo[2] = TessAdaptive(cpBezier[3], cpBezier[15]);
}
if (((patchParam >> 10) & 1) != 0) {
float3 ev23 = EvalBezier(cpBezier, float2(0.5, 1.0));
tessOuterLo[3] = TessAdaptive(cpBezier[12], ev23);
tessOuterHi[3] = TessAdaptive(cpBezier[15], ev23);
} else {
tessOuterLo[3] = TessAdaptive(cpBezier[12], cpBezier[15]);
}
}
void
GetTransitionTessLevels(
float3 cp[16], int patchParam, int patchLevel,
inout float4 outerLevel, inout float4 innerLevel,
inout float4 tessOuterLo, inout float4 tessOuterHi)
{
#if defined OSD_ENABLE_SCREENSPACE_TESSELLATION
GetTessLevelsLimitPoints(cp, patchParam, tessOuterLo, tessOuterHi);
#elif defined OSD_ENABLE_SCREENSPACE_TESSELLATION_REFINED
GetTessLevelsRefinedPoints(cp, patchParam, tessOuterLo, tessOuterHi);
#else
GetTessLevelsUniform(cp, patchParam, patchLevel, tessOuterLo, tessOuterHi);
#endif
#ifdef OSD_TRANSITION_PATTERN00
output.tessLevelOuter[0] = TessAdaptive(ev01, pv9) * 0.5;
output.tessLevelOuter[1] = TessAdaptive(ev01, pv10) * 0.5;
output.tessLevelOuter[2] = TessAdaptive(pv9, pv10);
// Outer levels are the sum of the Lo and Hi segments where the Hi
// segments will have a length of zero for non-transition edges.
outerLevel = tessOuterLo + tessOuterHi;
output.tessLevelInner =
(output.tessLevelOuter[0] + output.tessLevelOuter[1] + output.tessLevelOuter[2]) * 0.5;
#endif
#ifdef OSD_TRANSITION_PATTERN01
output.tessLevelOuter[0] = TessAdaptive(ev01, vv1);
output.tessLevelOuter[1] = TessAdaptive(pv6, pv10);
output.tessLevelOuter[2] = TessAdaptive(ev01, pv10) * 0.5;
output.tessLevelInner =
(output.tessLevelOuter[0] + output.tessLevelOuter[1] + output.tessLevelOuter[2]) * 0.25;
#endif
#ifdef OSD_TRANSITION_PATTERN02
output.tessLevelOuter[0] = TessAdaptive(ev01, vv0);
output.tessLevelOuter[1] = TessAdaptive(ev01, pv9) * 0.5;
output.tessLevelOuter[2] = TessAdaptive(pv5, pv9);
output.tessLevelInner =
(output.tessLevelOuter[0] + output.tessLevelOuter[1] + output.tessLevelOuter[2]) * 0.25;
#endif
#ifdef OSD_TRANSITION_PATTERN10
output.tessLevelOuter[0] = TessAdaptive(pv6, pv10);
output.tessLevelOuter[1] = TessAdaptive(ev01, pv10);
output.tessLevelOuter[2] = TessAdaptive(ev01, vv1);
output.tessLevelInner =
(output.tessLevelOuter[0] + output.tessLevelOuter[1]) * 0.25;
#endif
#ifdef OSD_TRANSITION_PATTERN11
output.tessLevelOuter[0] = TessAdaptive(pv9, pv10);
output.tessLevelOuter[1] = TessAdaptive(ev30, vv3);
output.tessLevelOuter[2] = TessAdaptive(ev30, pv10);
output.tessLevelInner =
(output.tessLevelOuter[0] + output.tessLevelOuter[2]) * 0.25;
#endif
#ifdef OSD_TRANSITION_PATTERN12
output.tessLevelOuter[0] = TessAdaptive(ev30, vv0);
output.tessLevelOuter[1] = TessAdaptive(ev01, vv0);
output.tessLevelOuter[2] = TessAdaptive(ev01, ev30);
output.tessLevelInner =
(output.tessLevelOuter[0] + output.tessLevelOuter[1] + output.tessLevelOuter[2]) * 0.25;
#endif
#ifdef OSD_TRANSITION_PATTERN13
output.tessLevelOuter[0] = TessAdaptive(ev01, pv10);
output.tessLevelOuter[1] = TessAdaptive(ev30, pv10);
output.tessLevelOuter[2] = TessAdaptive(ev01, ev30);
output.tessLevelInner =
(output.tessLevelOuter[0] + output.tessLevelOuter[1] + output.tessLevelOuter[2]) * 0.25;
#endif
#ifdef OSD_TRANSITION_PATTERN20
output.tessLevelOuter[0] = TessAdaptive(pv5, pv6);
output.tessLevelOuter[1] = TessAdaptive(ev12, vv1);
output.tessLevelOuter[2] = TessAdaptive(ev12, ev30);
output.tessLevelOuter[3] = TessAdaptive(ev30, vv0);
output.tessLevelInner[0] =
max(output.tessLevelOuter[1], output.tessLevelOuter[3]);
output.tessLevelInner[1] =
max(output.tessLevelOuter[0], output.tessLevelOuter[2]);
#endif
#ifdef OSD_TRANSITION_PATTERN21
output.tessLevelOuter[0] = TessAdaptive(ev23, ev30) * 0.5;
output.tessLevelOuter[1] = TessAdaptive(ev23, vv3);
output.tessLevelOuter[2] = TessAdaptive(ev30, vv3);
output.tessLevelInner =
(output.tessLevelOuter[1] + output.tessLevelOuter[2]) * 0.5;
#endif
#ifdef OSD_TRANSITION_PATTERN22
output.tessLevelOuter[0] = TessAdaptive(ev12, vv2);
output.tessLevelOuter[1] = TessAdaptive(ev23, vv2);
output.tessLevelOuter[2] = TessAdaptive(ev12, ev23) * 0.5;
output.tessLevelInner =
(output.tessLevelOuter[0] + output.tessLevelOuter[1]) * 0.5;
#endif
#ifdef OSD_TRANSITION_PATTERN23
output.tessLevelOuter[0] = TessAdaptive(ev12, ev30);
output.tessLevelOuter[1] = TessAdaptive(ev12, ev23) * 0.5;
output.tessLevelOuter[2] = TessAdaptive(ev23, ev30) * 0.5;
output.tessLevelInner =
(output.tessLevelOuter[0] + output.tessLevelOuter[1] + output.tessLevelOuter[2]) * 0.5;
#endif
#ifdef OSD_TRANSITION_PATTERN30
output.tessLevelOuter[0] = TessAdaptive(ev30, ev12) * 0.5;
output.tessLevelOuter[1] = TessAdaptive(ev30, vv0);
output.tessLevelOuter[2] = TessAdaptive(ev01, vv0);
output.tessLevelOuter[3] = TessAdaptive(ev01, ev23) * 0.5;
output.tessLevelInner[0] =
max(output.tessLevelOuter[1], output.tessLevelOuter[3]);
output.tessLevelInner[1] =
max(output.tessLevelOuter[0], output.tessLevelOuter[2]);
#endif
#ifdef OSD_TRANSITION_PATTERN31
output.tessLevelOuter[0] = TessAdaptive(ev01, ev23) * 0.5;
output.tessLevelOuter[1] = TessAdaptive(ev23, vv3);
output.tessLevelOuter[2] = TessAdaptive(ev30, vv3);
output.tessLevelOuter[3] = TessAdaptive(ev30, ev12) * 0.5;
output.tessLevelInner[0] =
max(output.tessLevelOuter[1], output.tessLevelOuter[3]);
output.tessLevelInner[1] =
max(output.tessLevelOuter[0], output.tessLevelOuter[2]);
#endif
#ifdef OSD_TRANSITION_PATTERN32
output.tessLevelOuter[0] = TessAdaptive(ev23, ev01) * 0.5;
output.tessLevelOuter[1] = TessAdaptive(ev01, vv1);
output.tessLevelOuter[2] = TessAdaptive(ev12, vv1);
output.tessLevelOuter[3] = TessAdaptive(ev12, ev30) * 0.5;
output.tessLevelInner[0] =
max(output.tessLevelOuter[1], output.tessLevelOuter[3]);
output.tessLevelInner[1] =
max(output.tessLevelOuter[0], output.tessLevelOuter[2]);
#endif
#ifdef OSD_TRANSITION_PATTERN33
output.tessLevelOuter[0] = TessAdaptive(ev12, ev30) * 0.5;
output.tessLevelOuter[1] = TessAdaptive(ev12, vv2);
output.tessLevelOuter[2] = TessAdaptive(ev23, vv2);
output.tessLevelOuter[3] = TessAdaptive(ev01, ev23) * 0.5;
output.tessLevelInner[0] =
max(output.tessLevelOuter[1], output.tessLevelOuter[3]);
output.tessLevelInner[1] =
max(output.tessLevelOuter[0], output.tessLevelOuter[2]);
#endif
#ifdef OSD_TRANSITION_PATTERN40
output.tessLevelOuter[0] = TessAdaptive(ev01, vv0);
output.tessLevelOuter[1] = TessAdaptive(ev01, ev23);
output.tessLevelOuter[2] = TessAdaptive(ev23, vv3);
output.tessLevelOuter[3] = TessAdaptive(pv5, pv9);
output.tessLevelInner[0] =
max(output.tessLevelOuter[1], output.tessLevelOuter[3]);
output.tessLevelInner[1] =
max(output.tessLevelOuter[0], output.tessLevelOuter[2]);
#endif
#ifdef OSD_TRANSITION_PATTERN41
output.tessLevelOuter[0] = TessAdaptive(ev01, vv1);
output.tessLevelOuter[1] = TessAdaptive(pv6, pv10);
output.tessLevelOuter[2] = TessAdaptive(ev23, vv2);
output.tessLevelOuter[3] = TessAdaptive(ev01, ev23);
output.tessLevelInner[0] =
max(output.tessLevelOuter[1], output.tessLevelOuter[3]);
output.tessLevelInner[1] =
max(output.tessLevelOuter[0], output.tessLevelOuter[2]);
#endif
#else // OSD_ENABLE_SCREENSPACE_TESSELLATION
// XXX: HLSL compiler crashes with an internal compiler error occasionaly
// if this shader accesses a shader resource buffer or a constant buffer
// from this hull constant function.
//float TessAmount = GetTessLevel(patchLevel);
//float TessAmount = GetTessLevel(0);
float TessAmount = 2.0;
#ifdef OSD_TRANSITION_PATTERN00
float side = sqrt(1.25)*TessAmount;
output.tessLevelOuter[0] = side;
output.tessLevelOuter[1] = side;
output.tessLevelOuter[2] = TessAmount;
output.tessLevelInner = TessAmount;
#endif
#ifdef OSD_TRANSITION_PATTERN01
float side = sqrt(1.25)*TessAmount;
output.tessLevelOuter[0] = TessAmount/2.0;
output.tessLevelOuter[1] = TessAmount;
output.tessLevelOuter[2] = side;
output.tessLevelInner = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN02
float side = sqrt(1.25)*TessAmount;
output.tessLevelOuter[0] = TessAmount/2.0;
output.tessLevelOuter[1] = side;
output.tessLevelOuter[2] = TessAmount;
output.tessLevelInner = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN10
float side = sqrt(1.25) * TessAmount;
output.tessLevelOuter[0] = TessAmount;
output.tessLevelOuter[1] = side;
output.tessLevelOuter[2] = TessAmount/2.0;
output.tessLevelInner = TessAmount/2;
#endif
#ifdef OSD_TRANSITION_PATTERN11
float side = sqrt(1.25) * TessAmount;
output.tessLevelOuter[0] = TessAmount;
output.tessLevelOuter[1] = TessAmount/2.0;
output.tessLevelOuter[2] = side;
output.tessLevelInner = TessAmount/2;
#endif
#ifdef OSD_TRANSITION_PATTERN12
float side = sqrt(0.125) * TessAmount;
output.tessLevelOuter[0] = TessAmount/2.0;
output.tessLevelOuter[1] = TessAmount/2.0;
output.tessLevelOuter[2] = side;
output.tessLevelInner = TessAmount/2;
#endif
#ifdef OSD_TRANSITION_PATTERN13
float side1 = sqrt(1.25) * TessAmount;
float side2 = sqrt(0.125) * TessAmount;
output.tessLevelOuter[0] = side1;
output.tessLevelOuter[1] = side1;
output.tessLevelOuter[2] = side2;
output.tessLevelInner = TessAmount/2.0*1.414;
#endif
#ifdef OSD_TRANSITION_PATTERN20
output.tessLevelOuter[0] = TessAmount;
output.tessLevelOuter[1] = TessAmount/2.0;
output.tessLevelOuter[2] = TessAmount;
output.tessLevelOuter[3] = TessAmount/2.0;
output.tessLevelInner[0] = TessAmount/2.0;
output.tessLevelInner[1] = TessAmount;
#endif
#ifdef OSD_TRANSITION_PATTERN21
float side = sqrt(0.125) * TessAmount;
output.tessLevelOuter[0] = side;
output.tessLevelOuter[1] = TessAmount/2.0;
output.tessLevelOuter[2] = TessAmount/2.0;
output.tessLevelInner = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN22
float side = sqrt(0.125) * TessAmount;
output.tessLevelOuter[0] = TessAmount/2.0;
output.tessLevelOuter[1] = TessAmount/2.0;
output.tessLevelOuter[2] = side;
output.tessLevelInner = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN23
float side = sqrt(0.125) * TessAmount;
output.tessLevelOuter[0] = TessAmount;
output.tessLevelOuter[1] = side;
output.tessLevelOuter[2] = side;
output.tessLevelInner = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN30
output.tessLevelOuter[0] = output.tessLevelOuter[1] =
output.tessLevelOuter[2] = output.tessLevelOuter[3] = TessAmount/2.0;
output.tessLevelInner[0] = output.tessLevelInner[1] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN31
output.tessLevelOuter[0] = output.tessLevelOuter[1] =
output.tessLevelOuter[2] = output.tessLevelOuter[3] = TessAmount/2.0;
output.tessLevelInner[0] = output.tessLevelInner[1] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN32
output.tessLevelOuter[0] = output.tessLevelOuter[1] =
output.tessLevelOuter[2] = output.tessLevelOuter[3] = TessAmount/2.0;
output.tessLevelInner[0] = output.tessLevelInner[1] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN33
output.tessLevelOuter[0] = output.tessLevelOuter[1] =
output.tessLevelOuter[2] = output.tessLevelOuter[3] = TessAmount/2.0;
output.tessLevelInner[0] = output.tessLevelInner[1] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN40
output.tessLevelOuter[0] = TessAmount/2.0;
output.tessLevelOuter[1] = TessAmount;
output.tessLevelOuter[2] = TessAmount/2.0;
output.tessLevelOuter[3] = TessAmount;
output.tessLevelInner[0] = TessAmount;
output.tessLevelInner[1] = TessAmount/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN41
output.tessLevelOuter[0] = TessAmount/2.0;
output.tessLevelOuter[1] = TessAmount;
output.tessLevelOuter[2] = TessAmount/2.0;
output.tessLevelOuter[3] = TessAmount;
output.tessLevelInner[0] = TessAmount;
output.tessLevelInner[1] = TessAmount/2.0;
#endif
#endif // OSD_ENABLE_SCREENSPACE_TESSELLATION
// Inner levels are the average the corresponding outer levels.
innerLevel[0] = (outerLevel[1] + outerLevel[3]) * 0.5;
innerLevel[1] = (outerLevel[0] + outerLevel[2]) * 0.5;
}
//----------------------------------------------------------
// Patches.DomainTransition
//----------------------------------------------------------
float2
GetTransitionSubpatchUV(
#ifdef OSD_TRANSITION_TRIANGLE_SUBPATCH
in float3 uvw
#else
in float2 uv
#endif
)
float
GetTransitionSplit(float t, float n0, float n1)
{
float2 UV = float2(0.0, 0.0);
float ti = round(t * (n0 + n1));
// OSD_TRANSITION_PATTERN0*
// +-------------+
// | /\\ |
// | 1 / \\ 2 |
// | / \\ |
// | / \\ |
// | / 0 \\ |
// |/ \\|
// +-------------+
#ifdef OSD_TRANSITION_PATTERN00
UV.x = 1.0-uvw.y-uvw.z/2;
UV.y = 1.0-uvw.z;
#endif
#ifdef OSD_TRANSITION_PATTERN01
UV.x = 1.0-uvw.y/2;
UV.y = uvw.x;
#endif
#ifdef OSD_TRANSITION_PATTERN02
UV.x = uvw.z/2;
UV.y = uvw.x;
#endif
// OSD_TRANSITION_PATTERN1*
// +-------------+
// | 0 /\\ 2 |
// | / \\ |
// | / 3 \\ |
// | / / |
// | / / 1 |
// |/ / |
// +-------------+
#ifdef OSD_TRANSITION_PATTERN10
UV.x = 1.0-uvw.x/2.0;
UV.y = uvw.z;
#endif
#ifdef OSD_TRANSITION_PATTERN11
UV.x = uvw.y;
UV.y = 1.0-uvw.x/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN12
UV.x = uvw.x/2.0;
UV.y = uvw.y/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN13
UV.x = 1.0-uvw.x-uvw.y/2.0;
UV.y = 1.0-uvw.y-uvw.x/2.0;
#endif
// OSD_TRANSITION_PATTERN2*
// +-------------+
// | |
// | 0 |
// | |
// |-------------|
// |\\ 3 / |
// | \\ / |
// | 1 \\ / 2 |
// +-------------+
#ifdef OSD_TRANSITION_PATTERN20
UV.x = 1.0-uv.y;
UV.y = uv.x/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN21
UV.x = uvw.z/2.0;
UV.y = 1.0-uvw.y/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN22
UV.x = 1.0-uvw.x/2.0;
UV.y = 1.0-uvw.y/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN23
UV.x = 1.0-uvw.y-uvw.x/2;
UV.y = 0.5+uvw.x/2.0;
#endif
// OSD_TRANSITION_PATTERN3*
// +-------------+
// | | |
// | 1 | 0 |
// | | |
// |------|------|
// | | |
// | 3 | 2 |
// | | |
// +-------------+
#ifdef OSD_TRANSITION_PATTERN30
UV.x = uv.y/2.0;
UV.y = 0.5 - uv.x/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN31
UV.x = 0.5 - uv.x/2.0;
UV.y = 1.0 - uv.y/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN32
UV.x = 0.5 + uv.x/2.0;
UV.y = uv.y/2.0;
#endif
#ifdef OSD_TRANSITION_PATTERN33
UV.x = 1.0 - uv.y/2.0;
UV.y = 0.5 + uv.x/2.0;
#endif
// OSD_TRANSITION_PATTERN4*
// +-------------+
// | | |
// | | |
// | | |
// | 1 | 0 |
// | | |
// | | |
// | | |
// +-------------+
#ifdef OSD_TRANSITION_PATTERN40
UV.x = 0.5 - uv.y/2.0;
UV.y = uv.x;
#endif
#ifdef OSD_TRANSITION_PATTERN41
UV.x = 1.0 - uv.y/2.0;
UV.y = uv.x;
#endif
if (ti <= n0) {
return 0.5 * (ti / n0);
} else {
return 0.5 * ((ti - n0) / n1) + 0.5;
}
}
float2
GetTransitionParameterization(
in HS_CONSTANT_FUNC_OUT input,
in float2 uv)
{
float2 UV = uv.xy;
if (UV.x == 0 && input.tessOuterHi[0] > 0) {
UV.y = GetTransitionSplit(UV.y, input.tessOuterLo[0], input.tessOuterHi[0]);
} else
if (UV.y == 0 && input.tessOuterHi[1] > 0) {
UV.x = GetTransitionSplit(UV.x, input.tessOuterLo[1], input.tessOuterHi[1]);
} else
if (UV.x == 1 && input.tessOuterHi[2] > 0) {
UV.y = GetTransitionSplit(UV.y, input.tessOuterLo[2], input.tessOuterHi[2]);
} else
if (UV.y == 1 && input.tessOuterHi[3] > 0) {
UV.x = GetTransitionSplit(UV.x, input.tessOuterLo[3], input.tessOuterHi[3]);
}
return UV;
}

View File

@ -27,7 +27,6 @@
#include "../version.h"
#include "../far/kernelBatch.h"
#include "../far/topologyRefiner.h"
#include "../far/patchTablesFactory.h"
#include "../far/stencilTables.h"
@ -51,8 +50,10 @@ enum MeshBits {
MeshPtexData = 2,
MeshFVarData = 3,
MeshUseSingleCreasePatch = 4,
MeshUseGregoryBasis = 5,
NUM_MESH_BITS = 6,
MeshEndCapRegular = 5, // exclusive
MeshEndCapGregoryBasis = 6, // exclusive
MeshEndCapLegacyGregory = 7, // exclusive
NUM_MESH_BITS = 8,
};
typedef std::bitset<NUM_MESH_BITS> MeshBitset;
@ -91,12 +92,6 @@ public:
protected:
static inline int getNumVertices(Far::TopologyRefiner const & refiner) {
return refiner.IsUniform() ?
refiner.GetNumVertices(0) + refiner.GetNumVertices(refiner.GetMaxLevel()) :
refiner.GetNumVerticesTotal();
}
static inline void refineMesh(Far::TopologyRefiner & refiner, int level, bool adaptive, bool singleCreasePatch) {
if (adaptive) {
@ -154,7 +149,6 @@ public:
Mesh(ComputeController * computeController,
Far::TopologyRefiner * refiner,
Far::PatchTables * patchTables,
Far::KernelBatchVector const & kernelBatches,
VertexBuffer * vertexBuffer,
VertexBuffer * varyingBuffer,
ComputeContext * computeContext,
@ -162,12 +156,11 @@ public:
_refiner(refiner),
_patchTables(patchTables),
_kernelBatches(kernelBatches),
_vertexBuffer(vertexBuffer),
_varyingBuffer(varyingBuffer),
_computeContext(computeContext),
_computeController(computeController),
_drawContext(drawContext) { }
_drawContext(drawContext) {}
virtual ~Mesh() {
delete _refiner;
@ -178,11 +171,6 @@ public:
delete _drawContext;
}
virtual int GetNumVertices() const {
assert(_refiner);
return MeshInterface<DRAW_CONTEXT>::getNumVertices(*_refiner);
}
virtual void UpdateVertexBuffer(float const *vertexData, int startVertex, int numVerts) {
_vertexBuffer->UpdateData(vertexData, startVertex, numVerts);
}
@ -192,11 +180,11 @@ public:
}
virtual void Refine() {
_computeController->Compute(_computeContext, _kernelBatches, _vertexBuffer, _varyingBuffer);
_computeController->Compute(_computeContext, _vertexBuffer, _varyingBuffer);
}
virtual void Refine(VertexBufferDescriptor const *vertexDesc, VertexBufferDescriptor const *varyingDesc) {
_computeController->Refine(_computeContext, _kernelBatches, _vertexBuffer, _varyingBuffer, vertexDesc, varyingDesc);
_computeController->Refine(_computeContext, _vertexBuffer, _varyingBuffer, vertexDesc, varyingDesc);
}
virtual void Synchronize() {
@ -222,7 +210,6 @@ public:
}
private:
void initializeComputeContext(int numVertexElements,
int numVaryingElements ) {
@ -237,8 +224,6 @@ private:
if (numVertexElements>0) {
vertexStencils = Far::StencilTablesFactory::Create(*_refiner, options);
_kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils));
}
if (numVaryingElements>0) {
@ -258,7 +243,7 @@ private:
assert(_refiner and _vertexBuffer);
Far::PatchTablesFactory::Options options(level);
Far::PatchTablesFactoryBase::Options options(level);
options.generateFVarTables = bits.test(MeshFVarData);
options.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch);
@ -287,11 +272,10 @@ private:
_varyingBuffer = VertexBuffer::Create(numVaryingElements, numVertices);
}
return numElements;
}
}
Far::TopologyRefiner * _refiner;
Far::PatchTables * _patchTables;
Far::KernelBatchVector _kernelBatches;
VertexBuffer * _vertexBuffer,
* _varyingBuffer;

View File

@ -40,7 +40,7 @@ OmpComputeController::OmpComputeController(int numThreads) {
void
OmpComputeController::ApplyStencilTableKernel(
Far::KernelBatch const &batch, ComputeContext const *context) const {
ComputeContext const *context) const {
assert(context);
@ -48,6 +48,9 @@ OmpComputeController::ApplyStencilTableKernel(
if (vertexStencils and _currentBindState.vertexBuffer) {
int start = 0;
int end = vertexStencils->GetNumStencils();
VertexBufferDescriptor const & desc = _currentBindState.vertexDesc;
float const * srcBuffer = _currentBindState.vertexBuffer + desc.offset;
@ -55,20 +58,25 @@ OmpComputeController::ApplyStencilTableKernel(
float * destBuffer = _currentBindState.vertexBuffer + desc.offset +
vertexStencils->GetNumControlVertices() * desc.stride;
OmpComputeStencils(_currentBindState.vertexDesc,
srcBuffer, destBuffer,
&vertexStencils->GetSizes().at(0),
&vertexStencils->GetOffsets().at(0),
&vertexStencils->GetControlIndices().at(0),
&vertexStencils->GetWeights().at(0),
batch.start,
batch.end);
if (end > start) {
OmpComputeStencils(_currentBindState.vertexDesc,
srcBuffer, destBuffer,
&vertexStencils->GetSizes().at(0),
&vertexStencils->GetOffsets().at(0),
&vertexStencils->GetControlIndices().at(0),
&vertexStencils->GetWeights().at(0),
start,
end);
}
}
Far::StencilTables const * varyingStencils = context->GetVaryingStencilTables();
if (varyingStencils and _currentBindState.varyingBuffer) {
int start = 0;
int end = varyingStencils->GetNumStencils();
VertexBufferDescriptor const & desc = _currentBindState.varyingDesc;
float const * srcBuffer = _currentBindState.varyingBuffer + desc.offset;
@ -76,14 +84,16 @@ OmpComputeController::ApplyStencilTableKernel(
float * destBuffer = _currentBindState.varyingBuffer + desc.offset +
varyingStencils->GetNumControlVertices() * desc.stride;
OmpComputeStencils(_currentBindState.varyingDesc,
srcBuffer, destBuffer,
&varyingStencils->GetSizes().at(0),
&varyingStencils->GetOffsets().at(0),
&varyingStencils->GetControlIndices().at(0),
&varyingStencils->GetWeights().at(0),
batch.start,
batch.end);
if (end > start) {
OmpComputeStencils(_currentBindState.varyingDesc,
srcBuffer, destBuffer,
&varyingStencils->GetSizes().at(0),
&varyingStencils->GetOffsets().at(0),
&varyingStencils->GetControlIndices().at(0),
&varyingStencils->GetWeights().at(0),
start,
end);
}
}
}

View File

@ -27,7 +27,6 @@
#include "../version.h"
#include "../far/kernelBatchDispatcher.h"
#include "../osd/cpuComputeContext.h"
#include "../osd/vertexDescriptor.h"
@ -66,9 +65,6 @@ public:
///
/// @param context The CpuContext to apply refinement operations to
///
/// @param batches Vector of batches of vertices organized by operative
/// kernel
///
/// @param vertexBuffer Vertex-interpolated data buffer
///
/// @param vertexDesc The descriptor of vertex elements to be refined.
@ -83,19 +79,16 @@ public:
///
template<class VERTEX_BUFFER, class VARYING_BUFFER>
void Compute( CpuComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER * vertexBuffer,
VARYING_BUFFER * varyingBuffer,
VertexBufferDescriptor const * vertexDesc=NULL,
VertexBufferDescriptor const * varyingDesc=NULL ){
if (batches.empty()) return;
omp_set_num_threads(_numThreads);
bind(vertexBuffer, varyingBuffer, vertexDesc, varyingDesc);
Far::KernelBatchDispatcher::Apply(this, context, batches, /*maxlevel*/ -1);
ApplyStencilTableKernel(context);
unbind();
}
@ -104,17 +97,13 @@ public:
///
/// @param context The CpuContext to apply refinement operations to
///
/// @param batches Vector of batches of vertices organized by operative
/// kernel
///
/// @param vertexBuffer Vertex-interpolated data buffer
///
template<class VERTEX_BUFFER>
void Compute(CpuComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER *vertexBuffer) {
Compute<VERTEX_BUFFER>(context, batches, vertexBuffer, (VERTEX_BUFFER*)0);
Compute<VERTEX_BUFFER>(context, vertexBuffer, (VERTEX_BUFFER*)0);
}
/// Waits until all running subdivision kernels finish.
@ -122,10 +111,7 @@ public:
protected:
friend class Far::KernelBatchDispatcher;
void ApplyStencilTableKernel(Far::KernelBatch const &batch,
ComputeContext const *context) const;
void ApplyStencilTableKernel(ComputeContext const *context) const;
template<class VERTEX_BUFFER, class VARYING_BUFFER>
void bind( VERTEX_BUFFER * vertexBuffer,

View File

@ -49,7 +49,7 @@ TbbComputeController::TbbComputeController(int numThreads)
void
TbbComputeController::ApplyStencilTableKernel(
Far::KernelBatch const &batch, ComputeContext const *context) const {
ComputeContext const *context) const {
assert(context);
@ -57,6 +57,9 @@ TbbComputeController::ApplyStencilTableKernel(
if (vertexStencils and _currentBindState.vertexBuffer) {
int start = 0;
int end = vertexStencils->GetNumStencils();
VertexBufferDescriptor const & desc = _currentBindState.vertexDesc;
float const * srcBuffer = _currentBindState.vertexBuffer + desc.offset;
@ -64,20 +67,25 @@ TbbComputeController::ApplyStencilTableKernel(
float * destBuffer = _currentBindState.vertexBuffer + desc.offset +
vertexStencils->GetNumControlVertices() * desc.stride;
TbbComputeStencils(_currentBindState.vertexDesc,
srcBuffer, destBuffer,
&vertexStencils->GetSizes().at(0),
&vertexStencils->GetOffsets().at(0),
&vertexStencils->GetControlIndices().at(0),
&vertexStencils->GetWeights().at(0),
batch.start,
batch.end);
if (end > start) {
TbbComputeStencils(_currentBindState.vertexDesc,
srcBuffer, destBuffer,
&vertexStencils->GetSizes().at(0),
&vertexStencils->GetOffsets().at(0),
&vertexStencils->GetControlIndices().at(0),
&vertexStencils->GetWeights().at(0),
start,
end);
}
}
Far::StencilTables const * varyingStencils = context->GetVaryingStencilTables();
if (varyingStencils and _currentBindState.varyingBuffer) {
int start = 0;
int end = varyingStencils->GetNumStencils();
VertexBufferDescriptor const & desc = _currentBindState.varyingDesc;
float const * srcBuffer = _currentBindState.varyingBuffer + desc.offset;
@ -85,14 +93,16 @@ TbbComputeController::ApplyStencilTableKernel(
float * destBuffer = _currentBindState.varyingBuffer + desc.offset +
varyingStencils->GetNumControlVertices() * desc.stride;
TbbComputeStencils(_currentBindState.varyingDesc,
srcBuffer, destBuffer,
&varyingStencils->GetSizes().at(0),
&varyingStencils->GetOffsets().at(0),
&varyingStencils->GetControlIndices().at(0),
&varyingStencils->GetWeights().at(0),
batch.start,
batch.end);
if (end > start) {
TbbComputeStencils(_currentBindState.varyingDesc,
srcBuffer, destBuffer,
&varyingStencils->GetSizes().at(0),
&varyingStencils->GetOffsets().at(0),
&varyingStencils->GetControlIndices().at(0),
&varyingStencils->GetWeights().at(0),
start,
end);
}
}
}

View File

@ -27,7 +27,6 @@
#include "../version.h"
#include "../far/kernelBatchDispatcher.h"
#include "../osd/cpuComputeContext.h"
#include "../osd/vertexDescriptor.h"
@ -62,9 +61,6 @@ public:
///
/// @param context The CpuContext to apply refinement operations to
///
/// @param batches Vector of batches of vertices organized by operative
/// kernel
///
/// @param vertexBuffer Vertex-interpolated data buffer
///
/// @param vertexDesc The descriptor of vertex elements to be refined.
@ -79,17 +75,14 @@ public:
///
template<class VERTEX_BUFFER, class VARYING_BUFFER>
void Compute( CpuComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER * vertexBuffer,
VARYING_BUFFER * varyingBuffer,
VertexBufferDescriptor const * vertexDesc=NULL,
VertexBufferDescriptor const * varyingDesc=NULL ){
if (batches.empty()) return;
bind(vertexBuffer, varyingBuffer, vertexDesc, varyingDesc);
Far::KernelBatchDispatcher::Apply(this, context, batches, /*maxlevel*/ -1);
ApplyStencilTableKernel(context);
unbind();
}
@ -98,17 +91,13 @@ public:
///
/// @param context The CpuContext to apply refinement operations to
///
/// @param batches Vector of batches of vertices organized by operative
/// kernel
///
/// @param vertexBuffer Vertex-interpolated data buffer
///
template<class VERTEX_BUFFER>
void Compute(CpuComputeContext const * context,
Far::KernelBatchVector const & batches,
VERTEX_BUFFER *vertexBuffer) {
Compute<VERTEX_BUFFER>(context, batches, vertexBuffer, (VERTEX_BUFFER*)0);
Compute<VERTEX_BUFFER>(context, vertexBuffer, (VERTEX_BUFFER*)0);
}
/// Waits until all running subdivision kernels finish.
@ -116,10 +105,7 @@ public:
protected:
friend class Far::KernelBatchDispatcher;
void ApplyStencilTableKernel(Far::KernelBatch const &batch,
ComputeContext const *context) const;
void ApplyStencilTableKernel(ComputeContext const *context) const;
template<class VERTEX_BUFFER, class VARYING_BUFFER>
void bind( VERTEX_BUFFER * vertexBuffer,

View File

@ -76,13 +76,12 @@ Scheme<SCHEME_BILINEAR>::ComputeVertexVertexMask(VERTEX const& vertex, MASK& mas
//
// Limit masks for any bilinear vertex are the vertex itself, with all tangents being
// zero for now as tangents are not unique (what did Hbr do?):
// Limit masks for position -- the limit position of all vertices is the refined vertex.
//
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_BILINEAR>::assignInteriorLimitMask(VERTEX const& /* vertex */, MASK& posMask) const {
Scheme<SCHEME_BILINEAR>::assignCornerLimitMask(VERTEX const& /* vertex */, MASK& posMask) const {
posMask.SetNumVertexWeights(1);
posMask.SetNumEdgeWeights(0);
@ -95,38 +94,65 @@ Scheme<SCHEME_BILINEAR>::assignInteriorLimitMask(VERTEX const& /* vertex */, MAS
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_BILINEAR>::assignBoundaryLimitMask(VERTEX const& vertex, MASK& posMask) const {
Scheme<SCHEME_BILINEAR>::assignCreaseLimitMask(VERTEX const& vertex, MASK& posMask,
int const /* creaseEnds */[2]) const {
assignInteriorLimitMask(vertex, posMask);
assignCornerLimitMask(vertex, posMask);
}
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_BILINEAR>::assignInteriorLimitTangentMasks(VERTEX const& /* vertex */,
Scheme<SCHEME_BILINEAR>::assignSmoothLimitMask(VERTEX const& vertex, MASK& posMask) const {
assignCornerLimitMask(vertex, posMask);
}
//
// Limit masks for tangents -- these are ambibuous around all vertices. Provide
// the tangents based on the incident edges of the first face.
//
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_BILINEAR>::assignCornerLimitTangentMasks(VERTEX const& /* vertex */,
MASK& tan1Mask, MASK& tan2Mask) const {
tan1Mask.SetNumVertexWeights(1);
tan1Mask.SetNumEdgeWeights(0);
tan1Mask.SetNumEdgeWeights(2);
tan1Mask.SetNumFaceWeights(0);
tan1Mask.SetFaceWeightsForFaceCenters(false);
tan2Mask.SetNumVertexWeights(1);
tan2Mask.SetNumEdgeWeights(0);
tan2Mask.SetNumEdgeWeights(2);
tan2Mask.SetNumFaceWeights(0);
tan2Mask.SetFaceWeightsForFaceCenters(false);
tan1Mask.VertexWeight(0) = 0.0f;
tan2Mask.VertexWeight(0) = 0.0f;
tan1Mask.VertexWeight(0) = -1.0f;
tan1Mask.EdgeWeight(0) = 1.0f;
tan1Mask.EdgeWeight(1) = 0.0f;
tan2Mask.VertexWeight(0) = -1.0f;
tan2Mask.EdgeWeight(0) = 0.0f;
tan2Mask.EdgeWeight(1) = 1.0f;
}
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_BILINEAR>::assignBoundaryLimitTangentMasks(VERTEX const& vertex,
Scheme<SCHEME_BILINEAR>::assignCreaseLimitTangentMasks(VERTEX const& vertex,
MASK& tan1Mask, MASK& tan2Mask, int const /* creaseEnds */[2]) const {
assignCornerLimitTangentMasks(vertex, tan1Mask, tan2Mask);
}
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_BILINEAR>::assignSmoothLimitTangentMasks(VERTEX const& vertex,
MASK& tan1Mask, MASK& tan2Mask) const {
assignInteriorLimitTangentMasks(vertex, tan1Mask, tan2Mask);
assignCornerLimitTangentMasks(vertex, tan1Mask, tan2Mask);
}
} // end namespace sdc

View File

@ -145,8 +145,8 @@ Scheme<SCHEME_CATMARK>::assignSmoothMaskForEdge(EDGE const& edge, MASK& mask) co
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_CATMARK>::assignCreaseMaskForVertex(VERTEX const& vertex, MASK& mask, float const edgeSharpness[]) const {
Scheme<SCHEME_CATMARK>::assignCreaseMaskForVertex(VERTEX const& vertex, MASK& mask,
int const creaseEnds[2]) const {
typedef typename MASK::Weight Weight;
int valence = vertex.GetNumEdges();
@ -160,25 +160,11 @@ Scheme<SCHEME_CATMARK>::assignCreaseMaskForVertex(VERTEX const& vertex, MASK& ma
Weight eWeight = 0.125f;
mask.VertexWeight(0) = vWeight;
//
// NOTE -- at some point the sharpness vector was optional, and topology would be used
// to identify a boundary crease. We are currently no longer passing a null sharpness
// vector and may not support it in future, in which case this test can be removed:
//
if (edgeSharpness != 0) {
// Use the sharpness values to identify the crease edges:
for (int i = 0; i < valence; ++i) {
mask.EdgeWeight(i) = (edgeSharpness[i] > 0.0f) ? eWeight : 0.0f;
}
} else {
// Use the boundary edges (first and last) as the crease edges:
mask.EdgeWeight(0) = eWeight;
for (int i = 1; i < (valence - 1); ++i) {
mask.EdgeWeight(i) = 0.0f;
}
mask.EdgeWeight(valence-1) = eWeight;
for (int i = 0; i < valence; ++i) {
mask.EdgeWeight(i) = 0.0f;
}
mask.EdgeWeight(creaseEnds[0]) = eWeight;
mask.EdgeWeight(creaseEnds[1]) = eWeight;
}
template <>
@ -225,7 +211,21 @@ Scheme<SCHEME_CATMARK>::assignSmoothMaskForVertex(VERTEX const& vertex, MASK& ma
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_CATMARK>::assignBoundaryLimitMask(VERTEX const& vertex, MASK& posMask) const {
Scheme<SCHEME_CATMARK>::assignCornerLimitMask(VERTEX const& /* vertex */, MASK& posMask) const {
posMask.SetNumVertexWeights(1);
posMask.SetNumEdgeWeights(0);
posMask.SetNumFaceWeights(0);
posMask.SetFaceWeightsForFaceCenters(false);
posMask.VertexWeight(0) = 1.0f;
}
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_CATMARK>::assignCreaseLimitMask(VERTEX const& vertex, MASK& posMask,
int const creaseEnds[2]) const {
typedef typename MASK::Weight Weight;
@ -240,17 +240,17 @@ Scheme<SCHEME_CATMARK>::assignBoundaryLimitMask(VERTEX const& vertex, MASK& posM
Weight eWeight = 1.0f / 6.0f;
posMask.VertexWeight(0) = vWeight;
posMask.EdgeWeight(0) = eWeight;
for (int i = 1; i < valence - 1; ++i) {
for (int i = 0; i < valence; ++i) {
posMask.EdgeWeight(i) = 0.0f;
}
posMask.EdgeWeight(valence - 1) = eWeight;
posMask.EdgeWeight(creaseEnds[0]) = eWeight;
posMask.EdgeWeight(creaseEnds[1]) = eWeight;
}
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_CATMARK>::assignInteriorLimitMask(VERTEX const& vertex, MASK& posMask) const {
Scheme<SCHEME_CATMARK>::assignSmoothLimitMask(VERTEX const& vertex, MASK& posMask) const {
typedef typename MASK::Weight Weight;
@ -262,11 +262,16 @@ Scheme<SCHEME_CATMARK>::assignInteriorLimitMask(VERTEX const& vertex, MASK& posM
posMask.SetNumFaceWeights(valence);
posMask.SetFaceWeightsForFaceCenters(false);
// Probably a good idea to test for and assign the regular case as a special case:
// Specialize for the regular case:
Weight fWeight = 1.0f / 36.0f;
Weight eWeight = 1.0f / 9.0f;
Weight vWeight = 4.0f / 9.0f;
Weight fWeight = 1.0f / (Weight)(valence * (valence + 5.0f));
Weight eWeight = 4.0f * fWeight;
Weight vWeight = (Weight)(1.0f - valence * (eWeight + fWeight));
if (valence != 4) {
fWeight = 1.0f / (Weight)(valence * (valence + 5.0f));
eWeight = 4.0f * fWeight;
vWeight = (Weight)(1.0f - valence * (eWeight + fWeight));
}
posMask.VertexWeight(0) = vWeight;
for (int i = 0; i < valence; ++i) {
@ -282,26 +287,91 @@ Scheme<SCHEME_CATMARK>::assignInteriorLimitMask(VERTEX const& vertex, MASK& posM
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_CATMARK>::assignBoundaryLimitTangentMasks(VERTEX const& /* vertex */,
Scheme<SCHEME_CATMARK>::assignCornerLimitTangentMasks(VERTEX const& vertex,
MASK& tan1Mask, MASK& tan2Mask) const {
int valence = vertex.GetNumEdges();
tan1Mask.SetNumVertexWeights(1);
tan1Mask.SetNumEdgeWeights(0);
tan1Mask.SetNumEdgeWeights(valence);
tan1Mask.SetNumFaceWeights(0);
tan1Mask.SetFaceWeightsForFaceCenters(false);
tan1Mask.VertexWeight(0) = 0.0f;
tan2Mask.SetNumVertexWeights(1);
tan2Mask.SetNumEdgeWeights(0);
tan2Mask.SetNumEdgeWeights(valence);
tan2Mask.SetNumFaceWeights(0);
tan2Mask.SetFaceWeightsForFaceCenters(false);
tan2Mask.VertexWeight(0) = 0.0f;
// Should be at least 2 edges -- be sure to clear weights for any more:
tan1Mask.VertexWeight(0) = -1.0f;
tan1Mask.EdgeWeight(0) = 1.0f;
tan1Mask.EdgeWeight(1) = 0.0f;
tan2Mask.VertexWeight(0) = -1.0f;
tan2Mask.EdgeWeight(0) = 0.0f;
tan2Mask.EdgeWeight(1) = 1.0f;
for (int i = 2; i < valence; ++i) {
tan1Mask.EdgeWeight(i) = 0.0f;
tan2Mask.EdgeWeight(i) = 0.0f;
}
}
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_CATMARK>::assignInteriorLimitTangentMasks(VERTEX const& vertex,
Scheme<SCHEME_CATMARK>::assignCreaseLimitTangentMasks(VERTEX const& vertex,
MASK& tan1Mask, MASK& tan2Mask, int const creaseEnds[2]) const {
int valence = vertex.GetNumEdges();
tan1Mask.SetNumVertexWeights(1);
tan1Mask.SetNumEdgeWeights(valence);
tan1Mask.SetNumFaceWeights(0);
tan1Mask.SetFaceWeightsForFaceCenters(false);
tan2Mask.SetNumVertexWeights(1);
tan2Mask.SetNumEdgeWeights(valence);
tan2Mask.SetNumFaceWeights(0);
tan2Mask.SetFaceWeightsForFaceCenters(false);
// Specialize for the regular (boundary) case:
bool isRegular = (vertex.GetNumEdges() == 3);
if (isRegular) {
tan1Mask.VertexWeight(0) = 0.0f;
tan1Mask.EdgeWeight(0) = 1.0f;
tan1Mask.EdgeWeight(1) = 0.0f;
tan1Mask.EdgeWeight(2) = -1.0f;
tan2Mask.VertexWeight(0) = -1.0f;
tan2Mask.EdgeWeight(0) = 0.0f;
tan2Mask.EdgeWeight(1) = 1.0f;
tan2Mask.EdgeWeight(2) = 0.0f;
} else {
// First, the tangent along the crease:
tan1Mask.VertexWeight(0) = 0.0f;
for (int i = 0; i < valence; ++i) {
tan1Mask.EdgeWeight(i) = 0.0f;
}
tan1Mask.EdgeWeight(creaseEnds[0]) = 1.0f;
tan1Mask.EdgeWeight(creaseEnds[1]) = -1.0f;
// Second, the tangent across the interior faces:
// - just using an interior edge for now
// - ultimately need regular and extra-ordinary cases here:
//
tan2Mask.VertexWeight(0) = -1.0f;
for (int i = 0; i < valence; ++i) {
tan2Mask.EdgeWeight(i) = 0.0f;
}
tan2Mask.EdgeWeight((creaseEnds[0] + creaseEnds[1]) >> 1) = 1.0f;
}
}
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_CATMARK>::assignSmoothLimitTangentMasks(VERTEX const& vertex,
MASK& tan1Mask, MASK& tan2Mask) const {
typedef typename MASK::Weight Weight;

View File

@ -165,6 +165,10 @@ public:
float const* incidentEdgeSharpness,
float const* childEdgesSharpness) const;
void GetSharpEdgePairOfCrease(float const * incidentEdgeSharpness,
int incidentEdgeCount,
int sharpEdgePair[2]) const;
// Would these really help? Maybe only need Rules for the vertex-vertex case...
//
// Rule DetermineEdgeVertexRule(float parentEdgeSharpness) const;
@ -220,6 +224,20 @@ Crease::SubdivideVertexSharpness(float vertexSharpness) const {
return decrementSharpness(vertexSharpness);
}
inline void
Crease::GetSharpEdgePairOfCrease(float const * incidentEdgeSharpness, int incidentEdgeCount,
int sharpEdgePair[2]) const {
// Only to be called when a crease is present at a vertex -- exactly two sharp
// edges are expected here:
//
sharpEdgePair[0] = 0;
while (IsSmooth(incidentEdgeSharpness[sharpEdgePair[0]])) ++ sharpEdgePair[0];
sharpEdgePair[1] = incidentEdgeCount - 1;
while (IsSmooth(incidentEdgeSharpness[sharpEdgePair[1]])) -- sharpEdgePair[1];
}
} // end namespace sdc
} // end namespace OPENSUBDIV_VERSION

View File

@ -151,8 +151,8 @@ Scheme<SCHEME_LOOP>::assignCornerMaskForVertex(VERTEX const&, MASK& mask) const
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_LOOP>::assignCreaseMaskForVertex(VERTEX const& vertex, MASK& mask, float const edgeSharpness[]) const
{
Scheme<SCHEME_LOOP>::assignCreaseMaskForVertex(VERTEX const& vertex, MASK& mask,
int const creaseEnds[2]) const {
typedef typename MASK::Weight Weight;
int valence = vertex.GetNumEdges();
@ -166,10 +166,11 @@ Scheme<SCHEME_LOOP>::assignCreaseMaskForVertex(VERTEX const& vertex, MASK& mask,
Weight eWeight = 0.125f;
mask.VertexWeight(0) = vWeight;
for (int i = 0; i < valence; ++i) {
mask.EdgeWeight(i) = (edgeSharpness[i] > 0.0f) ? eWeight : 0.0f;
mask.EdgeWeight(i) = 0.0f;
}
mask.EdgeWeight(creaseEnds[0]) = eWeight;
mask.EdgeWeight(creaseEnds[1]) = eWeight;
}
template <>
@ -215,7 +216,21 @@ Scheme<SCHEME_LOOP>::assignSmoothMaskForVertex(VERTEX const& vertex, MASK& mask)
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_LOOP>::assignBoundaryLimitMask(VERTEX const& vertex, MASK& posMask) const {
Scheme<SCHEME_LOOP>::assignCornerLimitMask(VERTEX const& /* vertex */, MASK& posMask) const {
posMask.SetNumVertexWeights(1);
posMask.SetNumEdgeWeights(0);
posMask.SetNumFaceWeights(0);
posMask.SetFaceWeightsForFaceCenters(false);
posMask.VertexWeight(0) = 1.0f;
}
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_LOOP>::assignCreaseLimitMask(VERTEX const& vertex, MASK& posMask,
int const creaseEnds[2]) const {
typedef typename MASK::Weight Weight;
@ -226,21 +241,32 @@ Scheme<SCHEME_LOOP>::assignBoundaryLimitMask(VERTEX const& vertex, MASK& posMask
posMask.SetNumFaceWeights(0);
posMask.SetFaceWeightsForFaceCenters(false);
//
// The refinement mask for a crease vertex is (1/8, 3/4, 1/8) and for a crease
// edge is (1/2, 1/2) -- producing a uniform B-spline curve along the crease
// (boundary) whether the vertex or its crease is regular or not. The limit
// mask is therefore (1/6, 2/3, 1/6) for ALL cases.
//
// An alternative limit mask (1/5, 3/5, 1/5) is often published for use either
// for irregular crease vertices or for all crease/boundary vertices, but this
// is based on an alternate refinement mask for the edge -- (3/8, 5/8) versus
// the usual (1/2, 1/2) -- and will not produce the B-spline curve desired.
//
Weight vWeight = 4.0f / 6.0f;
Weight eWeight = 1.0f / 6.0f;
posMask.VertexWeight(0) = vWeight;
posMask.EdgeWeight(0) = eWeight;
for (int i = 1; i < valence - 1; ++i) {
for (int i = 0; i < valence; ++i) {
posMask.EdgeWeight(i) = 0.0f;
}
posMask.EdgeWeight(valence - 1) = eWeight;
posMask.EdgeWeight(creaseEnds[0]) = eWeight;
posMask.EdgeWeight(creaseEnds[1]) = eWeight;
}
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_LOOP>::assignInteriorLimitMask(VERTEX const& vertex, MASK& posMask) const {
Scheme<SCHEME_LOOP>::assignSmoothLimitMask(VERTEX const& vertex, MASK& posMask) const {
typedef typename MASK::Weight Weight;
@ -272,34 +298,224 @@ Scheme<SCHEME_LOOP>::assignInteriorLimitMask(VERTEX const& vertex, MASK& posMask
}
}
//
/*
// Limit masks for tangents:
//
// A note on tangent magnitudes:
//
// Several formulae exist for limit tangents at a vertex to accomodate the
// different topological configurations around the vertex. While these produce
// the desired direction, there is inconsistency in the resulting magnitudes.
// Ideally a regular mesh of uniformly shaped triangles with similar edge lengths
// should produce tangents of similar magnitudes throughout -- including corners
// and boundaries. So some of the common formulae for these are adjusted with
// scale factors.
//
// For uses where magnitude does not matter, this scaling should be irrelevant.
// But just as with patches, where the magnitudes of partial derivates are
// consistent between similar patches, the magnitudes of limit tangents should
// also be similar.
//
// The reference tangents, in terms of magnitudes, are those produced by the
// limit tangent mask for smooth interior vertices, for which well established
// sin/cos formulae apply -- these remain unscaled. Formulae for the other
// crease/boundary, corner tangents and irregular cases are scaled to be more
// consistent with these.
//
// The crease/boundary tangents for the regular case can be viewed as derived
// from the smooth interior masks with two "phantom" points extrapolated across
// the regular boundary:
//
// v3 v2
// X - - - - - X
// / \ / \
// / \ / \
// v4 X - - - - - X - - - - - X v1
// . . 0 . .
// . . . .
// . . . .
// (v5) (v6)
//
// where v5 = v0 + (v4 - v3) and v6 = v0 + v1 - v2.
//
// When the standard limit tangent mask is applied, the cosines of increments
// of pi/3 gives us coefficients that are mutliples of 1/2, leading to the first
// tangent T1 = 3/2 * (v1 - v4), rather than the widely used T1 = v1 - v4. So
// this scale factor of 3/2 is applied to insure tangents along the boundaries
// are of similar magnitude as tangents in the immediate interior (which may be
// parallel).
//
// Tangents at corners are essentially a form of boundary tangent, and so its
// simple difference formula is scaled to be consistent with adjoining boundary
// tangents -- not just with the 3/2 factor from above, but with an additional
// 2.0 to compensate for the fact that the difference of only side of the vertex
// is considered here. The resulting scale factor of 3.0 for the regular corner
// is what similarly arises by extrapolating an interior region around the
// vertex and using the interior mask for the first tangent.
//
// The cross-tangent formula for the regular crease/boundary is similarly found
// from the above construction of the boundary, but the commonly used weights of
// +/- 1 and 2 result from omitting the common factor of sqrt(3)/2 (arising from
// the sines of increments of pi/3). With that scale factor close to one, it has
// less impact than the irregular cases, which are analogous to corner tangents
// in that differences on only one side of the vertex are considered. While a
// scaling of 3.0 is similarly understandable for the valence 2 and 3 cases, it is
// less obvious in the irregular formula for valence > 4, but similarly effective.
//
// The end result of these adjustments should be a set of limit tangents that are
// of similar magnitude over a regular mesh including boundaries and corners.
*/
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_LOOP>::assignBoundaryLimitTangentMasks(VERTEX const& /* vertex */,
Scheme<SCHEME_LOOP>::assignCornerLimitTangentMasks(VERTEX const& vertex,
MASK& tan1Mask, MASK& tan2Mask) const {
// Need to dig up formulae for this case...
int valence = vertex.GetNumEdges();
tan1Mask.SetNumVertexWeights(1);
tan1Mask.SetNumEdgeWeights(0);
tan1Mask.SetNumEdgeWeights(valence);
tan1Mask.SetNumFaceWeights(0);
tan1Mask.SetFaceWeightsForFaceCenters(false);
tan1Mask.VertexWeight(0) = 0.0f;
tan2Mask.SetNumVertexWeights(1);
tan2Mask.SetNumEdgeWeights(0);
tan2Mask.SetNumEdgeWeights(valence);
tan2Mask.SetNumFaceWeights(0);
tan2Mask.SetFaceWeightsForFaceCenters(false);
tan2Mask.VertexWeight(0) = 0.0f;
// See note above regarding scale factor of 3.0:
tan1Mask.VertexWeight(0) = -3.0f;
tan1Mask.EdgeWeight(0) = 3.0f;
tan1Mask.EdgeWeight(1) = 0.0f;
tan2Mask.VertexWeight(0) = -3.0f;
tan2Mask.EdgeWeight(0) = 0.0f;
tan2Mask.EdgeWeight(1) = 3.0f;
// Should be at least 2 edges -- be sure to clear weights for any more:
for (int i = 2; i < valence; ++i) {
tan1Mask.EdgeWeight(i) = 0.0f;
tan2Mask.EdgeWeight(i) = 0.0f;
}
}
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_LOOP>::assignInteriorLimitTangentMasks(VERTEX const& vertex,
Scheme<SCHEME_LOOP>::assignCreaseLimitTangentMasks(VERTEX const& vertex,
MASK& tan1Mask, MASK& tan2Mask, int const creaseEnds[2]) const {
typedef typename MASK::Weight Weight;
//
// First, the tangent along the crease:
// The first crease edge is considered the "leading" edge of the span
// of surface for which we are evaluating tangents and the second edge the
// "trailing edge". By convention, the tangent along the crease is oriented
// in the direction of the leading edge.
//
int valence = vertex.GetNumEdges();
tan1Mask.SetNumVertexWeights(1);
tan1Mask.SetNumEdgeWeights(valence);
tan1Mask.SetNumFaceWeights(0);
tan1Mask.SetFaceWeightsForFaceCenters(false);
tan1Mask.VertexWeight(0) = 0.0f;
for (int i = 0; i < valence; ++i) {
tan1Mask.EdgeWeight(i) = 0.0f;
}
// See the note above regarding scale factor of 1.5:
tan1Mask.EdgeWeight(creaseEnds[0]) = 1.5f;
tan1Mask.EdgeWeight(creaseEnds[1]) = -1.5f;
//
// Second, the tangent across the interior faces:
// Note this is ambigous for an interior vertex. We currently return
// the tangent for the surface in the counter-clockwise span between the
// leading and trailing edges that form the crease. Given the expected
// computation of a surface normal as Tan1 X Tan2, this tangent should be
// oriented "inward" from the crease/boundary -- across the surface rather
// than outward and away from it.
//
// There is inconsistency in the orientation of this tangent in commonly
// published results: the general formula provided for arbitrary valence
// has the tangent pointing across the crease and "outward" from the surface,
// while the special cases for regular valence and lower have the tangent
// pointing across the surface and "inward" from the crease. So if we are
// to consistently orient the first tangent along the crease, regardless of
// the interior topology, we have to correct this. With the first tangent
// following the direction of the leading crease edge, we want the second
// tangent pointing inward/across the surface -- so we flip the result of
// the general formula.
//
tan2Mask.SetNumVertexWeights(1);
tan2Mask.SetNumEdgeWeights(valence);
tan2Mask.SetNumFaceWeights(0);
tan2Mask.SetFaceWeightsForFaceCenters(false);
for (int i = 0; i < creaseEnds[0]; ++i) {
tan2Mask.EdgeWeight(i) = 0.0f;
}
int interiorEdgeCount = creaseEnds[1] - creaseEnds[0] - 1;
if (interiorEdgeCount == 2) {
// See note above regarding scale factor of (sin(60 degs) == sqrt(3)/2:
static Weight const Root3 = (Weight) 1.73205080756887729352f;
static Weight const Root3by2 = (Weight) (Root3 * 0.5);
tan2Mask.VertexWeight(0) = -Root3;
tan2Mask.EdgeWeight(creaseEnds[0]) = -Root3by2;
tan2Mask.EdgeWeight(creaseEnds[1]) = -Root3by2;
tan2Mask.EdgeWeight(creaseEnds[0] + 1) = Root3;
tan2Mask.EdgeWeight(creaseEnds[0] + 2) = Root3;
} else if (interiorEdgeCount > 2) {
// See notes above regarding scale factor of -3.0 (-1 for orientation,
// 2.0 for considering the region as a half-disk, and 1.5 in keeping
// with the crease tangent):
double theta = M_PI / (interiorEdgeCount + 1);
Weight cWeight = -3.0f * std::sin(theta);
Weight eWeightCoeff = -3.0f * (2.0f * std::cos(theta) - 2.0f);
tan2Mask.VertexWeight(0) = 0.0f;
tan2Mask.EdgeWeight(creaseEnds[0]) = cWeight;
tan2Mask.EdgeWeight(creaseEnds[1]) = cWeight;
for (int i = 1; i <= interiorEdgeCount; ++i) {
tan2Mask.EdgeWeight(creaseEnds[0] + i) = eWeightCoeff * std::sin(i * theta);
}
} else if (interiorEdgeCount == 1) {
// See notes above regarding scale factor of 3.0:
tan2Mask.VertexWeight(0) = -3.0f;
tan2Mask.EdgeWeight(creaseEnds[0]) = 0.0f;
tan2Mask.EdgeWeight(creaseEnds[1]) = 0.0f;
tan2Mask.EdgeWeight(creaseEnds[0] + 1) = 3.0f;
} else {
// See notes above regarding scale factor of 3.0:
tan2Mask.VertexWeight(0) = -6.0f;
tan2Mask.EdgeWeight(creaseEnds[0]) = 3.0f;
tan2Mask.EdgeWeight(creaseEnds[1]) = 3.0f;
}
for (int i = creaseEnds[1] + 1; i < valence; ++i) {
tan2Mask.EdgeWeight(i) = 0.0f;
}
}
template <>
template <typename VERTEX, typename MASK>
inline void
Scheme<SCHEME_LOOP>::assignSmoothLimitTangentMasks(VERTEX const& vertex,
MASK& tan1Mask, MASK& tan2Mask) const {
typedef typename MASK::Weight Weight;
@ -320,11 +536,29 @@ Scheme<SCHEME_LOOP>::assignInteriorLimitTangentMasks(VERTEX const& vertex,
tan1Mask.VertexWeight(0) = 0.0f;
tan2Mask.VertexWeight(0) = 0.0f;
Weight alpha = (Weight) (2.0f * M_PI / valence);
for (int i = 0; i < valence; ++i) {
double alphaI = alpha * i;
tan1Mask.EdgeWeight(i) = std::cos(alphaI);
tan2Mask.EdgeWeight(i) = std::sin(alphaI);
if (valence == 6) {
static Weight const Root3by2 = (Weight)(0.5f * 1.73205080756887729352f);
tan1Mask.EdgeWeight(0) = 1.0f;
tan1Mask.EdgeWeight(1) = 0.5f;
tan1Mask.EdgeWeight(2) = -0.5f;
tan1Mask.EdgeWeight(3) = -1.0f;
tan1Mask.EdgeWeight(4) = -0.5f;
tan1Mask.EdgeWeight(5) = 0.5f;
tan2Mask.EdgeWeight(0) = 0.0f;
tan2Mask.EdgeWeight(1) = Root3by2;
tan2Mask.EdgeWeight(2) = Root3by2;
tan2Mask.EdgeWeight(3) = 0.0f;
tan2Mask.EdgeWeight(4) = -Root3by2;
tan2Mask.EdgeWeight(5) = -Root3by2;
} else {
Weight alpha = (Weight) (2.0f * M_PI / valence);
for (int i = 0; i < valence; ++i) {
double alphaI = alpha * i;
tan1Mask.EdgeWeight(i) = std::cos(alphaI);
tan2Mask.EdgeWeight(i) = std::sin(alphaI);
}
}
}

Some files were not shown because too many files have changed in this diff Show More