mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-09 22:00:06 +00:00
Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
ed07ed6a8f
@ -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
126
README.md
@ -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
|
||||
|
||||
|
@ -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"
|
||||
)
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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)];
|
||||
}
|
||||
|
||||
|
@ -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
65
examples/glEvalLimit/glEvalLimit.cpp
Normal file → Executable 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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
759
examples/glImaging/glImaging.cpp
Executable 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;
|
||||
}
|
172
examples/glImaging/init_shapes.h
Normal file
172
examples/glImaging/init_shapes.h
Normal file
@ -0,0 +1,172 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
|
||||
#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 ) );
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
336
examples/glImaging/shader.glsl
Normal file
336
examples/glImaging/shader.glsl
Normal 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
|
697
examples/glImaging/stb_image_write.h
Normal file
697
examples/glImaging/stb_image_write.h
Normal 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
|
||||
*/
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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');
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
465
opensubdiv/far/endCapGregoryBasisPatchFactory.cpp
Normal file
465
opensubdiv/far/endCapGregoryBasisPatchFactory.cpp
Normal 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
|
153
opensubdiv/far/endCapGregoryBasisPatchFactory.h
Normal file
153
opensubdiv/far/endCapGregoryBasisPatchFactory.h
Normal 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
|
197
opensubdiv/far/endCapLegacyGregoryPatchFactory.cpp
Executable file
197
opensubdiv/far/endCapLegacyGregoryPatchFactory.cpp
Executable 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
|
||||
|
65
opensubdiv/far/endCapLegacyGregoryPatchFactory.h
Normal file
65
opensubdiv/far/endCapLegacyGregoryPatchFactory.h
Normal 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
|
278
opensubdiv/far/endCapRegularPatchFactory.cpp
Executable file
278
opensubdiv/far/endCapRegularPatchFactory.cpp
Executable 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
|
108
opensubdiv/far/endCapRegularPatchFactory.h
Normal file
108
opensubdiv/far/endCapRegularPatchFactory.h
Normal 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
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
@ -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 */
|
@ -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]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
@ -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 */
|
||||
|
213
opensubdiv/far/ptexIndices.cpp
Normal file
213
opensubdiv/far/ptexIndices.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
#include "../far/ptexIndices.h"
|
||||
|
||||
#include "../far/error.h"
|
||||
#include "../vtr/level.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
|
||||
PtexIndices::PtexIndices(TopologyRefiner const &refiner) {
|
||||
initializePtexIndices(refiner);
|
||||
}
|
||||
|
||||
PtexIndices::~PtexIndices() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PtexIndices::initializePtexIndices(TopologyRefiner const &refiner) {
|
||||
|
||||
int regFaceSize = Sdc::SchemeTypeTraits::GetRegularFaceSize(
|
||||
refiner.GetSchemeType());
|
||||
|
||||
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
|
106
opensubdiv/far/ptexIndices.h
Normal file
106
opensubdiv/far/ptexIndices.h
Normal file
@ -0,0 +1,106 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
// with the following modification; you may not use this file except in
|
||||
// compliance with the Apache License and the following modification to it:
|
||||
// Section 6. Trademarks. is deleted and replaced with:
|
||||
//
|
||||
// 6. Trademarks. This License does not grant permission to use the trade
|
||||
// names, trademarks, service marks, or product names of the Licensor
|
||||
// and its affiliates, except as required to comply with Section 4(c) of
|
||||
// the License and to reproduce the content of the NOTICE file.
|
||||
//
|
||||
// You may obtain a copy of the Apache License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the Apache License with the above modification is
|
||||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the Apache License for the specific
|
||||
// language governing permissions and limitations under the Apache License.
|
||||
//
|
||||
#ifndef 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 */
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 :
|
||||
|
@ -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];
|
||||
|
@ -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 *
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
180
opensubdiv/osd/d3d11Mesh.h
Normal file → Executable 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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user