From 4bf24d9b953ce39d96a89be756d0e525b206d7fd Mon Sep 17 00:00:00 2001 From: manuelk Date: Thu, 18 Apr 2013 19:55:05 -0700 Subject: [PATCH] First pass at our "Eval" API : this checkin is a mileston and is still missing code paths for certain types of feature adaptive patches. The check-in adds a new "limitEval" code example. More to come soon... fixes #45 --- examples/limitEval/CMakeLists.txt | 84 ++ examples/limitEval/main.cpp | 1132 +++++++++++++++++++++ opensubdiv/osd/CMakeLists.txt | 8 + opensubdiv/osd/cpuEvalLimitContext.cpp | 178 ++++ opensubdiv/osd/cpuEvalLimitContext.h | 359 +++++++ opensubdiv/osd/cpuEvalLimitController.cpp | 179 ++++ opensubdiv/osd/cpuEvalLimitController.h | 143 +++ opensubdiv/osd/cpuEvalLimitKernel.cpp | 427 ++++++++ opensubdiv/osd/cpuEvalLimitKernel.h | 96 ++ opensubdiv/osd/evalLimitContext.cpp | 75 ++ opensubdiv/osd/evalLimitContext.h | 117 +++ opensubdiv/osd/patch.h | 25 + opensubdiv/osd/vertexDescriptor.h | 21 +- 13 files changed, 2842 insertions(+), 2 deletions(-) create mode 100644 examples/limitEval/CMakeLists.txt create mode 100644 examples/limitEval/main.cpp create mode 100644 opensubdiv/osd/cpuEvalLimitContext.cpp create mode 100644 opensubdiv/osd/cpuEvalLimitContext.h create mode 100644 opensubdiv/osd/cpuEvalLimitController.cpp create mode 100644 opensubdiv/osd/cpuEvalLimitController.h create mode 100644 opensubdiv/osd/cpuEvalLimitKernel.cpp create mode 100644 opensubdiv/osd/cpuEvalLimitKernel.h create mode 100644 opensubdiv/osd/evalLimitContext.cpp create mode 100644 opensubdiv/osd/evalLimitContext.h diff --git a/examples/limitEval/CMakeLists.txt b/examples/limitEval/CMakeLists.txt new file mode 100644 index 00000000..779d2d5a --- /dev/null +++ b/examples/limitEval/CMakeLists.txt @@ -0,0 +1,84 @@ +# +# Copyright (C) Pixar. All rights reserved. +# +# This license governs use of the accompanying software. If you +# use the software, you accept this license. If you do not accept +# the license, do not use the software. +# +# 1. Definitions +# The terms "reproduce," "reproduction," "derivative works," and +# "distribution" have the same meaning here as under U.S. +# copyright law. A "contribution" is the original software, or +# any additions or changes to the software. +# A "contributor" is any person or entity that distributes its +# contribution under this license. +# "Licensed patents" are a contributor's patent claims that read +# directly on its contribution. +# +# 2. Grant of Rights +# (A) Copyright Grant- Subject to the terms of this license, +# including the license conditions and limitations in section 3, +# each contributor grants you a non-exclusive, worldwide, +# royalty-free copyright license to reproduce its contribution, +# prepare derivative works of its contribution, and distribute +# its contribution or any derivative works that you create. +# (B) Patent Grant- Subject to the terms of this license, +# including the license conditions and limitations in section 3, +# each contributor grants you a non-exclusive, worldwide, +# royalty-free license under its licensed patents to make, have +# made, use, sell, offer for sale, import, and/or otherwise +# dispose of its contribution in the software or derivative works +# of the contribution in the software. +# +# 3. Conditions and Limitations +# (A) No Trademark License- This license does not grant you +# rights to use any contributor's name, logo, or trademarks. +# (B) If you bring a patent claim against any contributor over +# patents that you claim are infringed by the software, your +# patent license from such contributor to the software ends +# automatically. +# (C) If you distribute any portion of the software, you must +# retain all copyright, patent, trademark, and attribution +# notices that are present in the software. +# (D) If you distribute any portion of the software in source +# code form, you may do so only under this license by including a +# complete copy of this license with your distribution. If you +# distribute any portion of the software in compiled or object +# code form, you may only do so under a license that complies +# with this license. +# (E) The software is licensed "as-is." You bear the risk of +# using it. The contributors give no express warranties, +# guarantees or conditions. You may have additional consumer +# rights under your local laws which this license cannot change. +# To the extent permitted under your local laws, the contributors +# exclude the implied warranties of merchantability, fitness for +# a particular purpose and non-infringement. +# + +# *** glViewer *** + +set(PLATFORM_LIBRARIES + ${OSD_LINK_TARGET} + ${GLEW_LIBRARY} + ${GLFW_LIBRARIES} +) + +include_directories( + ${PROJECT_SOURCE_DIR}/opensubdiv + ${PROJECT_SOURCE_DIR}/regression + ${GLEW_INCLUDE_DIR} + ${GLFW_INCLUDE_DIR} +) + +add_executable(limitEval + main.cpp + ../common/font_image.cpp + ../common/hud.cpp + ../common/gl_hud.cpp + ${INC_FILES} +) + +target_link_libraries(limitEval + ${PLATFORM_LIBRARIES} +) + diff --git a/examples/limitEval/main.cpp b/examples/limitEval/main.cpp new file mode 100644 index 00000000..1815090b --- /dev/null +++ b/examples/limitEval/main.cpp @@ -0,0 +1,1132 @@ +// +// Copyright (C) Pixar. All rights reserved. +// +// This license governs use of the accompanying software. If you +// use the software, you accept this license. If you do not accept +// the license, do not use the software. +// +// 1. Definitions +// The terms "reproduce," "reproduction," "derivative works," and +// "distribution" have the same meaning here as under U.S. +// copyright law. A "contribution" is the original software, or +// any additions or changes to the software. +// A "contributor" is any person or entity that distributes its +// contribution under this license. +// "Licensed patents" are a contributor's patent claims that read +// directly on its contribution. +// +// 2. Grant of Rights +// (A) Copyright Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free copyright license to reproduce its contribution, +// prepare derivative works of its contribution, and distribute +// its contribution or any derivative works that you create. +// (B) Patent Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free license under its licensed patents to make, have +// made, use, sell, offer for sale, import, and/or otherwise +// dispose of its contribution in the software or derivative works +// of the contribution in the software. +// +// 3. Conditions and Limitations +// (A) No Trademark License- This license does not grant you +// rights to use any contributor's name, logo, or trademarks. +// (B) If you bring a patent claim against any contributor over +// patents that you claim are infringed by the software, your +// patent license from such contributor to the software ends +// automatically. +// (C) If you distribute any portion of the software, you must +// retain all copyright, patent, trademark, and attribution +// notices that are present in the software. +// (D) If you distribute any portion of the software in source +// code form, you may do so only under this license by including a +// complete copy of this license with your distribution. If you +// distribute any portion of the software in compiled or object +// code form, you may only do so under a license that complies +// with this license. +// (E) The software is licensed "as-is." You bear the risk of +// using it. The contributors give no express warranties, +// guarantees or conditions. You may have additional consumer +// rights under your local laws which this license cannot change. +// To the extent permitted under your local laws, the contributors +// exclude the implied warranties of merchantability, fitness for +// a particular purpose and non-infringement. +// + +#if defined(__APPLE__) + #include + #define GLFW_INCLUDE_GL3 + #define GLFW_NO_GLU +#else + #include + #include + #if defined(WIN32) + #include + #endif +#endif + +#if defined(GLFW_VERSION_3) + #include + GLFWwindow* g_window=0; + GLFWmonitor* g_primary=0; +#else + #include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../common/stopwatch.h" +#include "../common/simple_math.h" +#include "../common/gl_hud.h" + +#include +#include +#include +#include +#include + +#ifdef OPENSUBDIV_HAS_OPENMP + #include +#endif + +using namespace OpenSubdiv; + +//------------------------------------------------------------------------------ +typedef HbrMesh OsdHbrMesh; +typedef HbrVertex OsdHbrVertex; +typedef HbrFace OsdHbrFace; +typedef HbrHalfedge OsdHbrHalfedge; + +typedef FarMesh OsdFarMesh; +typedef FarMeshFactory OsdFarMeshFactory; +typedef FarSubdivisionTables OsdFarMeshSubdivision; + +//------------------------------------------------------------------------------ +struct SimpleShape { + std::string name; + Scheme scheme; + std::string data; + + SimpleShape() { } + SimpleShape( std::string const & idata, char const * iname, Scheme ischeme ) + : name(iname), scheme(ischeme), data(idata) { } +}; + +std::vector g_defaultShapes; + +std::vector g_orgPositions, + g_positions; + +int g_currentShape = 0, + g_level = 3, + g_numElements = 3; + +std::vector g_coarseEdges; +std::vector g_coarseEdgeSharpness; +std::vector g_coarseVertexSharpness; + +int g_running = 1, + g_width = 1024, + g_height = 1024, + g_fullscreen = 0, + g_drawCageEdges = 1, + g_drawCageVertices = 0, + g_prev_x = 0, + g_prev_y = 0, + g_mbutton[3] = {0, 0, 0}, + g_frame=0, + g_freeze=0, + g_repeatCount; + +float g_rotate[2] = {0, 0}, + g_dolly = 5, + g_pan[2] = {0, 0}, + g_center[3] = {0, 0, 0}, + g_size = 0, + g_moveScale = 0.0f; + +GLuint g_transformUB = 0, + g_transformBinding = 0; + +struct Transform { + float ModelViewMatrix[16]; + float ProjectionMatrix[16]; + float ModelViewProjectionMatrix[16]; +} g_transformData; + + +// performance +float g_evalTime = 0; +float g_computeTime = 0; +Stopwatch g_fpsTimer; + +//------------------------------------------------------------------------------ +static void +initializeShapes( ) { + +#include + g_defaultShapes.push_back(SimpleShape(catmark_cube_corner0, "catmark_cube_corner0", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_cube_corner1, "catmark_cube_corner1", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_cube_corner2, "catmark_cube_corner2", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_cube_corner3, "catmark_cube_corner3", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_cube_corner4, "catmark_cube_corner4", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_cube_creases0, "catmark_cube_creases0", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_cube_creases1, "catmark_cube_creases1", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_cube, "catmark_cube", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_dart_edgecorner, "catmark_dart_edgecorner", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_dart_edgeonly, "catmark_dart_edgeonly", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_edgecorner ,"catmark_edgecorner", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_edgeonly, "catmark_edgeonly", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_gregory_test1, "catmark_gregory_test1", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_gregory_test2, "catmark_gregory_test2", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_gregory_test3, "catmark_gregory_test3", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_gregory_test4, "catmark_gregory_test4", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_hole_test1, "catmark_hole_test1", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_hole_test2, "catmark_hole_test2", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_pyramid_creases0, "catmark_pyramid_creases0", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_pyramid_creases1, "catmark_pyramid_creases1", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_pyramid, "catmark_pyramid", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_tent_creases0, "catmark_tent_creases0", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_tent_creases1, "catmark_tent_creases1", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_tent, "catmark_tent", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_torus, "catmark_torus", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_torus_creases0, "catmark_torus_creases0", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_square_hedit0, "catmark_square_hedit0", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_square_hedit1, "catmark_square_hedit1", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_square_hedit2, "catmark_square_hedit2", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_square_hedit3, "catmark_square_hedit3", kCatmark)); + +#include + g_defaultShapes.push_back(SimpleShape(catmark_square_hedit4, "catmark_square_hedit4", kCatmark)); + + + +} + +//------------------------------------------------------------------------------ +OsdCpuVertexBuffer * g_samplesVB=0; + +int g_nsamples=1000, + g_nsamplesFound=0; + +GLuint g_cageEdgeVAO = 0, + g_cageEdgeVBO = 0, + g_cageVertexVAO = 0, + g_cageVertexVBO = 0, + g_samplesVAO=0; + +GLhud g_hud; + +//------------------------------------------------------------------------------ +static void +createCoarseMesh( OsdHbrMesh * const hmesh, int nfaces ) { + // save coarse topology (used for coarse mesh drawing) + g_coarseEdges.clear(); + g_coarseEdgeSharpness.clear(); + g_coarseVertexSharpness.clear(); + + for(int i=0; iGetFace(i); + int nv = face->GetNumVertices(); + for(int j=0; jGetVertex(j)->GetID()); + g_coarseEdges.push_back(face->GetVertex((j+1)%nv)->GetID()); + g_coarseEdgeSharpness.push_back(face->GetEdge(j)->GetSharpness()); + } + } + int nv = hmesh->GetNumVertices(); + for(int i=0; iGetVertex(i)->GetSharpness()); + } +} + +//------------------------------------------------------------------------------ +static int +createRandomSamples( int nfaces, int nsamples, std::vector & coords ) { + + coords.resize(nfaces * nsamples); + + OsdEvalCoords * coord = &coords[0]; + + // large Pell prime number + srand( static_cast(2147483647) ); + + for (int i=0; iface = i; + coord->u = (float)rand()/(float)RAND_MAX; + coord->v = (float)rand()/(float)RAND_MAX; + ++coord; + } + } + + return (int)coords.size(); +} + +//------------------------------------------------------------------------------ +static int +getNumPtexFaces( OsdHbrMesh const * hmesh, int nfaces ) { + + OsdHbrFace * lastface = hmesh->GetFace( nfaces-1 ); + assert(lastface); + + int result = lastface->GetPtexIndex(); + + result += (hmesh->GetSubdivision()->FaceIsExtraordinary(hmesh, lastface) ? + lastface->GetNumVertices() : 0); + + return ++result; +} + +//------------------------------------------------------------------------------ +OsdCpuComputeContext * g_computeCtx = 0; + +OsdCpuComputeController g_computeCtrl; + +OsdCpuEvalLimitContext * g_evalCtx = 0; + +OsdCpuEvalLimitController g_evalCtrl; + +OsdVertexBufferDescriptor g_idesc( /*offset*/ 0, /*legnth*/ 3, /*stride*/ 3 ), + g_odesc( /*offset*/ 0, /*legnth*/ 3, /*stride*/ 6 ); + +std::vector g_coords; + +OsdCpuGLVertexBuffer * g_Q=0, + * g_dQu=0, + * g_dQv=0; + +OsdFarMesh * g_fmesh=0; + +//------------------------------------------------------------------------------ +static void +updateGeom() { + + int nverts = (int)g_orgPositions.size() / 3; + + const float *p = &g_orgPositions[0]; + + float r = sin(g_frame*0.001f) * g_moveScale; + + for (int i = 0; i < nverts; ++i) { + //float move = 0.05f*cosf(p[0]*20+g_frame*0.01f); + float ct = cos(p[2] * r); + float st = sin(p[2] * r); + g_positions[i*3+0] = p[0]*ct + p[1]*st; + g_positions[i*3+1] = -p[0]*st + p[1]*ct; + g_positions[i*3+2] = p[2]; + p+=3; + } + + // Run Compute pass to pose the control vertices --------------------------- + Stopwatch s; + s.Start(); + + g_samplesVB->UpdateData( &g_positions[0], 0, nverts); + + g_computeCtrl.Refine( g_computeCtx, g_fmesh->GetKernelBatches(), g_samplesVB ); + + s.Stop(); + g_computeTime = float(s.GetElapsed() * 1000.0f); + + + // Run Eval pass to get the samples locations ------------------------------ + + s.Start(); + + // Reset the output buffer + float * cpubuff = g_Q->BindCpuBuffer(); + memset( cpubuff, 0, g_Q->GetNumVertices()*g_Q->GetNumElements()*sizeof(float) ); + + g_nsamplesFound=0; + + // Bind/Unbind of the vertex buffers to the context needs to happen + // outside of the parallel loop + g_evalCtx->BindVertexBuffers( g_idesc, g_samplesVB, g_odesc, g_Q, g_dQu, g_dQv ); + +#ifdef OPENSUBDIV_HAS_OPENMP + #pragma omp parallel for +#endif + for (int i=0; i<(int)g_coords.size(); ++i) { + + int n = g_evalCtrl.EvalLimitSample( g_coords[i], g_evalCtx, i ); + + if (n) { + + // point colors + float * color = cpubuff + i * 6 + 3; + + color[0] = g_coords[i].u; + color[1] = 0.0f; + color[2] = g_coords[i].v; + +#pragma omp atomic + g_nsamplesFound += n; + } + } + + g_evalCtx->UnbindVertexBuffers(); + + g_Q->BindVBO(); + + s.Stop(); + + g_evalTime = float(s.GetElapsed() * 1000.0f); +} + +//------------------------------------------------------------------------------ +static void +createOsdMesh( const std::string &shape, int level, Scheme scheme=kCatmark ) { + + // Create HBR mesh + OsdHbrMesh * hmesh = simpleHbr(shape.c_str(), scheme, g_orgPositions); + + g_positions.resize(g_orgPositions.size(),0.0f); + + int nfaces = hmesh->GetNumFaces(), + nptexfaces = getNumPtexFaces(hmesh, nfaces); + + // Generate sample locations + int nsamples = createRandomSamples( nptexfaces, g_nsamples, g_coords ); + + createCoarseMesh(hmesh, nfaces); + + + + // Create FAR mesh + OsdFarMeshFactory factory( hmesh, level, /*adaptive*/ true); + + delete g_fmesh; + g_fmesh = factory.Create( /*ptex*/ true, /*fvar*/ false); + + int nverts = g_fmesh->GetNumVertices(); + + + + // Create v-buffer & populate w/ positions + delete g_samplesVB; + g_samplesVB = OsdCpuVertexBuffer::Create(3, nverts); + + + + // Create a Compute context, used to "pose" the vertices + delete g_computeCtx; + g_computeCtx = OsdCpuComputeContext::Create(g_fmesh); + + g_computeCtrl.Refine( g_computeCtx, g_fmesh->GetKernelBatches(), g_samplesVB ); + + + + // Create eval context & data buffers + delete g_evalCtx; + g_evalCtx = OsdCpuEvalLimitContext::Create(g_fmesh); + + delete g_Q; + g_Q = OsdCpuGLVertexBuffer::Create(6,nsamples); + + delete g_dQu; + g_dQu = OsdCpuGLVertexBuffer::Create(6,nsamples); + + delete g_dQv; + g_dQv = OsdCpuGLVertexBuffer::Create(6,nsamples); + + updateGeom(); + + // Bind g_Q as a GL_POINTS VBO + glBindVertexArray(g_samplesVAO); + + glBindBuffer(GL_ARRAY_BUFFER, g_Q->BindVBO()); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, 0); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, (float*)12); + + glBindVertexArray(0); +} + +//------------------------------------------------------------------------------ +struct Program +{ + GLuint program; + GLuint uniformModelViewProjectionMatrix; + GLuint attrPosition; + GLuint attrColor; +} g_defaultProgram; + +//------------------------------------------------------------------------------ +static void +checkGLErrors(std::string const & where = "") +{ + GLuint err; + while ((err = glGetError()) != GL_NO_ERROR) { + + std::cerr << "GL error: " + << (where.empty() ? "" : where + " ") + << err << "\n"; + } +} + +//------------------------------------------------------------------------------ +static GLuint +compileShader(GLenum shaderType, const char *source) +{ + GLuint shader = glCreateShader(shaderType); + glShaderSource(shader, 1, &source, NULL); + glCompileShader(shader); + checkGLErrors("compileShader"); + return shader; +} + +//------------------------------------------------------------------------------ +static bool +linkDefaultProgram() +{ +#if defined(GL_ARB_tessellation_shader) || defined(GL_VERSION_4_0) + #define GLSL_VERSION_DEFINE "#version 400\n" +#else + #define GLSL_VERSION_DEFINE "#version 150\n" +#endif + + static const char *vsSrc = + GLSL_VERSION_DEFINE + "in vec3 position;\n" + "in vec3 color;\n" + "out vec4 fragColor;\n" + "uniform mat4 ModelViewProjectionMatrix;\n" + "void main() {\n" + " fragColor = vec4(color, 1);\n" + " gl_Position = ModelViewProjectionMatrix * " + " vec4(position, 1);\n" + "}\n"; + + static const char *fsSrc = + GLSL_VERSION_DEFINE + "in vec4 fragColor;\n" + "out vec4 color;\n" + "void main() {\n" + " color = fragColor;\n" + "}\n"; + + GLuint program = glCreateProgram(); + GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vsSrc); + GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fsSrc); + + glAttachShader(program, vertexShader); + glAttachShader(program, fragmentShader); + + glLinkProgram(program); + + GLint status; + glGetProgramiv(program, GL_LINK_STATUS, &status); + if (status == GL_FALSE) { + GLint infoLogLength; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength); + char *infoLog = new char[infoLogLength]; + glGetProgramInfoLog(program, infoLogLength, NULL, infoLog); + printf("%s\n", infoLog); + delete[] infoLog; + exit(1); + } + + g_defaultProgram.program = program; + g_defaultProgram.uniformModelViewProjectionMatrix = + glGetUniformLocation(program, "ModelViewProjectionMatrix"); + g_defaultProgram.attrPosition = glGetAttribLocation(program, "position"); + g_defaultProgram.attrColor = glGetAttribLocation(program, "color"); + + return true; +} + +//------------------------------------------------------------------------------ +static inline void +setSharpnessColor(float s, float *r, float *g, float *b) +{ + // 0.0 2.0 4.0 + // green --- yellow --- red + *r = std::min(1.0f, s * 0.5f); + *g = std::min(1.0f, 2.0f - s*0.5f); + *b = 0; +} + +//------------------------------------------------------------------------------ +static void +drawCageEdges() { + + glUseProgram(g_defaultProgram.program); + glUniformMatrix4fv(g_defaultProgram.uniformModelViewProjectionMatrix, + 1, GL_FALSE, g_transformData.ModelViewProjectionMatrix); + + std::vector vbo; + vbo.reserve(g_coarseEdges.size() * 6); + float r, g, b; + for (int i = 0; i < (int)g_coarseEdges.size(); i+=2) { + setSharpnessColor(g_coarseEdgeSharpness[i/2], &r, &g, &b); + for (int j = 0; j < 2; ++j) { + vbo.push_back(g_positions[g_coarseEdges[i+j]*3]); + vbo.push_back(g_positions[g_coarseEdges[i+j]*3+1]); + vbo.push_back(g_positions[g_coarseEdges[i+j]*3+2]); + vbo.push_back(r); + vbo.push_back(g); + vbo.push_back(b); + } + } + + glBindVertexArray(g_cageEdgeVAO); + + glBindBuffer(GL_ARRAY_BUFFER, g_cageEdgeVBO); + glBufferData(GL_ARRAY_BUFFER, (int)vbo.size() * sizeof(float), &vbo[0], + GL_STATIC_DRAW); + + glEnableVertexAttribArray(g_defaultProgram.attrPosition); + glEnableVertexAttribArray(g_defaultProgram.attrColor); + glVertexAttribPointer(g_defaultProgram.attrPosition, + 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, 0); + glVertexAttribPointer(g_defaultProgram.attrColor, + 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, (void*)12); + + glDrawArrays(GL_LINES, 0, (int)g_coarseEdges.size()); + + glBindVertexArray(0); + glUseProgram(0); +} + +//------------------------------------------------------------------------------ +static void +drawCageVertices() { + + glUseProgram(g_defaultProgram.program); + glUniformMatrix4fv(g_defaultProgram.uniformModelViewProjectionMatrix, + 1, GL_FALSE, g_transformData.ModelViewProjectionMatrix); + + int numPoints = (int)g_positions.size()/3; + std::vector vbo; + vbo.reserve(numPoints*6); + float r, g, b; + for (int i = 0; i < numPoints; ++i) { + setSharpnessColor(g_coarseVertexSharpness[i], &r, &g, &b); + vbo.push_back(g_positions[i*3+0]); + vbo.push_back(g_positions[i*3+1]); + vbo.push_back(g_positions[i*3+2]); + vbo.push_back(r); + vbo.push_back(g); + vbo.push_back(b); + } + + glBindVertexArray(g_cageVertexVAO); + + glBindBuffer(GL_ARRAY_BUFFER, g_cageVertexVBO); + glBufferData(GL_ARRAY_BUFFER, (int)vbo.size() * sizeof(float), &vbo[0], + GL_STATIC_DRAW); + + glEnableVertexAttribArray(g_defaultProgram.attrPosition); + glEnableVertexAttribArray(g_defaultProgram.attrColor); + glVertexAttribPointer(g_defaultProgram.attrPosition, + 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, 0); + glVertexAttribPointer(g_defaultProgram.attrColor, + 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, (void*)12); + + glPointSize(10.0f); + glDrawArrays(GL_POINTS, 0, numPoints); + glPointSize(1.0f); + + glBindVertexArray(0); + glUseProgram(0); +} + +//------------------------------------------------------------------------------ +static void +drawSamples() { + + glUseProgram(g_defaultProgram.program); + + glUniformMatrix4fv(g_defaultProgram.uniformModelViewProjectionMatrix, + 1, GL_FALSE, g_transformData.ModelViewProjectionMatrix); + + + glBindVertexArray(g_samplesVAO); + + glPointSize(1.0f); + glDrawArrays( GL_POINTS, 0, (int)g_coords.size() ); + glPointSize(1.0f); + + glBindVertexArray(0); + + glUseProgram(0); +} + +//------------------------------------------------------------------------------ +static void +display() { + Stopwatch s; + s.Start(); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glViewport(0, 0, g_width, g_height); + + double aspect = g_width/(double)g_height; + identity(g_transformData.ModelViewMatrix); + translate(g_transformData.ModelViewMatrix, -g_pan[0], -g_pan[1], -g_dolly); + rotate(g_transformData.ModelViewMatrix, g_rotate[1], 1, 0, 0); + rotate(g_transformData.ModelViewMatrix, g_rotate[0], 0, 1, 0); + rotate(g_transformData.ModelViewMatrix, -90, 1, 0, 0); + translate(g_transformData.ModelViewMatrix, + -g_center[0], -g_center[1], -g_center[2]); + perspective(g_transformData.ProjectionMatrix, + 45.0f, (float)aspect, 0.01f, 500.0f); + multMatrix(g_transformData.ModelViewProjectionMatrix, + g_transformData.ModelViewMatrix, + g_transformData.ProjectionMatrix); + + s.Stop(); + float drawCpuTime = float(s.GetElapsed() * 1000.0f); + s.Start(); + glFinish(); + s.Stop(); + float drawGpuTime = float(s.GetElapsed() * 1000.0f); + + drawSamples(); + + if (g_drawCageEdges) + drawCageEdges(); + + if (g_drawCageVertices) + drawCageVertices(); + + if (g_hud.IsVisible()) { + g_fpsTimer.Stop(); + double fps = 1.0/g_fpsTimer.GetElapsed(); + g_fpsTimer.Start(); + + g_hud.DrawString(10, -120, "# Samples : (%d/%d)", g_nsamplesFound, g_Q->GetNumVertices()); + g_hud.DrawString(10, -100, "Compute : %.3f ms", g_computeTime); + g_hud.DrawString(10, -80, "Eval : %.3f ms", g_evalTime); + g_hud.DrawString(10, -60, "GPU Draw : %.3f ms", drawGpuTime); + g_hud.DrawString(10, -40, "CPU Draw : %.3f ms", drawCpuTime); + g_hud.DrawString(10, -20, "FPS : %3.1f", fps); + + g_hud.Flush(); + } + + glFinish(); + + checkGLErrors("display leave"); +} + +//------------------------------------------------------------------------------ +static void +idle() { + + if (not g_freeze) + g_frame++; + + updateGeom(); + + if (g_repeatCount != 0 and g_frame >= g_repeatCount) + g_running = 0; +} + +//------------------------------------------------------------------------------ +static void +#if GLFW_VERSION_MAJOR>=3 +motion(GLFWwindow *, double dx, double dy) { + int x=(int)dx, y=(int)dy; +#else +motion(int x, int y) { +#endif + + if (g_mbutton[0] && !g_mbutton[1] && !g_mbutton[2]) { + // orbit + g_rotate[0] += x - g_prev_x; + g_rotate[1] += y - g_prev_y; + } else if (!g_mbutton[0] && !g_mbutton[1] && g_mbutton[2]) { + // pan + g_pan[0] -= g_dolly*(x - g_prev_x)/g_width; + g_pan[1] += g_dolly*(y - g_prev_y)/g_height; + } else if ((g_mbutton[0] && !g_mbutton[1] && g_mbutton[2]) or + (!g_mbutton[0] && g_mbutton[1] && !g_mbutton[2])) { + // dolly + g_dolly -= g_dolly*0.01f*(x - g_prev_x); + if(g_dolly <= 0.01) g_dolly = 0.01f; + } + + g_prev_x = x; + g_prev_y = y; +} + +//------------------------------------------------------------------------------ +static void +#if GLFW_VERSION_MAJOR>=3 +mouse(GLFWwindow *, int button, int state) { +#else +mouse(int button, int state) { +#endif + + if (button == 0 && state == GLFW_PRESS && g_hud.MouseClick(g_prev_x, g_prev_y)) + return; + + if (button < 3) { + g_mbutton[button] = (state == GLFW_PRESS); + } +} + +//------------------------------------------------------------------------------ +static void +#if GLFW_VERSION_MAJOR>=3 +reshape(GLFWwindow *, int width, int height) { +#else +reshape(int width, int height) { +#endif + + g_width = width; + g_height = height; + + g_hud.Rebuild(width, height); +} + +//------------------------------------------------------------------------------ +#if GLFW_VERSION_MAJOR>=3 +void windowClose(GLFWwindow*) { + g_running = false; +} +#else +int windowClose() { + g_running = false; + return GL_TRUE; +} +#endif + +//------------------------------------------------------------------------------ +static void +setSamples(bool add) +{ + g_nsamples += add ? 1000 : -1000; + + g_nsamples = std::max(0, g_nsamples); + + createOsdMesh( g_defaultShapes[g_currentShape].data, g_level, g_defaultShapes[ g_currentShape ].scheme ); +} + +//------------------------------------------------------------------------------ +static void +#if GLFW_VERSION_MAJOR>=3 +keyboard(GLFWwindow *, int key, int event) { +#else +keyboard(int key, int event) { +#endif + + if (event == GLFW_RELEASE) return; + if (g_hud.KeyDown(tolower(key))) return; + + switch (key) { + case 'Q': g_running = 0; break; + + case '=': setSamples(true); break; + + case '-': setSamples(false); break; + + case GLFW_KEY_ESC: g_hud.SetVisible(!g_hud.IsVisible()); break; + } +} + +//------------------------------------------------------------------------------ +static void +callbackError(OpenSubdiv::OsdErrorType err, const char *message) +{ + printf("OsdError: %d\n", err); + printf("%s", message); +} + +//------------------------------------------------------------------------------ +static void +callbackModel(int m) +{ + if (m < 0) + m = 0; + + if (m >= (int)g_defaultShapes.size()) + m = (int)g_defaultShapes.size() - 1; + + g_currentShape = m; + + createOsdMesh( g_defaultShapes[m].data, g_level, g_defaultShapes[ g_currentShape ].scheme ); +} + +//------------------------------------------------------------------------------ +static void +callbackLevel(int l) +{ + g_level = l; + createOsdMesh( g_defaultShapes[g_currentShape].data, g_level, g_defaultShapes[ g_currentShape ].scheme ); +} + +//------------------------------------------------------------------------------ +static void +callbackAnimate(bool checked, int m) +{ + g_moveScale = checked; +} + +//------------------------------------------------------------------------------ +static void +callbackFreeze(bool checked, int f) +{ + g_freeze = checked; +} + +//------------------------------------------------------------------------------ +static void +initHUD() +{ + g_hud.Init(g_width, g_height); + + g_hud.AddCheckBox("Animate vertices (M)", g_moveScale != 0, 350, 20, callbackAnimate, 0, 'm'); + g_hud.AddCheckBox("Freeze (spc)", false, 350, 40, callbackFreeze, 0, ' '); + + for (int i = 1; i < 11; ++i) { + char level[16]; + sprintf(level, "Lv. %d", i); + g_hud.AddRadioButton(3, level, i==g_level, 10, 170+i*20, callbackLevel, i, '0'+(i%10)); + } + + for (int i = 0; i < (int)g_defaultShapes.size(); ++i) { + g_hud.AddRadioButton(4, g_defaultShapes[i].name.c_str(), i==0, -220, 10+i*16, callbackModel, i, 'n'); + } +} + +//------------------------------------------------------------------------------ +static void +initGL() +{ + glClearColor(0.1f, 0.1f, 0.1f, 1.0f); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glCullFace(GL_BACK); + glEnable(GL_CULL_FACE); + + glGenVertexArrays(1, &g_cageVertexVAO); + glGenVertexArrays(1, &g_cageEdgeVAO); + glGenVertexArrays(1, &g_samplesVAO); + glGenBuffers(1, &g_cageVertexVBO); + glGenBuffers(1, &g_cageEdgeVBO); +} + +//------------------------------------------------------------------------------ +static void +uninitGL() { + + glDeleteBuffers(1, &g_cageVertexVBO); + glDeleteBuffers(1, &g_cageEdgeVBO); + glDeleteVertexArrays(1, &g_cageVertexVAO); + glDeleteVertexArrays(1, &g_cageEdgeVAO); + glDeleteVertexArrays(1, &g_samplesVAO); +} + +//------------------------------------------------------------------------------ +static void +setGLCoreProfile() +{ +#if GLFW_VERSION_MAJOR>=3 + #define glfwOpenWindowHint glfwWindowHint + #define GLFW_OPENGL_VERSION_MAJOR GLFW_CONTEXT_VERSION_MAJOR + #define GLFW_OPENGL_VERSION_MINOR GLFW_CONTEXT_VERSION_MINOR +#endif + + glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); +#if not defined(__APPLE__) + glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 4); + glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 2); + glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); +#else + glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3); + glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 2); +#endif + +} + +//------------------------------------------------------------------------------ +int main(int, char**) { + + bool fullscreen = false; + + OsdSetErrorCallback(callbackError); + + initializeShapes(); + + if (not glfwInit()) { + printf("Failed to initialize GLFW\n"); + return 1; + } + + static const char windowTitle[] = "OpenSubdiv evalViewer"; + +#define CORE_PROFILE +#ifdef CORE_PROFILE + setGLCoreProfile(); +#endif + +#if GLFW_VERSION_MAJOR>=3 + if (fullscreen) { + + g_primary = glfwGetPrimaryMonitor(); + + // apparently glfwGetPrimaryMonitor fails under linux : if no primary, + // settle for the first one in the list + if (not g_primary) { + int count=0; + GLFWmonitor ** monitors = glfwGetMonitors(&count); + + if (count) + g_primary = monitors[0]; + } + + if (g_primary) { + GLFWvidmode vidmode = glfwGetVideoMode(g_primary); + g_width = vidmode.width; + g_height = vidmode.height; + } + } + + if (not (g_window=glfwCreateWindow(g_width, g_height, windowTitle, + fullscreen and g_primary ? g_primary : NULL, NULL))) { + printf("Failed to open window.\n"); + glfwTerminate(); + return 1; + } + glfwMakeContextCurrent(g_window); + glfwSetKeyCallback(g_window, keyboard); + glfwSetCursorPosCallback(g_window, motion); + glfwSetMouseButtonCallback(g_window, mouse); + glfwSetWindowSizeCallback(g_window, reshape); + glfwSetWindowCloseCallback(g_window, windowClose); +#else + if (glfwOpenWindow(g_width, g_height, 8, 8, 8, 8, 24, 8, + fullscreen ? GLFW_FULLSCREEN : GLFW_WINDOW) == GL_FALSE) { + printf("Failed to open window.\n"); + glfwTerminate(); + return 1; + } + glfwSetWindowTitle(windowTitle); + glfwSetKeyCallback(keyboard); + glfwSetMousePosCallback(motion); + glfwSetMouseButtonCallback(mouse); + glfwSetWindowSizeCallback(reshape); + glfwSetWindowCloseCallback(windowClose); +#endif + +#if not defined(__APPLE__) +#ifdef CORE_PROFILE + // this is the only way to initialize glew correctly under core profile context. + glewExperimental = true; +#endif + if (GLenum r = glewInit() != GLEW_OK) { + printf("Failed to initialize glew. Error = %s\n", glewGetErrorString(r)); + exit(1); + } +#ifdef CORE_PROFILE + // clear GL errors which was generated during glewInit() + glGetError(); +#endif +#endif + + //std::string & data = g_defaultShapes[ g_currentShape ].data; + //Scheme scheme = g_defaultShapes[ g_currentShape ].scheme; + + //createOsdMesh( data, g_level, scheme ); + + initGL(); + linkDefaultProgram(); + + glfwSwapInterval(0); + + initHUD(); + callbackModel(g_currentShape); + + while (g_running) { + idle(); + display(); + +#if GLFW_VERSION_MAJOR>=3 + glfwPollEvents(); + glfwSwapBuffers(g_window); +#else + glfwSwapBuffers(); +#endif + + glFinish(); + } + + uninitGL(); + glfwTerminate(); +} diff --git a/opensubdiv/osd/CMakeLists.txt b/opensubdiv/osd/CMakeLists.txt index 864815d0..05624e65 100644 --- a/opensubdiv/osd/CMakeLists.txt +++ b/opensubdiv/osd/CMakeLists.txt @@ -79,8 +79,12 @@ set(CPU_SOURCE_FILES cpuKernel.cpp cpuComputeController.cpp cpuComputeContext.cpp + cpuEvalLimitContext.cpp + cpuEvalLimitController.cpp + cpuEvalLimitKernel.cpp cpuVertexBuffer.cpp error.cpp + evalLimitContext.cpp drawContext.cpp drawRegistry.cpp sortedDrawContext.cpp @@ -98,14 +102,18 @@ set(INC_FILES set(PRIVATE_HEADER_FILES debug.h cpuKernel.h + cpuEvalLimitKernel.h ) set(PUBLIC_HEADER_FILES computeController.h cpuComputeContext.h cpuComputeController.h + cpuEvalLimitContext.h + cpuEvalLimitController.h cpuVertexBuffer.h error.h + evalLimitContext.h mesh.h nonCopyable.h drawContext.h diff --git a/opensubdiv/osd/cpuEvalLimitContext.cpp b/opensubdiv/osd/cpuEvalLimitContext.cpp new file mode 100644 index 00000000..e93a0ae6 --- /dev/null +++ b/opensubdiv/osd/cpuEvalLimitContext.cpp @@ -0,0 +1,178 @@ +// +// Copyright (C) Pixar. All rights reserved. +// +// This license governs use of the accompanying software. If you +// use the software, you accept this license. If you do not accept +// the license, do not use the software. +// +// 1. Definitions +// The terms "reproduce," "reproduction," "derivative works," and +// "distribution" have the same meaning here as under U.S. +// copyright law. A "contribution" is the original software, or +// any additions or changes to the software. +// A "contributor" is any person or entity that distributes its +// contribution under this license. +// "Licensed patents" are a contributor's patent claims that read +// directly on its contribution. +// +// 2. Grant of Rights +// (A) Copyright Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free copyright license to reproduce its contribution, +// prepare derivative works of its contribution, and distribute +// its contribution or any derivative works that you create. +// (B) Patent Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free license under its licensed patents to make, have +// made, use, sell, offer for sale, import, and/or otherwise +// dispose of its contribution in the software or derivative works +// of the contribution in the software. +// +// 3. Conditions and Limitations +// (A) No Trademark License- This license does not grant you +// rights to use any contributor's name, logo, or trademarks. +// (B) If you bring a patent claim against any contributor over +// patents that you claim are infringed by the software, your +// patent license from such contributor to the software ends +// automatically. +// (C) If you distribute any portion of the software, you must +// retain all copyright, patent, trademark, and attribution +// notices that are present in the software. +// (D) If you distribute any portion of the software in source +// code form, you may do so only under this license by including a +// complete copy of this license with your distribution. If you +// distribute any portion of the software in compiled or object +// code form, you may only do so under a license that complies +// with this license. +// (E) The software is licensed "as-is." You bear the risk of +// using it. The contributors give no express warranties, +// guarantees or conditions. You may have additional consumer +// rights under your local laws which this license cannot change. +// To the extent permitted under your local laws, the contributors +// exclude the implied warranties of merchantability, fitness for +// a particular purpose and non-infringement. +// + +#include "../osd/cpuEvalLimitContext.h" +#include "../osd/vertexDescriptor.h" + +#include +#include +#include +#include + +namespace OpenSubdiv { +namespace OPENSUBDIV_VERSION { + +OsdCpuEvalLimitContext * +OsdCpuEvalLimitContext::Create(FarMesh const * farmesh) { + + assert(farmesh); + + // we do not support uniform yet + if (not farmesh->GetPatchTables()) + return NULL; + + return new OsdCpuEvalLimitContext(farmesh); +} + +OsdCpuEvalLimitContext::OsdCpuEvalLimitContext(FarMesh const * farmesh) : + OsdEvalLimitContext(farmesh) { + + FarPatchTables const * patchTables = farmesh->GetPatchTables(); + assert(patchTables); + + _patchMap = new OsdCpuEvalLimitContext::PatchMap( *patchTables ); + + size_t npatches = patchTables->GetNumPatches(), + nvertices = patchTables->GetNumControlVertices(); + + _patchArrays.reserve(npatches); + + _patchBitFields.reserve(npatches); + + _patchBuffer.reserve(nvertices); + + + // Full regular patches + _AppendPatchArray(OsdPatchDescriptor(kRegular, 0, 0, 0, 0), + patchTables->GetFullRegularPatches(), + patchTables->GetFullRegularPtexCoordinates()); + + _AppendPatchArray(OsdPatchDescriptor(kBoundary, 0, 0, 0, 0), + patchTables->GetFullBoundaryPatches(), + patchTables->GetFullBoundaryPtexCoordinates()); + + _AppendPatchArray(OsdPatchDescriptor(kCorner, 0, 0, 0, 0), + patchTables->GetFullCornerPatches(), + patchTables->GetFullCornerPtexCoordinates()); + + _AppendPatchArray(OsdPatchDescriptor(kGregory, 0, 0, patchTables->GetMaxValence(), 0), + patchTables->GetFullGregoryPatches(), + patchTables->GetFullGregoryPtexCoordinates()); + + _AppendPatchArray(OsdPatchDescriptor(kBoundaryGregory, 0, 0, patchTables->GetMaxValence(), 0), + patchTables->GetFullBoundaryGregoryPatches(), + patchTables->GetFullBoundaryGregoryPtexCoordinates()); + + _vertexValenceBuffer = patchTables->GetVertexValenceTable(); + _quadOffsetBuffer = patchTables->GetQuadOffsetTable(); + + // Transition patches + for (int p=0; p<5; ++p) { + + _AppendPatchArray(OsdPatchDescriptor(kTransitionRegular, p, 0, 0, 0), + patchTables->GetTransitionRegularPatches(p), + patchTables->GetTransitionRegularPtexCoordinates(p)); + + for (int r=0; r<4; ++r) { + _AppendPatchArray(OsdPatchDescriptor(kTransitionBoundary, p, r, 0, 0), + patchTables->GetTransitionBoundaryPatches(p, r), + patchTables->GetTransitionBoundaryPtexCoordinates(p, r)); + + _AppendPatchArray(OsdPatchDescriptor(kTransitionCorner, p, r, 0, 0), + patchTables->GetTransitionCornerPatches(p, r), + patchTables->GetTransitionCornerPtexCoordinates(p, r)); + } + } + +} + +OsdCpuEvalLimitContext::~OsdCpuEvalLimitContext() { + delete _patchMap; +} + +int +OsdCpuEvalLimitContext::_AppendPatchArray( + OsdPatchDescriptor const & desc, + FarPatchTables::PTable const & pTable, + FarPatchTables::PtexCoordinateTable const & ptxTable ) +{ + if (pTable.first.empty() or ptxTable.empty()) + return 0; + + OsdPatchArray array; + array.desc = desc; + array.firstIndex = (int)_patchBuffer.size(); + array.numIndices = (int)pTable.first.size(); + array.gregoryQuadOffsetBase = 0; + //array.gregoryVertexValenceBase = gregoryQuadOffsetBase; + + // copy patch array descriptor + _patchArrays.push_back(array); + + // copy patches bitfields + for (int i=0; i<(int)ptxTable.size(); ++i) { + _patchBitFields.push_back( ptxTable[i].bitField ); + } + + // copy control vertices indices + _patchBuffer.insert( _patchBuffer.end(), pTable.first.begin(), pTable.first.end()); + + return 1; +} + +} // end namespace OPENSUBDIV_VERSION +} // end namespace OpenSubdiv diff --git a/opensubdiv/osd/cpuEvalLimitContext.h b/opensubdiv/osd/cpuEvalLimitContext.h new file mode 100644 index 00000000..dfc4c0e2 --- /dev/null +++ b/opensubdiv/osd/cpuEvalLimitContext.h @@ -0,0 +1,359 @@ +// +// Copyright (C) Pixar. All rights reserved. +// +// This license governs use of the accompanying software. If you +// use the software, you accept this license. If you do not accept +// the license, do not use the software. +// +// 1. Definitions +// The terms "reproduce," "reproduction," "derivative works," and +// "distribution" have the same meaning here as under U.S. +// copyright law. A "contribution" is the original software, or +// any additions or changes to the software. +// A "contributor" is any person or entity that distributes its +// contribution under this license. +// "Licensed patents" are a contributor's patent claims that read +// directly on its contribution. +// +// 2. Grant of Rights +// (A) Copyright Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free copyright license to reproduce its contribution, +// prepare derivative works of its contribution, and distribute +// its contribution or any derivative works that you create. +// (B) Patent Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free license under its licensed patents to make, have +// made, use, sell, offer for sale, import, and/or otherwise +// dispose of its contribution in the software or derivative works +// of the contribution in the software. +// +// 3. Conditions and Limitations +// (A) No Trademark License- This license does not grant you +// rights to use any contributor's name, logo, or trademarks. +// (B) If you bring a patent claim against any contributor over +// patents that you claim are infringed by the software, your +// patent license from such contributor to the software ends +// automatically. +// (C) If you distribute any portion of the software, you must +// retain all copyright, patent, trademark, and attribution +// notices that are present in the software. +// (D) If you distribute any portion of the software in source +// code form, you may do so only under this license by including a +// complete copy of this license with your distribution. If you +// distribute any portion of the software in compiled or object +// code form, you may only do so under a license that complies +// with this license. +// (E) The software is licensed "as-is." You bear the risk of +// using it. The contributors give no express warranties, +// guarantees or conditions. You may have additional consumer +// rights under your local laws which this license cannot change. +// To the extent permitted under your local laws, the contributors +// exclude the implied warranties of merchantability, fitness for +// a particular purpose and non-infringement. +// +#ifndef OSD_CPU_EVAL_LIMIT_CONTEXT_H +#define OSD_CPU_EVAL_LIMIT_CONTEXT_H + +#include "../version.h" + +#include "../osd/evalLimitContext.h" +#include "../osd/vertexDescriptor.h" + +#include +#include + +namespace OpenSubdiv { +namespace OPENSUBDIV_VERSION { + +class OsdCpuEvalLimitContext : public OsdEvalLimitContext { +public: + /// \brief Factory + /// Returns an EvalLimitContext from the given farmesh. + /// Note : the farmesh is expected to be feature-adaptive and have ptex + /// coordinates tables. + static OsdCpuEvalLimitContext * Create(FarMesh const * farmesh); + + /// Destructor + virtual ~OsdCpuEvalLimitContext(); + + + /// Binds the data buffers. + /// + /// @param inDesc vertex buffer data descriptor shared by all input data buffers + /// + /// @param inQ input vertex data + /// + /// @param outDesc vertex buffer data descriptor shared by all output data buffers + /// + /// @param outQ output vertex data + /// + /// @param outDQu optional output derivative along "u" of the vertex data + /// + /// @param outDQv optional output derivative along "v" of the vertex data + /// + template + void BindVertexBuffers( OsdVertexBufferDescriptor const & inDesc, VERTEX_BUFFER *inQ, + OsdVertexBufferDescriptor const & outDesc, OUTPUT_BUFFER *outQ, + OUTPUT_BUFFER *outdQu=0, + OUTPUT_BUFFER *outdQv=0) { + _inDesc = inDesc; + _inQ = inQ ? inQ->BindCpuBuffer() : 0; + + _outDesc = outDesc; + _outQ = outQ ? outQ->BindCpuBuffer() : 0 ; + _outdQu = outdQu ? outdQu->BindCpuBuffer() : 0 ; + _outdQv = outdQv ? outdQv->BindCpuBuffer() : 0 ; + } + + /// Unbind the data buffers + void UnbindVertexBuffers() { + _inQ = 0; + _outQ = 0; + _outdQu = 0; + _outdQv = 0; + } + + /// Returns the input vertex buffer descriptor + const OsdVertexBufferDescriptor & GetInputDesc() const { + return _inDesc; + } + + /// Returns the output vertex buffer descriptor + const OsdVertexBufferDescriptor & GetOutputDesc() const { + return _outDesc; + } + + /// Returns the input vertex buffer data + float const * GetInputVertexData() const { + return _inQ; + } + + /// Returns the output vertex buffer data + float * GetOutputVertexData() const { + return _outQ; + } + + /// Returns the U derivative of the output vertex buffer data + float * GetOutputVertexDataUDerivative() const { + return _outdQu; + } + + /// Returns the V derivative of the output vertex buffer data + float * GetOutputVertexDataVDerivative() const { + return _outdQv; + } + + /// Returns the vector of patch arrays + const OsdPatchArrayVector & GetPatchArrayVector() const { + return _patchArrays; + } + + /// Returns the vector of per-patch parametric data + const std::vector & GetPatchBitFields() const { + return _patchBitFields; + } + + /// The ordered array of control vertex indices for all the patches + const std::vector & GetControlVertices() const { + return _patchBuffer; + } + + /// XXXX + const int * GetVertexValenceBuffer() const { + return &_vertexValenceBuffer[0]; + } + + const unsigned int *GetQuadOffsetBuffer() const { + return &_quadOffsetBuffer[0]; + } + + /// Maps coarse-face ptex coordinates to children patches + struct PatchMap { + public: + + + /// \brief Returns the number and list of patch indices for a given face. + /// + /// PatchMaps map coarse faces to their childrn feature adaptive patches. + /// Coarse faces are indexed using their ptex face ID to resolve parametric + /// ambiguity on non-quad faces. Note : this "map" is actually a vector, so + /// queries are O(1) order. + /// + /// @param faceid the ptex face index to search for + /// + /// @param npatches the number of children patches found for the faceid + /// + /// @param patches a set of pointers to the individual patch handles + /// + bool GetChildPatchesHandles( int faceid, int * npatches, OsdPatchHandle const ** patches ) const { + + if (_handles.empty() or _offsets.empty() or (faceid>=(int)_offsets.size())) + return false; + + *npatches = (faceid==(int)_offsets.size()-1 ? (unsigned int)_handles.size()-1 : _offsets[faceid+1]) - _offsets[faceid] + 1; + + *patches = &_handles[ _offsets[faceid] ]; + + return true; + } + + private: + + friend class OsdCpuEvalLimitContext; + + typedef std::multimap MultiMap; + + // Inserts the patches from the array into the multimap + int _AddPatchArray( int arrayid, int ringsize, + FarPatchTables::PtexCoordinateTable const & ptxtable, + int & nfaces, MultiMap & mmap ) { + + if (ptxtable.empty()) + return 0; + + for (int i=0; i<(int)ptxtable.size(); ++i) { + + int faceId = ptxtable[i].faceIndex; + + OsdPatchHandle handle = { arrayid, i*ringsize, (unsigned int)mmap.size() }; + + mmap.insert( std::pair(faceId, handle) ); + + nfaces = std::max(nfaces, faceId); + } + + return 1; + } + + // Constructor + PatchMap( FarPatchTables const & patchTables ) { + + int npatches = (int)patchTables.GetNumPatches(); + + _handles.reserve(npatches); + + MultiMap mmap; + + // Insert all the patch arrays into the map + int arrayId=0, nfaces=0; + + arrayId+=_AddPatchArray( arrayId, + patchTables.GetRegularPatchRingsize(), + patchTables.GetFullRegularPtexCoordinates(), + nfaces, mmap ); + + arrayId+=_AddPatchArray( arrayId, + patchTables.GetBoundaryPatchRingsize(), + patchTables.GetFullBoundaryPtexCoordinates(), + nfaces, mmap ); + + arrayId+=_AddPatchArray( arrayId, + patchTables.GetCornerPatchRingsize(), + patchTables.GetFullCornerPtexCoordinates(), + nfaces, mmap ); + + arrayId+=_AddPatchArray( arrayId, + patchTables.GetGregoryPatchRingsize(), + patchTables.GetFullGregoryPtexCoordinates(), + nfaces, mmap ); + + for (unsigned char pattern=0; pattern<5; ++pattern) { + + arrayId+=_AddPatchArray( arrayId, + patchTables.GetRegularPatchRingsize(), + patchTables.GetTransitionRegularPtexCoordinates(pattern), + nfaces, mmap ); + + for (unsigned char rot=0; rot<4; ++rot) { + + arrayId+=_AddPatchArray( arrayId, + patchTables.GetBoundaryPatchRingsize(), + patchTables.GetTransitionBoundaryPtexCoordinates(pattern, rot), + nfaces, mmap ); + + arrayId+=_AddPatchArray( arrayId, + patchTables.GetCornerPatchRingsize(), + patchTables.GetTransitionCornerPtexCoordinates(pattern, rot), + nfaces, mmap ); + } + } + + ++nfaces; + + _handles.resize( mmap.size() ); + + _offsets.reserve( nfaces ); + _offsets.push_back(0); + + unsigned int handlesIdx = 0, faceId=mmap.begin()->first; + + // Serialize the multi-map + for (MultiMap::const_iterator it=mmap.begin(); it!=mmap.end(); ++it, ++handlesIdx) { + + assert(it->first >= faceId); + + if (it->first != faceId) { + + faceId = it->first; + + // position the offset marker to the new face + _offsets.push_back( handlesIdx ); + } + + // copy the patch id into the table + _handles[handlesIdx] = it->second; + } + } + + // Patch handle allowing location of individual patch data inside patch + // arrays or in serialized form + std::vector _handles; + + // offset to the first handle of the child patches for each coarse face + std::vector _offsets; + }; + + /// Returns a map object that can connect a faceId to a list of children patches + const PatchMap * GetPatchesMap() const { + return _patchMap; + } + +protected: + explicit OsdCpuEvalLimitContext(FarMesh const * farmesh); + +private: + + //-------------------------------------------------------------------------- + int _AppendPatchArray( OsdPatchDescriptor const & desc, + FarPatchTables::PTable const & pT, + FarPatchTables::PtexCoordinateTable const & ptxT ); + + + // Topology data for a mesh + OsdPatchArrayVector _patchArrays; // patch descriptor for each patch in the mesh + std::vector _patchBitFields; // per-patch parametric info + std::vector _patchBuffer; // list of control vertices + + std::vector _vertexValenceBuffer; // extra Gregory patch data buffers + std::vector _quadOffsetBuffer; + + PatchMap * _patchMap; + + OsdVertexBufferDescriptor _inDesc, + _outDesc; + + float * _inQ, // input vertex data + * _outQ, // output vertex data + * _outdQu, // U derivative of output vertex data + * _outdQv; // V derivative of output vertex data +}; + +} // end namespace OPENSUBDIV_VERSION +using namespace OPENSUBDIV_VERSION; + +} // end namespace OpenSubdiv + +#endif /* OSD_CPU_EVAL_LIMIT_CONTEXT_H */ diff --git a/opensubdiv/osd/cpuEvalLimitController.cpp b/opensubdiv/osd/cpuEvalLimitController.cpp new file mode 100644 index 00000000..04759794 --- /dev/null +++ b/opensubdiv/osd/cpuEvalLimitController.cpp @@ -0,0 +1,179 @@ +// +// Copyright (C) Pixar. All rights reserved. +// +// This license governs use of the accompanying software. If you +// use the software, you accept this license. If you do not accept +// the license, do not use the software. +// +// 1. Definitions +// The terms "reproduce," "reproduction," "derivative works," and +// "distribution" have the same meaning here as under U.S. +// copyright law. A "contribution" is the original software, or +// any additions or changes to the software. +// A "contributor" is any person or entity that distributes its +// contribution under this license. +// "Licensed patents" are a contributor's patent claims that read +// directly on its contribution. +// +// 2. Grant of Rights +// (A) Copyright Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free copyright license to reproduce its contribution, +// prepare derivative works of its contribution, and distribute +// its contribution or any derivative works that you create. +// (B) Patent Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free license under its licensed patents to make, have +// made, use, sell, offer for sale, import, and/or otherwise +// dispose of its contribution in the software or derivative works +// of the contribution in the software. +// +// 3. Conditions and Limitations +// (A) No Trademark License- This license does not grant you +// rights to use any contributor's name, logo, or trademarks. +// (B) If you bring a patent claim against any contributor over +// patents that you claim are infringed by the software, your +// patent license from such contributor to the software ends +// automatically. +// (C) If you distribute any portion of the software, you must +// retain all copyright, patent, trademark, and attribution +// notices that are present in the software. +// (D) If you distribute any portion of the software in source +// code form, you may do so only under this license by including a +// complete copy of this license with your distribution. If you +// distribute any portion of the software in compiled or object +// code form, you may only do so under a license that complies +// with this license. +// (E) The software is licensed "as-is." You bear the risk of +// using it. The contributors give no express warranties, +// guarantees or conditions. You may have additional consumer +// rights under your local laws which this license cannot change. +// To the extent permitted under your local laws, the contributors +// exclude the implied warranties of merchantability, fitness for +// a particular purpose and non-infringement. +// + +#include "../osd/cpuEvalLimitController.h" +#include "../osd/cpuEvalLimitKernel.h" + +namespace OpenSubdiv { +namespace OPENSUBDIV_VERSION { + +OsdCpuEvalLimitController::OsdCpuEvalLimitController() { +} + +OsdCpuEvalLimitController::~OsdCpuEvalLimitController() { +} + + +int +OsdCpuEvalLimitController::_EvalLimitSample( OpenSubdiv::OsdEvalCoords const & coords, + OsdCpuEvalLimitContext const *context, + unsigned int index ) { + + + int npatches=0; + OsdPatchHandle const * patchHandles; + + // Get the list of all children patches of the face described in coords + if (not context->GetPatchesMap()->GetChildPatchesHandles( coords.face, &npatches, &patchHandles)) + return 0; + + // Position lookup pointers at the indexed vertex + float const * inQ = context->GetInputVertexData(); + float * outQ = context->GetOutputVertexData() + index * context->GetOutputDesc().stride; + float * outdQu = context->GetOutputVertexDataUDerivative() + index * context->GetOutputDesc().stride; + float * outdQv = context->GetOutputVertexDataVDerivative() + index * context->GetOutputDesc().stride; + + for (int i=0; iGetPatchBitFields()[ handle.serialIndex ]; + + float frac = 1.0f / float( 1 << bits.GetDepth() ); + + // Are the coordinates within the parametric space covered by the patch ? + float pu = (float)bits.GetU()*frac; + if ( (coords.u < pu) or (coords.u > pu+frac) ) + continue; + + float pv = (float)bits.GetV()*frac; + if ( (coords.v < pv) or (coords.v > pv+frac) ) + continue; + + assert( handle.array < context->GetPatchArrayVector().size() ); + + OsdPatchArray const & parray = context->GetPatchArrayVector()[ handle.array ]; + + unsigned int const * cvs = &context->GetControlVertices()[ parray.firstIndex + handle.vertexOffset ]; + + // normalize u,v coordinates + float u = (coords.u - pu) / frac, + v = (coords.v - pv) / frac; + + assert( (u>=0.0f) and (u<=1.0f) and (v>=0.0f) and (v<=1.0f) ); + + // Based on patch type - go execute interpolation + switch( parray.desc.type ) { + + case kRegular : + evalBSpline( v, u, cvs, + context->GetInputDesc(), + inQ, + context->GetOutputDesc(), + outQ, outdQu, outdQv); return 1; + + case kBoundary : return 0; + + case kCorner : return 0; + + case kGregory : /*evalGregory(v, u, cvs, + unsigned int const * quadOffsetBuffer, + int maxValence, + unsigned int const * vertexIndices, + OsdVertexBufferDescriptor const & inDesc, + float const * inQ, + OsdVertexBufferDescriptor const & outDesc, + float * outQ, + float * outDQU, + float * outDQV );*/ return 0; + + + return 0; + + case kBoundaryGregory : return 0; + + + case kTransitionRegular : + switch( bits.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); + } + + evalBSpline( v, u, cvs, + context->GetInputDesc(), + inQ, + context->GetOutputDesc(), + outQ, outdQu, outdQv); return 1; + + case kTransitionBoundary: return 0; + + case kTransitionCorner : return 0; + + + default: + assert(0); + } + } + return 0; +} + +} // end namespace OPENSUBDIV_VERSION +} // end namespace OpenSubdiv diff --git a/opensubdiv/osd/cpuEvalLimitController.h b/opensubdiv/osd/cpuEvalLimitController.h new file mode 100644 index 00000000..c0a803e8 --- /dev/null +++ b/opensubdiv/osd/cpuEvalLimitController.h @@ -0,0 +1,143 @@ +// +// Copyright (C) Pixar. All rights reserved. +// +// This license governs use of the accompanying software. If you +// use the software, you accept this license. If you do not accept +// the license, do not use the software. +// +// 1. Definitions +// The terms "reproduce," "reproduction," "derivative works," and +// "distribution" have the same meaning here as under U.S. +// copyright law. A "contribution" is the original software, or +// any additions or changes to the software. +// A "contributor" is any person or entity that distributes its +// contribution under this license. +// "Licensed patents" are a contributor's patent claims that read +// directly on its contribution. +// +// 2. Grant of Rights +// (A) Copyright Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free copyright license to reproduce its contribution, +// prepare derivative works of its contribution, and distribute +// its contribution or any derivative works that you create. +// (B) Patent Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free license under its licensed patents to make, have +// made, use, sell, offer for sale, import, and/or otherwise +// dispose of its contribution in the software or derivative works +// of the contribution in the software. +// +// 3. Conditions and Limitations +// (A) No Trademark License- This license does not grant you +// rights to use any contributor's name, logo, or trademarks. +// (B) If you bring a patent claim against any contributor over +// patents that you claim are infringed by the software, your +// patent license from such contributor to the software ends +// automatically. +// (C) If you distribute any portion of the software, you must +// retain all copyright, patent, trademark, and attribution +// notices that are present in the software. +// (D) If you distribute any portion of the software in source +// code form, you may do so only under this license by including a +// complete copy of this license with your distribution. If you +// distribute any portion of the software in compiled or object +// code form, you may only do so under a license that complies +// with this license. +// (E) The software is licensed "as-is." You bear the risk of +// using it. The contributors give no express warranties, +// guarantees or conditions. You may have additional consumer +// rights under your local laws which this license cannot change. +// To the extent permitted under your local laws, the contributors +// exclude the implied warranties of merchantability, fitness for +// a particular purpose and non-infringement. +// + +#ifndef OSD_CPU_EVAL_LIMIT_CONTROLLER_H +#define OSD_CPU_EVAL_LIMIT_CONTROLLER_H + +#include "../version.h" + +#include "../osd/evalLimitContext.h" +#include "../osd/cpuEvalLimitContext.h" +#include "../osd/vertexDescriptor.h" + +namespace OpenSubdiv { +namespace OPENSUBDIV_VERSION { + +/// \brief CPU controler for limit surface evaluation. +/// +/// A CPU-driven controller that can be called to evaluate samples on the limit +/// surface for a given EvalContext. +/// +class OsdCpuEvalLimitController { + +public: + /// Constructor. + OsdCpuEvalLimitController(); + + /// Destructor. + ~OsdCpuEvalLimitController(); + + /// \brief Represents a location on the limit surface + struct OsdEvalCoords { + int face; // Ptex unique face ID + float u,v; // local u,v + }; + + /// \brief Vertex interpolation of samples at the limit + /// + /// Evaluates "vertex" interpolation of a sample on the surface limit. + /// + /// Warning : this function is re-entrant but it breaks the Osd API pattern + /// by requiring the client code to bind and unbind the vertex buffers to + /// the EvalLimitContext. + /// + /// Ex : + /// \code + /// evalCtxt->BindVertexBuffers( ... ); + /// + /// parallel_for( int index=0; iEvalLimitSample( coord, evalCtxt, index ); + /// } + /// + /// evalCtxt->UnbindVertexBuffers(); + /// \endcode + /// + /// @param coords location on the limit surface to be evaluated + /// + /// @param context the EvalLimitContext that the controller will evaluate + /// + /// @param index the index of the vertex in the output buffers bound to the + /// context + /// + template + int EvalLimitSample( OpenSubdiv::OsdEvalCoords const & coords, + OsdCpuEvalLimitContext * context, + unsigned int index + ) { + + if (not context) + return 0; + + int n = _EvalLimitSample( coords, context, index ); + + return n; + } + +private: + + int _EvalLimitSample( OpenSubdiv::OsdEvalCoords const & coords, + OsdCpuEvalLimitContext const * context, + unsigned int index ); + +}; + +} // end namespace OPENSUBDIV_VERSION +using namespace OPENSUBDIV_VERSION; + +} // end namespace OpenSubdiv + +#endif /* OSD_CPU_EVAL_LIMIT_CONTROLLER_H */ diff --git a/opensubdiv/osd/cpuEvalLimitKernel.cpp b/opensubdiv/osd/cpuEvalLimitKernel.cpp new file mode 100644 index 00000000..d0a7f688 --- /dev/null +++ b/opensubdiv/osd/cpuEvalLimitKernel.cpp @@ -0,0 +1,427 @@ +// +// Copyright (C) Pixar. All rights reserved. +// +// This license governs use of the accompanying software. If you +// use the software, you accept this license. If you do not accept +// the license, do not use the software. +// +// 1. Definitions +// The terms "reproduce," "reproduction," "derivative works," and +// "distribution" have the same meaning here as under U.S. +// copyright law. A "contribution" is the original software, or +// any additions or changes to the software. +// A "contributor" is any person or entity that distributes its +// contribution under this license. +// "Licensed patents" are a contributor's patent claims that read +// directly on its contribution. +// +// 2. Grant of Rights +// (A) Copyright Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free copyright license to reproduce its contribution, +// prepare derivative works of its contribution, and distribute +// its contribution or any derivative works that you create. +// (B) Patent Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free license under its licensed patents to make, have +// made, use, sell, offer for sale, import, and/or otherwise +// dispose of its contribution in the software or derivative works +// of the contribution in the software. +// +// 3. Conditions and Limitations +// (A) No Trademark License- This license does not grant you +// rights to use any contributor's name, logo, or trademarks. +// (B) If you bring a patent claim against any contributor over +// patents that you claim are infringed by the software, your +// patent license from such contributor to the software ends +// automatically. +// (C) If you distribute any portion of the software, you must +// retain all copyright, patent, trademark, and attribution +// notices that are present in the software. +// (D) If you distribute any portion of the software in source +// code form, you may do so only under this license by including a +// complete copy of this license with your distribution. If you +// distribute any portion of the software in compiled or object +// code form, you may only do so under a license that complies +// with this license. +// (E) The software is licensed "as-is." You bear the risk of +// using it. The contributors give no express warranties, +// guarantees or conditions. You may have additional consumer +// rights under your local laws which this license cannot change. +// To the extent permitted under your local laws, the contributors +// exclude the implied warranties of merchantability, fitness for +// a particular purpose and non-infringement. +// + +#include "../osd/cpuEvalLimitKernel.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace OpenSubdiv { +namespace OPENSUBDIV_VERSION { + +inline void +evalCubicBSpline(float u, float B[4], float BU[4]) +{ + float t = u; + float s = 1.0f - u; + + float C0 = s * (0.5f * s); + float C1 = t * (s + 0.5f * t) + s * (0.5f * s + t); + float C2 = t * ( 0.5f * t); + + B[0] = 1.f/3.f * s * C0; + B[1] = (2.f/3.f * s + t) * C0 + (2.f/3.f * s + 1.f/3.f * t) * C1; + B[2] = (1.f/3.f * s + 2.f/3.f * t) * C1 + ( s + 2.f/3.f * t) * C2; + B[3] = 1.f/3.f * t * C2; + + if (BU) { + BU[0] = - C0; + BU[1] = C0 - C1; + BU[2] = C1 - C2; + BU[3] = C2; + } +} + +void +evalBSpline(float u, float v, + unsigned int const * vertexIndices, + OsdVertexBufferDescriptor const & inDesc, + float const * inQ, + OsdVertexBufferDescriptor const & outDesc, + float * outQ, + float * outDQU, + float * outDQV ) { + + // make sure that we have enough space to store results + assert( inDesc.length <= (outDesc.stride-outDesc.offset) ); + + bool evalDeriv = (outDQU or outDQV); + + // XXX these dynamic allocs won't work w/ VC++ + float B[4], D[4], + *BU=(float*)alloca(inDesc.length*4*sizeof(float)), + *DU=(float*)alloca(inDesc.length*4*sizeof(float)); + + memset(BU, 0, inDesc.length*4*sizeof(float)); + memset(DU, 0, inDesc.length*4*sizeof(float)); + + evalCubicBSpline(u, B, evalDeriv ? D : 0); + + float const * inOffset = inQ + inDesc.offset; + + for (int i=0; i<4; ++i) { + for (int j=0; j<4; ++j) { + + float const * in = inOffset + vertexIndices[i+j*4]*inDesc.stride; + + for (int k=0; k const * farmesh) { + + _adaptive = farmesh->SupportsFeatureAdaptive(); + + +} + +OsdEvalLimitContext::~OsdEvalLimitContext() { +} + +} // end namespace OPENSUBDIV_VERSION +} // end namespace OpenSubdiv diff --git a/opensubdiv/osd/evalLimitContext.h b/opensubdiv/osd/evalLimitContext.h new file mode 100644 index 00000000..ea933347 --- /dev/null +++ b/opensubdiv/osd/evalLimitContext.h @@ -0,0 +1,117 @@ +// +// Copyright (C) Pixar. All rights reserved. +// +// This license governs use of the accompanying software. If you +// use the software, you accept this license. If you do not accept +// the license, do not use the software. +// +// 1. Definitions +// The terms "reproduce," "reproduction," "derivative works," and +// "distribution" have the same meaning here as under U.S. +// copyright law. A "contribution" is the original software, or +// any additions or changes to the software. +// A "contributor" is any person or entity that distributes its +// contribution under this license. +// "Licensed patents" are a contributor's patent claims that read +// directly on its contribution. +// +// 2. Grant of Rights +// (A) Copyright Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free copyright license to reproduce its contribution, +// prepare derivative works of its contribution, and distribute +// its contribution or any derivative works that you create. +// (B) Patent Grant- Subject to the terms of this license, +// including the license conditions and limitations in section 3, +// each contributor grants you a non-exclusive, worldwide, +// royalty-free license under its licensed patents to make, have +// made, use, sell, offer for sale, import, and/or otherwise +// dispose of its contribution in the software or derivative works +// of the contribution in the software. +// +// 3. Conditions and Limitations +// (A) No Trademark License- This license does not grant you +// rights to use any contributor's name, logo, or trademarks. +// (B) If you bring a patent claim against any contributor over +// patents that you claim are infringed by the software, your +// patent license from such contributor to the software ends +// automatically. +// (C) If you distribute any portion of the software, you must +// retain all copyright, patent, trademark, and attribution +// notices that are present in the software. +// (D) If you distribute any portion of the software in source +// code form, you may do so only under this license by including a +// complete copy of this license with your distribution. If you +// distribute any portion of the software in compiled or object +// code form, you may only do so under a license that complies +// with this license. +// (E) The software is licensed "as-is." You bear the risk of +// using it. The contributors give no express warranties, +// guarantees or conditions. You may have additional consumer +// rights under your local laws which this license cannot change. +// To the extent permitted under your local laws, the contributors +// exclude the implied warranties of merchantability, fitness for +// a particular purpose and non-infringement. +// +#ifndef OSD_EVAL_LIMIT_CONTEXT_H +#define OSD_EVAL_LIMIT_CONTEXT_H + +#include "../version.h" + +#include "../far/mesh.h" + +#include "../osd/nonCopyable.h" +#include "../osd/patch.h" +#include "../osd/vertex.h" + +namespace OpenSubdiv { +namespace OPENSUBDIV_VERSION { + + +/// \brief Coordinates set on a limit surface +/// +class OsdEvalCoords { + +public: + + OsdEvalCoords() { } + + /// \brief Constructor + /// + /// @param f Ptex face id + /// + /// @param x parametric location on face + /// + /// @param y parametric location on face + /// + OsdEvalCoords(int f, float x, float y) : face(f), u(x), v(y) { } + + unsigned int face; // Ptex face ID + float u,v; // local face (u,v) +}; + + +/// \brief LimitEval Context +/// +/// A stub class to derive LimitEval context classes. +/// +class OsdEvalLimitContext : OsdNonCopyable { + +public: + /// \brief Destructor. + virtual ~OsdEvalLimitContext(); + +protected: + explicit OsdEvalLimitContext(FarMesh const * farmesh); + +private: + bool _adaptive; +}; + +} // end namespace OPENSUBDIV_VERSION +using namespace OPENSUBDIV_VERSION; + +} // end namespace OpenSubdiv + +#endif /* OSD_EVAL_LIMIT_CONTEXT_H */ diff --git a/opensubdiv/osd/patch.h b/opensubdiv/osd/patch.h index 38f6e137..5135b8d9 100644 --- a/opensubdiv/osd/patch.h +++ b/opensubdiv/osd/patch.h @@ -77,11 +77,25 @@ enum OsdPatchType { kTransitionCorner = 8, }; +/// \brief A bitfield-based descriptor for feature adaptive patches struct OsdPatchDescriptor { OsdPatchDescriptor() : type(kNonPatch), pattern(0), rotation(0), subpatch(0), maxValence(0), numElements(0) {} + /// \brief Constructor + /// + /// @param type Patch type enum (see OsdPatchType) + /// + /// @param pattern Transition pattern. One of 5 patterns (see : "Feature Adaptive + /// GPU Rendering of Catmull-Clark Subdivision Surfaces") + /// + /// @param rotation Number of CCW parametric rotations of the patch. + /// + /// @param maxValence The maximum vertex valence (set for the entire mesh) + /// + /// @param numElements Stride of the data in the vertex buffer (used for drawing) + /// OsdPatchDescriptor( OsdPatchType type, unsigned char pattern, @@ -91,6 +105,7 @@ struct OsdPatchDescriptor { type(type), pattern(pattern), rotation(rotation), subpatch(0), maxValence(maxValence), numElements(numElements) {} + /// Returns the number of control vertices expected for a patch of this type short GetPatchSize() const { switch (type) { case kNonPatch : return (loop ? 3:4); @@ -120,21 +135,31 @@ struct OsdPatchDescriptor { unsigned char numElements:5; // 0-31 }; + bool operator< (OsdPatchDescriptor const & a, OsdPatchDescriptor const & b); +/// \brief A container to aggregate patches of the same type. struct OsdPatchArray { OsdPatchDescriptor desc; int firstIndex; // index of first vertex in patch indices array int numIndices; // number of vertex indices in indices array int levelBase; // XXX ??? + int gregoryVertexValenceBase; int gregoryQuadOffsetBase; }; typedef std::vector OsdPatchArrayVector; +/// Unique patch identifier +struct OsdPatchHandle { + unsigned int array, // OsdPatchArray containing the patch + vertexOffset, // Offset to the first CV of the patch + serialIndex; // Serialized Index of the patch +}; + } // end namespace OPENSUBDIV_VERSION using namespace OPENSUBDIV_VERSION; diff --git a/opensubdiv/osd/vertexDescriptor.h b/opensubdiv/osd/vertexDescriptor.h index 9f9f341c..29628b68 100644 --- a/opensubdiv/osd/vertexDescriptor.h +++ b/opensubdiv/osd/vertexDescriptor.h @@ -167,11 +167,28 @@ struct OsdVertexDescriptor { int numVaryingElements; }; +/// \brief Describes vertex elements in interleaved data buffers struct OsdVertexBufferDescriptor { /// Default Constructor - OsdVertexBufferDescriptor() - : offset(0), length(0), stride(0) { } + OsdVertexBufferDescriptor() : offset(0), length(0), stride(0) { } + + /// Constructor + OsdVertexBufferDescriptor(int o, int l, int s) : offset(o), length(l), stride(s) { } + + /// True if the descriptor values are internally consistent + bool IsValid() const { + return (offset=length); + } + + /// True if the 'other' descriptor can be used as a destination for + /// data evaluations. + bool CanEval( OsdVertexBufferDescriptor const & other ) const { + return IsValid() and + other.IsValid() and + (length==other.length) and + (other.length <= (stride-offset)); + } int offset; // offset to desired element data int length; // number or length of the data