Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--intern/opensubdiv/CMakeLists.txt48
-rw-r--r--intern/opensubdiv/internal/opensubdiv.cc99
-rw-r--r--intern/opensubdiv/internal/opensubdiv_converter_factory.cc438
-rw-r--r--intern/opensubdiv/internal/opensubdiv_converter_factory.h37
-rw-r--r--intern/opensubdiv/internal/opensubdiv_converter_internal.cc70
-rw-r--r--intern/opensubdiv/internal/opensubdiv_converter_internal.h50
-rw-r--r--intern/opensubdiv/internal/opensubdiv_converter_orient.cc66
-rw-r--r--intern/opensubdiv/internal/opensubdiv_converter_orient.h50
-rw-r--r--intern/opensubdiv/internal/opensubdiv_converter_orient_impl.h66
-rw-r--r--intern/opensubdiv/internal/opensubdiv_device_context_cuda.cc226
-rw-r--r--intern/opensubdiv/internal/opensubdiv_device_context_cuda.h54
-rw-r--r--intern/opensubdiv/internal/opensubdiv_device_context_opencl.cc269
-rw-r--r--intern/opensubdiv/internal/opensubdiv_device_context_opencl.h52
-rw-r--r--intern/opensubdiv/internal/opensubdiv_evaluator.cc154
-rw-r--r--intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc734
-rw-r--r--intern/opensubdiv/internal/opensubdiv_evaluator_internal.h134
-rw-r--r--intern/opensubdiv/internal/opensubdiv_gl_mesh.cc287
-rw-r--r--intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.cc587
-rw-r--r--intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.h39
-rw-r--r--intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.cc175
-rw-r--r--intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.h57
-rw-r--r--intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.cc32
-rw-r--r--intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.h43
-rw-r--r--intern/opensubdiv/internal/opensubdiv_gpu.cc (renamed from intern/opensubdiv/opensubdiv_gpu_capi.cc)0
-rw-r--r--intern/opensubdiv/internal/opensubdiv_internal.h38
-rw-r--r--intern/opensubdiv/internal/opensubdiv_topology_refiner.cc315
-rw-r--r--intern/opensubdiv/internal/opensubdiv_topology_refiner.h (renamed from intern/opensubdiv/opensubdiv_topology_refiner.h)0
-rw-r--r--intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.cc26
-rw-r--r--intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.h47
-rw-r--r--intern/opensubdiv/internal/opensubdiv_util.cc61
-rw-r--r--intern/opensubdiv/internal/opensubdiv_util.h39
-rw-r--r--intern/opensubdiv/opensubdiv_capi.cc441
-rw-r--r--intern/opensubdiv/opensubdiv_capi.h178
-rw-r--r--intern/opensubdiv/opensubdiv_capi_type.h41
-rw-r--r--intern/opensubdiv/opensubdiv_converter.cc764
-rw-r--r--intern/opensubdiv/opensubdiv_converter_capi.h263
-rw-r--r--intern/opensubdiv/opensubdiv_device_context_cuda.cc237
-rw-r--r--intern/opensubdiv/opensubdiv_device_context_cuda.h54
-rw-r--r--intern/opensubdiv/opensubdiv_device_context_opencl.cc251
-rw-r--r--intern/opensubdiv/opensubdiv_device_context_opencl.h58
-rw-r--r--intern/opensubdiv/opensubdiv_evaluator_capi.cc516
-rw-r--r--intern/opensubdiv/opensubdiv_evaluator_capi.h117
-rw-r--r--intern/opensubdiv/opensubdiv_gl_mesh.h40
-rw-r--r--intern/opensubdiv/opensubdiv_gl_mesh_capi.h92
-rw-r--r--intern/opensubdiv/opensubdiv_intern.h46
-rw-r--r--intern/opensubdiv/opensubdiv_topology_refiner_capi.h110
-rw-r--r--intern/opensubdiv/opensubdiv_utils_capi.cc88
-rw-r--r--intern/opensubdiv/shader/gpu_shader_opensubdiv_fragment.glsl (renamed from intern/opensubdiv/gpu_shader_opensubdiv_fragment.glsl)0
-rw-r--r--intern/opensubdiv/shader/gpu_shader_opensubdiv_geometry.glsl (renamed from intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl)0
-rw-r--r--intern/opensubdiv/shader/gpu_shader_opensubdiv_vertex.glsl (renamed from intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl)0
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c6
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_intern.h4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c139
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c96
54 files changed, 4919 insertions, 2915 deletions
diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt
index 876b5c0181f..887eb399224 100644
--- a/intern/opensubdiv/CMakeLists.txt
+++ b/intern/opensubdiv/CMakeLists.txt
@@ -34,20 +34,40 @@ set(INC_SYS
)
set(SRC
- opensubdiv_capi.cc
- opensubdiv_converter.cc
- opensubdiv_device_context_cuda.cc
- opensubdiv_device_context_opencl.cc
- opensubdiv_evaluator_capi.cc
- opensubdiv_gpu_capi.cc
- opensubdiv_utils_capi.cc
+ internal/opensubdiv.cc
+ internal/opensubdiv_converter_factory.cc
+ internal/opensubdiv_converter_internal.cc
+ internal/opensubdiv_converter_orient.cc
+ internal/opensubdiv_device_context_cuda.cc
+ internal/opensubdiv_device_context_opencl.cc
+ internal/opensubdiv_evaluator.cc
+ internal/opensubdiv_evaluator_internal.cc
+ internal/opensubdiv_gl_mesh.cc
+ internal/opensubdiv_gl_mesh_draw.cc
+ internal/opensubdiv_gl_mesh_fvar.cc
+ internal/opensubdiv_gl_mesh_internal.cc
+ internal/opensubdiv_topology_refiner.cc
+ internal/opensubdiv_topology_refiner_internal.cc
+ internal/opensubdiv_util.cc
+
+ internal/opensubdiv_converter_internal.h
+ internal/opensubdiv_converter_orient.h
+ internal/opensubdiv_converter_orient_impl.h
+ internal/opensubdiv_device_context_cuda.h
+ internal/opensubdiv_device_context_opencl.h
+ internal/opensubdiv_evaluator_internal.h
+ internal/opensubdiv_gl_mesh_fvar.h
+ internal/opensubdiv_gl_mesh_internal.h
+ internal/opensubdiv_internal.h
+ internal/opensubdiv_topology_refiner_internal.h
+ internal/opensubdiv_util.h
opensubdiv_capi.h
+ opensubdiv_capi_type.h
opensubdiv_converter_capi.h
- opensubdiv_device_context_cuda.h
- opensubdiv_device_context_opencl.h
- opensubdiv_intern.h
- opensubdiv_topology_refiner.h
+ opensubdiv_evaluator_capi.h
+ opensubdiv_gl_mesh_capi.h
+ opensubdiv_topology_refiner_capi.h
)
macro(OPENSUBDIV_DEFINE_COMPONENT component)
@@ -64,9 +84,9 @@ OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_OPENMP)
OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK)
OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_GLSL_COMPUTE)
-data_to_c_simple(gpu_shader_opensubdiv_vertex.glsl SRC)
-data_to_c_simple(gpu_shader_opensubdiv_geometry.glsl SRC)
-data_to_c_simple(gpu_shader_opensubdiv_fragment.glsl SRC)
+data_to_c_simple(shader/gpu_shader_opensubdiv_vertex.glsl SRC)
+data_to_c_simple(shader/gpu_shader_opensubdiv_geometry.glsl SRC)
+data_to_c_simple(shader/gpu_shader_opensubdiv_fragment.glsl SRC)
add_definitions(-DGLEW_STATIC)
diff --git a/intern/opensubdiv/internal/opensubdiv.cc b/intern/opensubdiv/internal/opensubdiv.cc
new file mode 100644
index 00000000000..c2945ed25ab
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv.cc
@@ -0,0 +1,99 @@
+// Copyright 2013 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+// Contributor(s): Brecht van Lommel
+
+#include "opensubdiv_capi.h"
+
+#ifdef _MSC_VER
+# include <iso646.h>
+#endif
+
+#include <GL/glew.h>
+
+#include "opensubdiv_device_context_opencl.h"
+#include "opensubdiv_device_context_cuda.h"
+#include "opensubdiv_gl_mesh_capi.h"
+
+void openSubdiv_init(void) {
+ // Ensure all OpenGL strings are cached.
+ openSubdiv_getAvailableEvaluators();
+}
+
+void openSubdiv_cleanup(void) {
+ openSubdiv_deinitGLMeshDrawingResources();
+}
+
+int openSubdiv_getAvailableEvaluators(void) {
+ int flags = OPENSUBDIV_EVALUATOR_CPU;
+
+#ifdef OPENSUBDIV_HAS_OPENMP
+ flags |= OPENSUBDIV_EVALUATOR_OPENMP;
+#endif
+
+#ifdef OPENSUBDIV_HAS_OPENCL
+ if (CLDeviceContext::HAS_CL_VERSION_1_1()) {
+ flags |= OPENSUBDIV_EVALUATOR_OPENCL;
+ }
+#endif
+
+#ifdef OPENSUBDIV_HAS_CUDA
+ if (CudaDeviceContext::HAS_CUDA_VERSION_4_0()) {
+ flags |= OPENSUBDIV_EVALUATOR_CUDA;
+ }
+#endif
+
+#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
+ if (GLEW_VERSION_4_1) {
+ flags |= OPENSUBDIV_EVALUATOR_GLSL_TRANSFORM_FEEDBACK;
+ }
+#endif
+
+#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
+ if (GLEW_VERSION_4_3 || GLEW_ARB_compute_shader) {
+ flags |= OPENSUBDIV_EVALUATOR_GLSL_COMPUTE;
+ }
+#endif
+
+ return flags;
+}
+
+int openSubdiv_getVersionHex(void) {
+#if defined(OPENSUBDIV_VERSION_NUMBER)
+ return OPENSUBDIV_VERSION_NUMBER;
+#elif defined(OPENSUBDIV_VERSION_MAJOR)
+ return OPENSUBDIV_VERSION_MAJOR * 10000 +
+ OPENSUBDIV_VERSION_MINOR * 100 +
+ OPENSUBDIV_VERSION_PATCH;
+#elif defined(OPENSUBDIV_VERSION)
+ const char* version = STRINGIFY(OPENSUBDIV_VERSION);
+ if (version[0] == 'v') {
+ version += 1;
+ }
+ int major = 0, minor = 0, patch = 0;
+ vector<string> tokens;
+ opensubdiv_capi::stringSplit(&tokens, version, "_", true);
+ if (tokens.size() == 3) {
+ major = atoi(tokens[0].c_str());
+ minor = atoi(tokens[1].c_str());
+ patch = atoi(tokens[2].c_str());
+ }
+ return major * 10000 + minor * 100 + patch;
+#else
+ return 0;
+#endif
+}
diff --git a/intern/opensubdiv/internal/opensubdiv_converter_factory.cc b/intern/opensubdiv/internal/opensubdiv_converter_factory.cc
new file mode 100644
index 00000000000..bd6edbb9648
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_converter_factory.cc
@@ -0,0 +1,438 @@
+// Copyright 2015 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifdef _MSC_VER
+# include <iso646.h>
+#endif
+
+#include "internal/opensubdiv_converter_factory.h"
+
+#include <cassert>
+#include <cstdio>
+#include <stack>
+#include <vector>
+
+#include <opensubdiv/far/topologyRefinerFactory.h>
+
+#include "internal/opensubdiv_converter_internal.h"
+#include "internal/opensubdiv_converter_orient.h"
+#include "internal/opensubdiv_internal.h"
+#include "opensubdiv_converter_capi.h"
+
+struct TopologyRefinerData {
+ const OpenSubdiv_Converter* converter;
+};
+
+namespace OpenSubdiv {
+namespace OPENSUBDIV_VERSION {
+namespace Far {
+
+template <>
+inline bool
+TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology(
+ TopologyRefiner& refiner,
+ const TopologyRefinerData& cb_data) {
+ const OpenSubdiv_Converter* converter = cb_data.converter;
+ /// Faces and face-vertices.
+ const int num_faces = converter->getNumFaces(converter);
+ setNumBaseFaces(refiner, num_faces);
+ for (int face_index = 0; face_index < num_faces; ++face_index) {
+ const int num_face_vertices =
+ converter->getNumFaceVertices(converter, face_index);
+ setNumBaseFaceVertices(refiner, face_index, num_face_vertices);
+ }
+ // Edges and edge-faces.
+ const int num_edges = converter->getNumEdges(converter);
+ setNumBaseEdges(refiner, num_edges);
+ for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
+ const int num_edge_faces =
+ converter->getNumEdgeFaces(converter, edge_index);
+ setNumBaseEdgeFaces(refiner, edge_index, num_edge_faces);
+ }
+ // Vertices and vertex-faces and vertex-edges.
+ const int num_vertices = converter->getNumVertices(converter);
+ setNumBaseVertices(refiner, num_vertices);
+ for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
+ const int num_vert_edges =
+ converter->getNumVertexEdges(converter, vertex_index);
+ const int num_vert_faces =
+ converter->getNumVertexFaces(converter, vertex_index);
+ setNumBaseVertexEdges(refiner, vertex_index, num_vert_edges);
+ setNumBaseVertexFaces(refiner, vertex_index, num_vert_faces);
+ }
+ return true;
+}
+
+template <>
+inline bool
+TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology(
+ TopologyRefiner& refiner,
+ const TopologyRefinerData& cb_data) {
+ using Far::IndexArray;
+ const OpenSubdiv_Converter* converter = cb_data.converter;
+ // Face relations.
+ const int num_faces = converter->getNumFaces(converter);
+ for (int face_index = 0; face_index < num_faces; ++face_index) {
+ IndexArray dst_face_verts = getBaseFaceVertices(refiner, face_index);
+ converter->getFaceVertices(converter, face_index, &dst_face_verts[0]);
+ IndexArray dst_face_edges = getBaseFaceEdges(refiner, face_index);
+ converter->getFaceEdges(converter, face_index, &dst_face_edges[0]);
+ }
+ // Edge relations.
+ const int num_edges = converter->getNumEdges(converter);
+ for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
+ // Edge-vertices.
+ IndexArray dst_edge_vertices = getBaseEdgeVertices(refiner, edge_index);
+ converter->getEdgeVertices(converter, edge_index, &dst_edge_vertices[0]);
+ // Edge-faces.
+ IndexArray dst_edge_faces = getBaseEdgeFaces(refiner, edge_index);
+ converter->getEdgeFaces(converter, edge_index, &dst_edge_faces[0]);
+ }
+// TODO(sergey): Find a way to move this to an utility function.
+#ifdef OPENSUBDIV_ORIENT_TOPOLOGY
+ // Make face normals consistent.
+ std::vector<bool> face_used(num_faces, false);
+ std::stack<int> traverse_stack;
+ int face_start = 0, num_traversed_faces = 0;
+ // Traverse all islands.
+ while (num_traversed_faces != num_faces) {
+ // Find first face of any untraversed islands.
+ while (face_used[face_start]) {
+ ++face_start;
+ }
+ // Add first face to the stack.
+ traverse_stack.push(face_start);
+ face_used[face_start] = true;
+ // Go over whole connected component.
+ while (!traverse_stack.empty()) {
+ int face = traverse_stack.top();
+ traverse_stack.pop();
+ IndexArray face_edges = getBaseFaceEdges(refiner, face);
+ ConstIndexArray face_vertices = getBaseFaceVertices(refiner, face);
+ for (int i = 0; i < face_edges.size(); ++i) {
+ const int edge = face_edges[i];
+ ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge);
+ if (edge_faces.size() != 2) {
+ /* Can't make consistent normals for non-manifolds. */
+ continue;
+ }
+ ConstIndexArray edge_vertices = getBaseEdgeVertices(refiner, edge);
+ // Get winding of the reference face.
+ const int vert0_of_face = face_vertices.FindIndex(edge_vertices[0]);
+ const int vert1_of_face = face_vertices.FindIndex(edge_vertices[1]);
+ const int delta_face =
+ opensubdiv_capi::getLoopWinding(vert0_of_face, vert1_of_face);
+ for (int edge_face = 0; edge_face < edge_faces.size(); ++edge_face) {
+ const int other_face_index = edge_faces[edge_face];
+ // Never re-traverse faces, only move forward.
+ if (face_used[other_face_index]) {
+ continue;
+ }
+ IndexArray other_face_vertics =
+ getBaseFaceVertices(refiner, other_face_index);
+ const int vert0_of_other_face =
+ other_face_vertics.FindIndex(edge_vertices[0]);
+ const int vert1_of_other_face =
+ other_face_vertics.FindIndex(edge_vertices[1]);
+ const int delta_other_face = opensubdiv_capi::getLoopWinding(
+ vert0_of_other_face, vert1_of_other_face);
+ if (delta_face * delta_other_face > 0) {
+ IndexArray other_face_vertices =
+ getBaseFaceVertices(refiner, other_face_index);
+ IndexArray other_face_edges =
+ getBaseFaceEdges(refiner, other_face_index);
+ opensubdiv_capi::reverseFaceLoops(&other_face_vertices,
+ &other_face_edges);
+ }
+ traverse_stack.push(other_face_index);
+ face_used[other_face_index] = true;
+ }
+ }
+ ++num_traversed_faces;
+ }
+ }
+#endif // OPENSUBDIV_ORIENT_TOPOLOGY
+ // Vertex relations.
+ const int num_vertices = converter->getNumVertices(converter);
+ std::vector<int> vertex_faces, vertex_edges;
+ for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
+ // Vertex-faces.
+ IndexArray dst_vertex_faces = getBaseVertexFaces(refiner, vertex_index);
+ const int num_vertex_faces =
+ converter->getNumVertexFaces(converter, vertex_index);
+ vertex_faces.resize(num_vertex_faces);
+ converter->getVertexFaces(converter, vertex_index, &vertex_faces[0]);
+ // Vertex-edges.
+ IndexArray dst_vertex_edges = getBaseVertexEdges(refiner, vertex_index);
+ const int num_vertex_edges =
+ converter->getNumVertexEdges(converter, vertex_index);
+ vertex_edges.resize(num_vertex_edges);
+ converter->getVertexEdges(converter, vertex_index, &vertex_edges[0]);
+// TODO(sergey): Find a way to move this to an utility function.
+#ifdef OPENSUBDIV_ORIENT_TOPOLOGY
+ // Order vertex edges and faces to be in a CCW order.
+ std::fill(face_used.begin(), face_used.end(), false);
+ // Number of edges and faces added to the ordered array.
+ int edge_count_ordered = 0, face_count_ordered = 0;
+ // Add loose edges straight into the edges array.
+ bool has_fan_connections = false;
+ for (int i = 0; i < num_vertex_edges; ++i) {
+ IndexArray edge_faces = getBaseEdgeFaces(refiner, vertex_edges[i]);
+ if (edge_faces.size() == 0) {
+ dst_vertex_edges[edge_count_ordered++] = vertex_edges[i];
+ } else if (edge_faces.size() > 2) {
+ has_fan_connections = true;
+ }
+ }
+ if (has_fan_connections) {
+ // OpenSubdiv currently doesn't give us clues how to handle fan face
+ // connections. and since handling such connections complicates the loop
+ // below we simply don't do special orientation for them.
+ memcpy(&dst_vertex_edges[0], &vertex_edges[0],
+ sizeof(int) * num_vertex_edges);
+ memcpy(&dst_vertex_faces[0], &vertex_faces[0],
+ sizeof(int) * num_vertex_faces);
+ continue;
+ }
+ // Perform at max numbder of vert-edges iteration and try to avoid
+ // deadlock here for malformed mesh.
+ for (int global_iter = 0; global_iter < num_vertex_edges; ++global_iter) {
+ // Number of edges and faces which are still to be ordered.
+ const int num_vertex_edges_remained =
+ num_vertex_edges - edge_count_ordered;
+ const int num_vertex_faces_remained =
+ num_vertex_faces - face_count_ordered;
+ if (num_vertex_edges_remained == 0 && num_vertex_faces_remained == 0) {
+ // All done, nothing to do anymore.
+ break;
+ }
+ // Face, edge and face-vertex index to start traversal from.
+ int face_start = -1, edge_start = -1, face_vertex_start = -1;
+ if (num_vertex_edges_remained == num_vertex_faces_remained) {
+ // Vertex is either complete manifold or is connected to several
+ // manifold islands (hourglass-like configuration), can pick up
+ // random edge unused and start from it.
+ //
+ // TODO(sergey): Start from previous edge from which traversal began at
+ // previous iteration.
+ for (int i = 0; i < num_vertex_edges; ++i) {
+ face_start = vertex_faces[i];
+ if (!face_used[face_start]) {
+ ConstIndexArray face_vertices =
+ getBaseFaceVertices(refiner, face_start);
+ ConstIndexArray face_edges = getBaseFaceEdges(refiner, face_start);
+ face_vertex_start = face_vertices.FindIndex(vertex_index);
+ edge_start = face_edges[face_vertex_start];
+ break;
+ }
+ }
+ } else {
+ // Special handle of non-manifold vertex.
+ for (int i = 0; i < num_vertex_edges; ++i) {
+ edge_start = vertex_edges[i];
+ IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_start);
+ if (edge_faces.size() == 1) {
+ face_start = edge_faces[0];
+ if (!face_used[face_start]) {
+ ConstIndexArray face_vertices =
+ getBaseFaceVertices(refiner, face_start);
+ ConstIndexArray face_edges =
+ getBaseFaceEdges(refiner, face_start);
+ face_vertex_start = face_vertices.FindIndex(vertex_index);
+ if (edge_start == face_edges[face_vertex_start]) {
+ break;
+ }
+ }
+ }
+ // Reset indices for sanity check below.
+ face_start = edge_start = face_vertex_start = -1;
+ }
+ }
+ // Sanity check.
+ assert(face_start != -1);
+ assert(edge_start != -1);
+ assert(face_vertex_start != -1);
+ // Traverse faces starting from the current one. */
+ int edge_first = edge_start;
+ dst_vertex_faces[face_count_ordered++] = face_start;
+ dst_vertex_edges[edge_count_ordered++] = edge_start;
+ face_used[face_start] = true;
+ while (edge_count_ordered < num_vertex_edges) {
+ IndexArray face_vertices = getBaseFaceVertices(refiner, face_start);
+ IndexArray face_edges = getBaseFaceEdges(refiner, face_start);
+ int face_edge_start = face_vertex_start;
+ int face_edge_next = (face_edge_start > 0) ? (face_edge_start - 1)
+ : (face_vertices.size() - 1);
+ Index edge_next = face_edges[face_edge_next];
+ if (edge_next == edge_first) {
+ // Multiple manifolds found, stop for now and handle rest
+ // in the next iteration.
+ break;
+ }
+ dst_vertex_edges[edge_count_ordered++] = edge_next;
+ if (face_count_ordered < num_vertex_faces) {
+ IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_next);
+ assert(edge_faces.size() != 0);
+ if (edge_faces.size() == 1) {
+ assert(edge_faces[0] == face_start);
+ break;
+ } else if (edge_faces.size() != 2) {
+ break;
+ }
+ assert(edge_faces.size() == 2);
+ face_start = edge_faces[(edge_faces[0] == face_start) ? 1 : 0];
+ face_vertex_start =
+ getBaseFaceEdges(refiner, face_start).FindIndex(edge_next);
+ dst_vertex_faces[face_count_ordered++] = face_start;
+ face_used[face_start] = true;
+ }
+ edge_start = edge_next;
+ }
+ }
+ // Verify ordering doesn't ruin connectivity information.
+ assert(face_count_ordered == num_vertex_faces);
+ assert(edge_count_ordered == num_vertex_edges);
+ opensubdiv_capi::checkOrientedVertexConnectivity(
+ num_vertex_edges, num_vertex_faces, &vertex_edges[0], &vertex_faces[0],
+ &dst_vertex_edges[0], &dst_vertex_faces[0]);
+ // For the release builds we're failing mesh construction so instead of
+ // nasty bugs the unsupported mesh will simply disappear from the viewport.
+ if (face_count_ordered != num_vertex_faces ||
+ edge_count_ordered != num_vertex_edges) {
+ return false;
+ }
+#else // OPENSUBDIV_ORIENT_TOPOLOGY
+ memcpy(&dst_vertex_edges[0], &vertex_edges[0],
+ sizeof(int) * num_vertex_edges);
+ memcpy(&dst_vertex_faces[0], &vertex_faces[0],
+ sizeof(int) * num_vertex_faces);
+#endif // OPENSUBDIV_ORIENT_TOPOLOGY
+ }
+ populateBaseLocalIndices(refiner);
+ return true;
+}
+
+template <>
+inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags(
+ TopologyRefiner& refiner,
+ const TopologyRefinerData& cb_data) {
+ using OpenSubdiv::Sdc::Crease;
+ const OpenSubdiv_Converter* converter = cb_data.converter;
+ const int num_edges = converter->getNumEdges(converter);
+ for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
+ const float sharpness =
+ opensubdiv_capi::getCompatibleEdgeSharpness(converter, edge_index);
+ setBaseEdgeSharpness(refiner, edge_index, sharpness);
+ }
+ // OpenSubdiv expects non-manifold vertices to be sharp but at the time it
+ // handles correct cases when vertex is a corner of plane. Currently mark
+ // vertices which are adjacent to a loose edge as sharp, but this decision
+ // needs some more investigation.
+ const int num_vertices = converter->getNumVertices(converter);
+ for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
+ ConstIndexArray vertex_edges = getBaseVertexEdges(refiner, vertex_index);
+ for (int i = 0; i < vertex_edges.size(); ++i) {
+ const int edge_index = vertex_edges[i];
+ ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge_index);
+ if (edge_faces.size() == 0) {
+ setBaseVertexSharpness(refiner, vertex_index,
+ Crease::SHARPNESS_INFINITE);
+ break;
+ }
+ }
+ if (vertex_edges.size() == 2) {
+ const int edge0 = vertex_edges[0], edge1 = vertex_edges[1];
+ const float sharpness0 = converter->getEdgeSharpness(converter, edge0);
+ const float sharpness1 = converter->getEdgeSharpness(converter, edge1);
+ const float sharpness = std::min(sharpness0, sharpness1);
+ setBaseVertexSharpness(refiner, vertex_index, sharpness);
+ }
+ }
+ return true;
+}
+
+template <>
+inline bool
+TopologyRefinerFactory<TopologyRefinerData>::assignFaceVaryingTopology(
+ TopologyRefiner& refiner,
+ const TopologyRefinerData& cb_data) {
+ const OpenSubdiv_Converter* converter = cb_data.converter;
+ const int num_layers = converter->getNumUVLayers(converter);
+ if (num_layers <= 0) {
+ // No UV maps, we can skip any face-varying data.
+ return true;
+ }
+ const int num_faces = getNumBaseFaces(refiner);
+ for (int layer_index = 0; layer_index < num_layers; ++layer_index) {
+ converter->precalcUVLayer(converter, layer_index);
+ const int num_uvs = converter->getNumUVCoordinates(converter);
+ // Fill in per-corner index of the UV.
+ const int channel = createBaseFVarChannel(refiner, num_uvs);
+ for (int face_index = 0; face_index < num_faces; ++face_index) {
+ Far::IndexArray dst_face_uvs =
+ getBaseFaceFVarValues(refiner, face_index, channel);
+ for (int corner = 0; corner < dst_face_uvs.size(); ++corner) {
+ const int uv_index =
+ converter->getFaceCornerUVIndex(converter, face_index, corner);
+ dst_face_uvs[corner] = uv_index;
+ }
+ }
+ converter->finishUVLayer(converter);
+ }
+ return true;
+}
+
+template <>
+inline void TopologyRefinerFactory<TopologyRefinerData>::reportInvalidTopology(
+ TopologyError /*errCode*/, const char* msg,
+ const TopologyRefinerData& /*mesh*/) {
+ printf("OpenSubdiv Error: %s\n", msg);
+}
+
+} /* namespace Far */
+} /* namespace OPENSUBDIV_VERSION */
+} /* namespace OpenSubdiv */
+
+namespace opensubdiv_capi {
+
+OpenSubdiv::Far::TopologyRefiner* createOSDTopologyRefinerFromConverter(
+ OpenSubdiv_Converter* converter) {
+ using OpenSubdiv::Sdc::Options;
+ using OpenSubdiv::Far::TopologyRefinerFactory;
+ const OpenSubdiv::Sdc::SchemeType scheme_type =
+ getSchemeTypeFromCAPI(converter->getSchemeType(converter));
+ const Options::FVarLinearInterpolation linear_interpolation =
+ getFVarLinearInterpolationFromCAPI(
+ converter->getFVarLinearInterpolation(converter));
+ Options options;
+ options.SetVtxBoundaryInterpolation(Options::VTX_BOUNDARY_EDGE_ONLY);
+ options.SetCreasingMethod(Options::CREASE_UNIFORM);
+ options.SetFVarLinearInterpolation(linear_interpolation);
+
+ TopologyRefinerFactory<TopologyRefinerData>::Options topology_options(
+ scheme_type, options);
+#ifdef OPENSUBDIV_VALIDATE_TOPOLOGY
+ topology_options.validateFullTopology = true;
+#endif
+ TopologyRefinerData cb_data;
+ cb_data.converter = converter;
+ return TopologyRefinerFactory<TopologyRefinerData>::Create(
+ cb_data, topology_options);
+}
+
+} // namespace opensubdiv_capi
diff --git a/intern/opensubdiv/internal/opensubdiv_converter_factory.h b/intern/opensubdiv/internal/opensubdiv_converter_factory.h
new file mode 100644
index 00000000000..451418813e1
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_converter_factory.h
@@ -0,0 +1,37 @@
+// Copyright 2015 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_CONVERTER_FACTORY_H_
+#define OPENSUBDIV_CONVERTER_FACTORY_H_
+
+#ifdef _MSC_VER
+# include <iso646.h>
+#endif
+
+#include <opensubdiv/far/topologyRefiner.h>
+
+struct OpenSubdiv_Converter;
+
+namespace opensubdiv_capi {
+
+OpenSubdiv::Far::TopologyRefiner* createOSDTopologyRefinerFromConverter(
+ struct OpenSubdiv_Converter* converter);
+
+} // namespace opensubdiv_capi
+
+#endif // OPENSUBDIV_CONVERTER_FACTORY_H_
diff --git a/intern/opensubdiv/internal/opensubdiv_converter_internal.cc b/intern/opensubdiv/internal/opensubdiv_converter_internal.cc
new file mode 100644
index 00000000000..56b5657121d
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_converter_internal.cc
@@ -0,0 +1,70 @@
+// Copyright 2018 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifdef _MSC_VER
+# include <iso646.h>
+#endif
+
+#include "internal/opensubdiv_converter_internal.h"
+
+#include <opensubdiv/sdc/crease.h>
+#include <cassert>
+
+namespace opensubdiv_capi {
+
+OpenSubdiv::Sdc::SchemeType getSchemeTypeFromCAPI(OpenSubdiv_SchemeType type) {
+ switch (type) {
+ case OSD_SCHEME_BILINEAR:
+ return OpenSubdiv::Sdc::SCHEME_BILINEAR;
+ case OSD_SCHEME_CATMARK:
+ return OpenSubdiv::Sdc::SCHEME_CATMARK;
+ case OSD_SCHEME_LOOP:
+ return OpenSubdiv::Sdc::SCHEME_LOOP;
+ }
+ assert(!"Unknown scheme type passed via C-API");
+ return OpenSubdiv::Sdc::SCHEME_CATMARK;
+}
+
+OpenSubdiv::Sdc::Options::FVarLinearInterpolation
+getFVarLinearInterpolationFromCAPI(
+ OpenSubdiv_FVarLinearInterpolation linear_interpolation) {
+ typedef OpenSubdiv::Sdc::Options Options;
+ switch (linear_interpolation) {
+ case OSD_FVAR_LINEAR_INTERPOLATION_NONE:
+ return Options::FVAR_LINEAR_NONE;
+ case OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY:
+ return Options::FVAR_LINEAR_CORNERS_ONLY;
+ case OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES:
+ return Options::FVAR_LINEAR_BOUNDARIES;
+ case OSD_FVAR_LINEAR_INTERPOLATION_ALL:
+ return Options::FVAR_LINEAR_ALL;
+ }
+ assert(!"Unknown fvar linear interpolation passed via C-API");
+ return Options::FVAR_LINEAR_NONE;
+}
+
+float getCompatibleEdgeSharpness(const OpenSubdiv_Converter* converter,
+ int edge_index) {
+ if (converter->getNumEdgeFaces(converter, edge_index) == 2) {
+ return converter->getEdgeSharpness(converter, edge_index);
+ } else {
+ return OpenSubdiv::Sdc::Crease::SHARPNESS_INFINITE;
+ }
+}
+
+} // namespace opensubdiv_capi
diff --git a/intern/opensubdiv/internal/opensubdiv_converter_internal.h b/intern/opensubdiv/internal/opensubdiv_converter_internal.h
new file mode 100644
index 00000000000..68518d67884
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_converter_internal.h
@@ -0,0 +1,50 @@
+// Copyright 2018 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_CONVERTER_INTERNAL_H_
+#define OPENSUBDIV_CONVERTER_INTERNAL_H_
+
+#ifdef _MSC_VER
+# include <iso646.h>
+#endif
+
+#include <opensubdiv/sdc/options.h>
+#include <opensubdiv/sdc/types.h>
+
+#include "opensubdiv_converter_capi.h"
+
+struct OpenSubdiv_Converter;
+
+namespace opensubdiv_capi {
+
+// Convert scheme type from C-API enum to an OpenSubdiv native enum.
+OpenSubdiv::Sdc::SchemeType getSchemeTypeFromCAPI(OpenSubdiv_SchemeType type);
+
+// Convert face-varying interpolation type from C-API to an OpenSubdiv
+// native enum.
+OpenSubdiv::Sdc::Options::FVarLinearInterpolation
+getFVarLinearInterpolationFromCAPI(
+ OpenSubdiv_FVarLinearInterpolation linear_interpolation);
+
+// Get edge sharpness in a way which makes OpenSubdiv happy.
+float getCompatibleEdgeSharpness(const OpenSubdiv_Converter* converter,
+ int edge_index);
+
+} // namespace opensubdiv_capi
+
+#endif // OPENSUBDIV_CONVERTER_INTERNAL_H_
diff --git a/intern/opensubdiv/internal/opensubdiv_converter_orient.cc b/intern/opensubdiv/internal/opensubdiv_converter_orient.cc
new file mode 100644
index 00000000000..449e9028180
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_converter_orient.cc
@@ -0,0 +1,66 @@
+// Copyright 2018 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#include "internal/opensubdiv_converter_orient.h"
+
+#include "internal/opensubdiv_internal.h"
+
+namespace opensubdiv_capi {
+
+void checkOrientedVertexConnectivity(const int num_vertex_edges,
+ const int num_vertex_faces,
+ const int* vertex_edges,
+ const int* vertex_faces,
+ const int* dst_vertex_edges,
+ const int* dst_vertex_faces) {
+#ifndef NDEBUG
+ for (int i = 0; i < num_vertex_faces; ++i) {
+ bool found = false;
+ for (int j = 0; j < num_vertex_faces; ++j) {
+ if (vertex_faces[i] == dst_vertex_faces[j]) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ assert(!"vert-faces connectivity ruined");
+ }
+ }
+ for (int i = 0; i < num_vertex_edges; ++i) {
+ bool found = false;
+ for (int j = 0; j < num_vertex_edges; ++j) {
+ if (vertex_edges[i] == dst_vertex_edges[j]) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ assert(!"vert-edges connectivity ruined");
+ }
+ }
+#else
+ (void) num_vertex_edges;
+ (void) num_vertex_faces;
+ (void) vertex_edges;
+ (void) vertex_faces;
+ (void) dst_vertex_edges;
+ (void) dst_vertex_faces;
+#endif
+}
+
+} // namespace opensubdiv_capi
diff --git a/intern/opensubdiv/internal/opensubdiv_converter_orient.h b/intern/opensubdiv/internal/opensubdiv_converter_orient.h
new file mode 100644
index 00000000000..b783007a0cb
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_converter_orient.h
@@ -0,0 +1,50 @@
+// Copyright 2018 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_CONVERTER_ORIENT_H_
+#define OPENSUBDIV_CONVERTER_ORIENT_H_
+
+#include <opensubdiv/far/types.h>
+
+// Set of utility functions which are needed to bring topology to an orientation
+// (or, winding, if you wish) which OpenSubdiv expects.
+
+namespace opensubdiv_capi {
+
+inline void reverseFaceVertices(int* face_vertices, const int num_vertices);
+
+// TODO(sergey): Document which value corresponds to which winding.
+inline int getLoopWinding(int vert0_of_face, int vert1_of_face);
+
+inline void reverseFaceLoops(
+ OpenSubdiv::Far::IndexArray* face_vertices,
+ OpenSubdiv::Far::IndexArray* face_edges);
+
+// Used for debugging, checks whether orientation happened correct.
+void checkOrientedVertexConnectivity(const int num_vertex_edges,
+ const int num_vertex_faces,
+ const int* vertex_edges,
+ const int* vertex_faces,
+ const int* dst_vertex_edges,
+ const int* dst_vertex_faces);
+
+} // namespace opensubdiv_capi
+
+#endif // OPENSUBDIV_CONVERTER_ORIENT_H_
+
+#include "internal/opensubdiv_converter_orient_impl.h"
diff --git a/intern/opensubdiv/internal/opensubdiv_converter_orient_impl.h b/intern/opensubdiv/internal/opensubdiv_converter_orient_impl.h
new file mode 100644
index 00000000000..3125bc600e5
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_converter_orient_impl.h
@@ -0,0 +1,66 @@
+// Copyright 2018 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_CONVERTER_ORIENT_IMPL_H_
+#define OPENSUBDIV_CONVERTER_ORIENT_IMPL_H_
+
+#include "internal/opensubdiv_converter_orient.h"
+
+#include <algorithm>
+#include <cmath>
+#include <utility>
+
+namespace opensubdiv_capi {
+
+inline void reverseFaceVertices(int* face_vertices, const int num_vertices) {
+ int last_vert = face_vertices[num_vertices - 1];
+ for (int i = num_vertices - 1; i > 0; --i) {
+ face_vertices[i] = face_vertices[i - 1];
+ }
+ face_vertices[0] = last_vert;
+}
+
+inline int getLoopWinding(int vert0_of_face, int vert1_of_face) {
+ int delta_face = vert1_of_face - vert0_of_face;
+ if (abs(delta_face) != 1) {
+ if (delta_face > 0) {
+ delta_face = -1;
+ } else {
+ delta_face = 1;
+ }
+ }
+ return delta_face;
+}
+
+inline void reverseFaceLoops(
+ OpenSubdiv::Far::IndexArray* face_vertices,
+ OpenSubdiv::Far::IndexArray* face_edges) {
+ const int num_face_vertices = face_vertices->size();
+ for (int i = 0; i < num_face_vertices / 2; ++i) {
+ const int j = num_face_vertices - i - 1;
+ if (i != j) {
+ std::swap((*face_vertices)[i], (*face_vertices)[j]);
+ std::swap((*face_edges)[i], (*face_edges)[j]);
+ }
+ }
+ reverseFaceVertices(&(*face_vertices)[0], num_face_vertices);
+}
+
+} // namespace opensubdiv_capi
+
+#endif // OPENSUBDIV_CONVERTER_ORIENT_IMPL_H_
diff --git a/intern/opensubdiv/internal/opensubdiv_device_context_cuda.cc b/intern/opensubdiv/internal/opensubdiv_device_context_cuda.cc
new file mode 100644
index 00000000000..875f503b9ab
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_device_context_cuda.cc
@@ -0,0 +1,226 @@
+// Adopted from OpenSubdiv with the following license:
+//
+// 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.
+
+#ifdef OPENSUBDIV_HAS_CUDA
+
+#ifdef _MSC_VER
+# include <iso646.h>
+#endif
+
+#include "opensubdiv_device_context_cuda.h"
+
+#if defined(_WIN32)
+# include <windows.h>
+#elif defined(__APPLE__)
+# include <OpenGL/OpenGL.h>
+#else
+# include <GL/glx.h>
+# include <X11/Xlib.h>
+#endif
+
+#include <cuda.h>
+#include <cuda_gl_interop.h>
+#include <cuda_runtime_api.h>
+#include <algorithm>
+#include <cstdio>
+
+#define message(fmt, ...)
+// #define message(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
+#define error(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
+
+namespace {
+
+int getCudaDeviceForCurrentGLContext() {
+ // Find and use the CUDA device for the current GL context
+ unsigned int interop_device_count = 0;
+ int interopDevices[1];
+ cudaError_t status = cudaGLGetDevices(&interop_device_count,
+ interopDevices,
+ 1,
+ cudaGLDeviceListCurrentFrame);
+ if (status == cudaErrorNoDevice || interop_device_count != 1) {
+ message("CUDA no interop devices found.\n");
+ return 0;
+ }
+ int device = interopDevices[0];
+#if defined(_WIN32)
+ return device;
+#elif defined(__APPLE__)
+ return device;
+#else // X11
+ Display* display = glXGetCurrentDisplay();
+ int screen = DefaultScreen(display);
+ if (device != screen) {
+ error("The CUDA interop device (%d) does not match "
+ "the screen used by the current GL context (%d), "
+ "which may cause slow performance on systems "
+ "with multiple GPU devices.",
+ device, screen);
+ }
+ message("CUDA init using device for current GL context: %d\n", device);
+ return device;
+#endif
+}
+
+// Beginning of GPU Architecture definitions.
+int convertSMVer2Cores_local(int major, int minor) {
+ // Defines for GPU Architecture types (using the SM version to determine
+ // the # of cores per SM
+ typedef struct {
+ int SM; // 0xMm (hexidecimal notation),
+ // M = SM Major version,
+ // and m = SM minor version
+ int Cores;
+ } sSMtoCores;
+
+ sSMtoCores nGpuArchCoresPerSM[] = {
+ {0x10, 8}, // Tesla Generation (SM 1.0) G80 class.
+ {0x11, 8}, // Tesla Generation (SM 1.1) G8x class.
+ {0x12, 8}, // Tesla Generation (SM 1.2) G9x class.
+ {0x13, 8}, // Tesla Generation (SM 1.3) GT200 class.
+ {0x20, 32}, // Fermi Generation (SM 2.0) GF100 class.
+ {0x21, 48}, // Fermi Generation (SM 2.1) GF10x class.
+ {0x30, 192}, // Fermi Generation (SM 3.0) GK10x class.
+ {-1, -1}};
+ int index = 0;
+ while (nGpuArchCoresPerSM[index].SM != -1) {
+ if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor)) {
+ return nGpuArchCoresPerSM[index].Cores;
+ }
+ index++;
+ }
+ printf("MapSMtoCores undefined SMversion %d.%d!\n", major, minor);
+ return -1;
+}
+
+// This function returns the best GPU (with maximum GFLOPS).
+int cutGetMaxGflopsDeviceId() {
+ int current_device = 0, sm_per_multiproc = 0;
+ int max_compute_perf = 0, max_perf_device = -1;
+ int device_count = 0, best_SM_arch = 0;
+ int compat_major, compat_minor;
+ cuDeviceGetCount(&device_count);
+ // Find the best major SM Architecture GPU device.
+ while (current_device < device_count) {
+ cuDeviceComputeCapability(&compat_major, &compat_minor, current_device);
+ if (compat_major > 0 && compat_major < 9999) {
+ best_SM_arch = std::max(best_SM_arch, compat_major);
+ }
+ current_device++;
+ }
+ // Find the best CUDA capable GPU device.
+ current_device = 0;
+ while (current_device < device_count) {
+ cuDeviceComputeCapability(&compat_major, &compat_minor, current_device);
+ if (compat_major == 9999 && compat_minor == 9999) {
+ sm_per_multiproc = 1;
+ } else {
+ sm_per_multiproc = convertSMVer2Cores_local(compat_major, compat_minor);
+ }
+ int multi_processor_count;
+ cuDeviceGetAttribute(&multi_processor_count,
+ CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT,
+ current_device);
+ int clock_rate;
+ cuDeviceGetAttribute(&clock_rate, CU_DEVICE_ATTRIBUTE_CLOCK_RATE,
+ current_device);
+ int compute_perf = multi_processor_count * sm_per_multiproc * clock_rate;
+ if (compute_perf > max_compute_perf) {
+ /* If we find GPU with SM major > 2, search only these */
+ if (best_SM_arch > 2) {
+ /* If our device==dest_SM_arch, choose this, or else pass. */
+ if (compat_major == best_SM_arch) {
+ max_compute_perf = compute_perf;
+ max_perf_device = current_device;
+ }
+ } else {
+ max_compute_perf = compute_perf;
+ max_perf_device = current_device;
+ }
+ }
+ ++current_device;
+ }
+ return max_perf_device;
+}
+
+} // namespace
+
+bool CudaDeviceContext::HAS_CUDA_VERSION_4_0() {
+#ifdef OPENSUBDIV_HAS_CUDA
+ static bool cuda_initialized = false;
+ static bool cuda_load_success = true;
+ if (!cuda_initialized) {
+ cuda_initialized = true;
+
+#ifdef OPENSUBDIV_HAS_CUEW
+ cuda_load_success = cuewInit(CUEW_INIT_CUDA) == CUEW_SUCCESS;
+ if (!cuda_load_success) {
+ fprintf(stderr, "Loading CUDA failed.\n");
+ }
+#endif
+ // Need to initialize CUDA here so getting device
+ // with the maximum FPLOS works fine.
+ if (cuInit(0) == CUDA_SUCCESS) {
+ // This is to deal with cases like NVidia Optimus,
+ // when there might be CUDA library installed but
+ // NVidia card is not being active.
+ if (cutGetMaxGflopsDeviceId() < 0) {
+ cuda_load_success = false;
+ }
+ } else {
+ cuda_load_success = false;
+ }
+ }
+ return cuda_load_success;
+#else
+ return false;
+#endif
+}
+
+CudaDeviceContext::CudaDeviceContext()
+ : initialized_(false) {
+}
+
+CudaDeviceContext::~CudaDeviceContext() {
+ cudaDeviceReset();
+}
+
+bool CudaDeviceContext::Initialize() {
+ // See if any cuda device is available.
+ int device_count = 0;
+ cudaGetDeviceCount(&device_count);
+ message("CUDA device count: %d\n", device_count);
+ if (device_count <= 0) {
+ return false;
+ }
+ cudaGLSetGLDevice(getCudaDeviceForCurrentGLContext());
+ initialized_ = true;
+ return true;
+}
+
+bool CudaDeviceContext::IsInitialized() const {
+ return initialized_;
+}
+
+#endif // OPENSUBDIV_HAS_CUDA
diff --git a/intern/opensubdiv/internal/opensubdiv_device_context_cuda.h b/intern/opensubdiv/internal/opensubdiv_device_context_cuda.h
new file mode 100644
index 00000000000..ef212df10f0
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_device_context_cuda.h
@@ -0,0 +1,54 @@
+// Adopted from OpenSubdiv with the following license:
+//
+// 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 OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_
+#define OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_
+
+#ifdef OPENSUBDIV_HAS_CUDA
+
+struct ID3D11Device;
+
+class CudaDeviceContext {
+ public:
+ CudaDeviceContext();
+ ~CudaDeviceContext();
+
+ static bool HAS_CUDA_VERSION_4_0();
+
+ // Initialze cuda device from the current GL context.
+ bool Initialize();
+
+ // Initialze cuda device from the ID3D11Device.
+ bool Initialize(ID3D11Device* device);
+
+ // Returns true if the cuda device has already been initialized.
+ bool IsInitialized() const;
+
+ private:
+ bool initialized_;
+};
+
+#endif // OPENSUBDIV_HAS_CUDA
+
+#endif // _OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_
diff --git a/intern/opensubdiv/internal/opensubdiv_device_context_opencl.cc b/intern/opensubdiv/internal/opensubdiv_device_context_opencl.cc
new file mode 100644
index 00000000000..00f58af894a
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_device_context_opencl.cc
@@ -0,0 +1,269 @@
+// Adopted from OpenSubdiv with the following license:
+//
+// 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 "opensubdiv_device_context_opencl.h"
+
+#ifdef OPENSUBDIV_HAS_OPENCL
+
+#if defined(_WIN32)
+# include <windows.h>
+#elif defined(__APPLE__)
+# include <OpenGL/OpenGL.h>
+#else
+# include <GL/glx.h>
+#endif
+
+#include <cstdio>
+#include <cstring>
+#include <string>
+#include <vector>
+
+#define message(...) // fprintf(stderr, __VA_ARGS__)
+#define error(...) fprintf(stderr, __VA_ARGS__)
+
+namespace {
+
+// Returns the first found platform.
+cl_platform_id findPlatform() {
+ cl_uint num_platforms;
+ cl_int ci_error_number = clGetPlatformIDs(0, NULL, &num_platforms);
+ if (ci_error_number != CL_SUCCESS) {
+ error("Error %d in clGetPlatformIDs call.\n", ci_error_number);
+ return NULL;
+ }
+ if (num_platforms == 0) {
+ error("No OpenCL platform found.\n");
+ return NULL;
+ }
+ std::vector<cl_platform_id> cl_platform_ids(num_platforms);
+ ci_error_number = clGetPlatformIDs(num_platforms, &cl_platform_ids[0], NULL);
+ char ch_buffer[1024];
+ for (cl_uint i = 0; i < num_platforms; ++i) {
+ ci_error_number = clGetPlatformInfo(cl_platform_ids[i],
+ CL_PLATFORM_NAME,
+ sizeof(ch_buffer),
+ ch_buffer,
+ NULL);
+ if (ci_error_number == CL_SUCCESS) {
+ cl_platform_id platform_id = cl_platform_ids[i];
+ return platform_id;
+ }
+ }
+ return NULL;
+}
+
+// Return the device in cl_devices which supports the extension.
+int findExtensionSupportedDevice(cl_device_id* cl_devices,
+ int num_devices,
+ const char* extension_name) {
+ // Find a device that supports sharing with GL/D3D11
+ // (SLI / X-fire configurations)
+ cl_int cl_error_number;
+ for (int i = 0; i < num_devices; ++i) {
+ // Get extensions string size.
+ size_t extensions_size;
+ cl_error_number = clGetDeviceInfo(cl_devices[i],
+ CL_DEVICE_EXTENSIONS,
+ 0,
+ NULL,
+ &extensions_size);
+ if (cl_error_number != CL_SUCCESS) {
+ error("Error %d in clGetDeviceInfo\n", cl_error_number);
+ return -1;
+ }
+ if (extensions_size > 0) {
+ // Get extensions string.
+ std::string extensions('\0', extensions_size);
+ cl_error_number = clGetDeviceInfo(cl_devices[i],
+ CL_DEVICE_EXTENSIONS,
+ extensions_size,
+ &extensions[0],
+ &extensions_size);
+ if (cl_error_number != CL_SUCCESS) {
+ error("Error %d in clGetDeviceInfo\n", cl_error_number);
+ continue;
+ }
+ // Parse string. This is bit deficient since the extentions
+ // is space separated.
+ //
+ // The actual string would be "cl_khr_d3d11_sharing"
+ // or "cl_nv_d3d11_sharing"
+ if (extensions.find(extension_name) != std::string::npos) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+} // namespace
+
+CLDeviceContext::CLDeviceContext()
+ : cl_context_(NULL),
+ cl_command_queue_(NULL) {
+}
+
+CLDeviceContext::~CLDeviceContext() {
+ if (cl_command_queue_) {
+ clReleaseCommandQueue(cl_command_queue_);
+ }
+ if (cl_context_) {
+ clReleaseContext(cl_context_);
+ }
+}
+
+bool CLDeviceContext::HAS_CL_VERSION_1_1() {
+#ifdef OPENSUBDIV_HAS_CLEW
+ static bool clew_initialized = false;
+ static bool clew_load_success;
+ if (!clew_initialized) {
+ clew_initialized = true;
+ clew_load_success = clewInit() == CLEW_SUCCESS;
+ if (!clew_load_success) {
+ error("Loading OpenCL failed.\n");
+ }
+ }
+ return clew_load_success;
+#endif
+ return true;
+}
+
+bool CLDeviceContext::Initialize() {
+#ifdef OPENSUBDIV_HAS_CLEW
+ if (!clGetPlatformIDs) {
+ error("Error clGetPlatformIDs function not bound.\n");
+ return false;
+ }
+#endif
+ cl_int cl_error_number;
+ cl_platform_id cp_platform = findPlatform();
+
+#if defined(_WIN32)
+ cl_context_properties props[] = {
+ CL_GL_CONTEXT_KHR,
+ (cl_context_properties)wglGetCurrentContext(),
+ CL_WGL_HDC_KHR,
+ (cl_context_properties)wglGetCurrentDC(),
+ CL_CONTEXT_PLATFORM,
+ (cl_context_properties)cp_platform,
+ 0};
+#elif defined(__APPLE__)
+ CGLContextObj kCGLContext = CGLGetCurrentContext();
+ CGLShareGroupObj kCGLShareGroup = CGLGetShareGroup(kCGLContext);
+ cl_context_properties props[] = {CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE,
+ (cl_context_properties)kCGLShareGroup,
+ 0};
+#else
+ cl_context_properties props[] = {
+ CL_GL_CONTEXT_KHR,
+ (cl_context_properties)glXGetCurrentContext(),
+ CL_GLX_DISPLAY_KHR,
+ (cl_context_properties)glXGetCurrentDisplay(),
+ CL_CONTEXT_PLATFORM,
+ (cl_context_properties)cp_platform,
+ 0};
+#endif
+
+#if defined(__APPLE__)
+ _clContext = clCreateContext(props, 0, NULL, clLogMessagesToStdoutAPPLE, NULL,
+ &cl_error_number);
+ if (cl_error_number != CL_SUCCESS) {
+ error("Error %d in clCreateContext\n", cl_error_number);
+ return false;
+ }
+ size_t devices_size = 0;
+ clGetGLContextInfoAPPLE(_clContext, kCGLContext,
+ CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE,
+ 0,
+ NULL,
+ &devices_size);
+ const int num_devices = devices_size / sizeof(cl_device_id);
+ if (num_devices == 0) {
+ error("No sharable devices.\n");
+ return false;
+ }
+ std::vector<cl_device_id> cl_devices(num_devices);
+ clGetGLContextInfoAPPLE(_clContext, kCGLContext,
+ CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE,
+ num_devices * sizeof(cl_device_id),
+ &cl_devices[0],
+ NULL);
+ int cl_device_used = 0;
+#else // not __APPLE__
+ // Get the number of GPU devices available to the platform.
+ cl_uint num_devices = 0;
+ clGetDeviceIDs(cp_platform, CL_DEVICE_TYPE_GPU, 0, NULL, &num_devices);
+ if (num_devices == 0) {
+ error("No CL GPU device found.\n");
+ return false;
+ }
+ // Create the device list.
+ std::vector<cl_device_id> cl_devices(num_devices);
+ clGetDeviceIDs(cp_platform,
+ CL_DEVICE_TYPE_GPU,
+ num_devices,
+ &cl_devices[0],
+ NULL);
+ const char* extension = "cl_khr_gl_sharing";
+ int cl_device_used = findExtensionSupportedDevice(&cl_devices[0],
+ num_devices,
+ extension);
+ if (cl_device_used < 0) {
+ error("No device found that supports CL/GL context sharing\n");
+ return false;
+ }
+ cl_context_ = clCreateContext(props,
+ 1,
+ &cl_devices[cl_device_used],
+ NULL, NULL,
+ &cl_error_number);
+#endif // not __APPLE__
+ if (cl_error_number != CL_SUCCESS) {
+ error("Error %d in clCreateContext\n", cl_error_number);
+ return false;
+ }
+ cl_command_queue_ = clCreateCommandQueue(cl_context_,
+ cl_devices[cl_device_used],
+ 0,
+ &cl_error_number);
+ if (cl_error_number != CL_SUCCESS) {
+ error("Error %d in clCreateCommandQueue\n", cl_error_number);
+ return false;
+ }
+ return true;
+}
+
+bool CLDeviceContext::IsInitialized() const {
+ return (cl_context_ != NULL);
+}
+
+cl_context CLDeviceContext::GetContext() const {
+ return cl_context_;
+}
+
+cl_command_queue CLDeviceContext::GetCommandQueue() const {
+ return cl_command_queue_;
+}
+
+#endif // OPENSUBDIV_HAS_OPENCL
diff --git a/intern/opensubdiv/internal/opensubdiv_device_context_opencl.h b/intern/opensubdiv/internal/opensubdiv_device_context_opencl.h
new file mode 100644
index 00000000000..bc751cb6954
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_device_context_opencl.h
@@ -0,0 +1,52 @@
+// Adopted from OpenSubdiv with the following license:
+//
+// 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 OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_
+#define OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_
+
+#ifdef OPENSUBDIV_HAS_OPENCL
+#include <opensubdiv/osd/opencl.h>
+
+class CLDeviceContext {
+ public:
+ static bool HAS_CL_VERSION_1_1();
+
+ CLDeviceContext();
+ ~CLDeviceContext();
+
+ bool Initialize();
+
+ bool IsInitialized() const;
+
+ cl_context GetContext() const;
+ cl_command_queue GetCommandQueue() const;
+
+ protected:
+ cl_context cl_context_;
+ cl_command_queue cl_command_queue_;
+};
+
+#endif // OPENSUBDIV_HAS_OPENCL
+
+#endif // _OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_
diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator.cc b/intern/opensubdiv/internal/opensubdiv_evaluator.cc
new file mode 100644
index 00000000000..29d42a903ba
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_evaluator.cc
@@ -0,0 +1,154 @@
+// Copyright 2015 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#include "opensubdiv_evaluator_capi.h"
+
+#include <new>
+#include "MEM_guardedalloc.h"
+
+#include "internal/opensubdiv_evaluator_internal.h"
+
+namespace {
+
+void setCoarsePositions(OpenSubdiv_Evaluator* evaluator,
+ const float* positions,
+ const int start_vertex_index, const int num_vertices) {
+ evaluator->internal->eval_output->setCoarsePositions(positions,
+ start_vertex_index,
+ num_vertices);
+}
+
+void setVaryingData(OpenSubdiv_Evaluator* evaluator,
+ const float* varying_data,
+ const int start_vertex_index, const int num_vertices) {
+ evaluator->internal->eval_output->setVaryingData(varying_data,
+ start_vertex_index,
+ num_vertices);
+}
+
+void setFaceVaryingData(OpenSubdiv_Evaluator* evaluator,
+ const float* face_varying_data,
+ const int start_vertex_index, const int num_vertices) {
+ evaluator->internal->eval_output->setFaceVaryingData(face_varying_data,
+ start_vertex_index,
+ num_vertices);
+}
+
+void setCoarsePositionsFromBuffer(OpenSubdiv_Evaluator* evaluator,
+ const void* buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices) {
+ evaluator->internal->eval_output->setCoarsePositionsFromBuffer(
+ buffer,
+ start_offset,
+ stride,
+ start_vertex_index,
+ num_vertices);
+}
+
+void setVaryingDataFromBuffer(OpenSubdiv_Evaluator* evaluator,
+ const void* buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices) {
+ evaluator->internal->eval_output->setVaryingDataFromBuffer(
+ buffer,
+ start_offset,
+ stride,
+ start_vertex_index,
+ num_vertices);
+}
+
+void setFaceVaryingDataFromBuffer(OpenSubdiv_Evaluator* evaluator,
+ const void* buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices) {
+ evaluator->internal->eval_output->setFaceVaryingDataFromBuffer(
+ buffer,
+ start_offset,
+ stride,
+ start_vertex_index,
+ num_vertices);
+}
+
+void refine(OpenSubdiv_Evaluator* evaluator) {
+ evaluator->internal->eval_output->refine();
+}
+
+void evaluateLimit(OpenSubdiv_Evaluator* evaluator,
+ const int ptex_face_index,
+ const float face_u, const float face_v,
+ float P[3], float dPdu[3], float dPdv[3]) {
+ evaluator->internal->eval_output->evaluateLimit(ptex_face_index,
+ face_u, face_v,
+ P, dPdu, dPdv);
+}
+
+void evaluateVarying(OpenSubdiv_Evaluator* evaluator,
+ const int ptex_face_index,
+ float face_u, float face_v,
+ float varying[3]) {
+ evaluator->internal->eval_output->evaluateVarying(ptex_face_index,
+ face_u, face_v,
+ varying);
+}
+
+void evaluateFaceVarying(OpenSubdiv_Evaluator* evaluator,
+ const int ptex_face_index,
+ float face_u, float face_v,
+ float face_varying[2]) {
+ evaluator->internal->eval_output->evaluateFaceVarying(ptex_face_index,
+ face_u, face_v,
+ face_varying);
+}
+
+void assignFunctionPointers(OpenSubdiv_Evaluator* evaluator) {
+ evaluator->setCoarsePositions = setCoarsePositions;
+ evaluator->setVaryingData = setVaryingData;
+ evaluator->setFaceVaryingData = setFaceVaryingData;
+
+ evaluator->setCoarsePositionsFromBuffer = setCoarsePositionsFromBuffer;
+ evaluator->setVaryingDataFromBuffer = setVaryingDataFromBuffer;
+ evaluator->setFaceVaryingDataFromBuffer = setFaceVaryingDataFromBuffer;
+
+ evaluator->refine = refine;
+
+ evaluator->evaluateLimit = evaluateLimit;
+ evaluator->evaluateVarying = evaluateVarying;
+ evaluator->evaluateFaceVarying = evaluateFaceVarying;
+}
+
+} // namespace
+
+OpenSubdiv_Evaluator* openSubdiv_createEvaluatorFromTopologyRefiner(
+ OpenSubdiv_TopologyRefiner* topology_refiner) {
+ OpenSubdiv_Evaluator* evaluator = OBJECT_GUARDED_NEW(OpenSubdiv_Evaluator);
+ assignFunctionPointers(evaluator);
+ evaluator->internal = openSubdiv_createEvaluatorInternal(topology_refiner);
+ return evaluator;
+}
+
+void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator* evaluator) {
+ openSubdiv_deleteEvaluatorInternal(evaluator->internal);
+ OBJECT_GUARDED_DELETE(evaluator, OpenSubdiv_Evaluator);
+}
diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc
new file mode 100644
index 00000000000..595df3eaa75
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc
@@ -0,0 +1,734 @@
+// Copyright 2018 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#include "internal/opensubdiv_evaluator_internal.h"
+
+#include <cassert>
+#include <cstdio>
+#include <vector>
+
+#ifdef _MSC_VER
+# include <iso646.h>
+#endif
+
+#include <opensubdiv/far/patchMap.h>
+#include <opensubdiv/far/patchTable.h>
+#include <opensubdiv/far/patchTableFactory.h>
+#include <opensubdiv/osd/cpuEvaluator.h>
+#include <opensubdiv/osd/cpuPatchTable.h>
+#include <opensubdiv/osd/cpuVertexBuffer.h>
+#include <opensubdiv/osd/mesh.h>
+#include <opensubdiv/osd/types.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "internal/opensubdiv_topology_refiner_internal.h"
+#include "opensubdiv_topology_refiner_capi.h"
+
+using OpenSubdiv::Osd::BufferDescriptor;
+using OpenSubdiv::Osd::CpuEvaluator;
+using OpenSubdiv::Osd::CpuPatchTable;
+using OpenSubdiv::Osd::CpuVertexBuffer;
+using OpenSubdiv::Osd::PatchCoord;
+using OpenSubdiv::Far::PatchMap;
+using OpenSubdiv::Far::PatchTable;
+using OpenSubdiv::Far::PatchTableFactory;
+using OpenSubdiv::Far::StencilTable;
+using OpenSubdiv::Far::StencilTableFactory;
+using OpenSubdiv::Far::TopologyRefiner;
+
+namespace opensubdiv_capi {
+
+namespace {
+
+// Helper class to wrap numerous of patch coordinates into a buffer.
+// Used to pass coordinates to the CPU evaluator. Other evaluators are not
+// supported.
+class PatchCoordBuffer : public std::vector<PatchCoord> {
+ public:
+ static PatchCoordBuffer* Create(int size) {
+ PatchCoordBuffer* buffer = new PatchCoordBuffer();
+ buffer->resize(size);
+ return buffer;
+ }
+
+ PatchCoord* BindCpuBuffer() {
+ return reinterpret_cast<PatchCoord*>(&(*this)[0]);
+ }
+
+ int GetNumVertices() {
+ return size();
+ }
+
+ void UpdateData(const PatchCoord* patch_coords, int num_patch_coords) {
+ memcpy(&(*this)[0],
+ reinterpret_cast<const void*>(patch_coords),
+ sizeof(PatchCoord) * num_patch_coords);
+ }
+};
+
+// Helper class to wrap single of patch coord into a buffer. Used to pass
+// coordinates to the CPU evaluator. Other evaluators are not supported.
+class SinglePatchCoordBuffer {
+ public:
+ static SinglePatchCoordBuffer* Create() {
+ return new SinglePatchCoordBuffer();
+ }
+
+ SinglePatchCoordBuffer() {
+ }
+
+ explicit SinglePatchCoordBuffer(const PatchCoord &patch_coord)
+ : patch_coord_(patch_coord) {
+ }
+
+ PatchCoord* BindCpuBuffer() {
+ return &patch_coord_;
+ }
+
+ int GetNumVertices() {
+ return 1;
+ }
+
+ void UpdateData(const PatchCoord &patch_coord) {
+ patch_coord_ = patch_coord;
+ }
+
+ protected:
+ PatchCoord patch_coord_;
+};
+
+// Helper class which is aimed to be used in cases when buffer is small enough
+// and better to be allocated in stack rather than in heap.
+//
+// TODO(sergey): Check if bare arrays could be used by CPU evaluator.
+template <int element_size, int num_vertices>
+class StackAllocatedBuffer {
+ public:
+ static PatchCoordBuffer* Create(int /*size*/) {
+ // TODO(sergey): Validate that requested dize is smaller than static
+ // stack memory size.
+ return new StackAllocatedBuffer<element_size, num_vertices>();
+ }
+
+ float* BindCpuBuffer() {
+ return &data_[0];
+ }
+
+ int GetNumVertices() {
+ return num_vertices;
+ }
+
+ // TODO(sergey): Support UpdateData().
+ protected:
+ float data_[element_size * num_vertices];
+};
+
+// Volatile evaluator which can be used from threads.
+//
+// TODO(sergey): Make it possible to evaluate coordinates in chunks.
+// TODO(sergey): Make it possible to evaluate multiple face varying layers.
+// (or maybe, it's cheap to create new evaluator for existing
+// topology to evaluate all needed face varying layers?)
+template <typename SRC_VERTEX_BUFFER,
+ typename EVAL_VERTEX_BUFFER,
+ typename STENCIL_TABLE,
+ typename PATCH_TABLE,
+ typename EVALUATOR,
+ typename DEVICE_CONTEXT = void>
+class VolatileEvalOutput {
+ public:
+ typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache;
+
+ VolatileEvalOutput(const StencilTable* vertex_stencils,
+ const StencilTable* varying_stencils,
+ const StencilTable* face_varying_stencils,
+ const int face_varying_channel,
+ const int face_varying_width,
+ const PatchTable* patch_table,
+ EvaluatorCache* evaluator_cache = NULL,
+ DEVICE_CONTEXT* device_context = NULL)
+ : src_desc_(0, 3, 3),
+ src_varying_desc_(0, 3, 3),
+ src_face_varying_desc_(0, face_varying_width, face_varying_width),
+ face_varying_channel_(face_varying_channel),
+ face_varying_width_(face_varying_width),
+ evaluator_cache_(evaluator_cache),
+ device_context_(device_context) {
+ // Total number of vertices = coarse points + refined points + local points.
+ int num_total_vertices = vertex_stencils->GetNumControlVertices() +
+ vertex_stencils->GetNumStencils();
+ num_coarse_vertices_ = vertex_stencils->GetNumControlVertices();
+ using OpenSubdiv::Osd::convertToCompatibleStencilTable;
+ src_data_ =
+ SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_);
+ src_varying_data_ =
+ SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_);
+ patch_table_ = PATCH_TABLE::Create(patch_table, device_context_);
+ patch_coords_ = NULL;
+ vertex_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(
+ vertex_stencils, device_context_);
+ varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(
+ varying_stencils, device_context_);
+ if (face_varying_stencils != NULL) {
+ num_coarse_face_varying_vertices_ =
+ face_varying_stencils->GetNumControlVertices();
+ const int num_total_face_varying_vertices =
+ face_varying_stencils->GetNumControlVertices() +
+ face_varying_stencils->GetNumStencils();
+ src_face_varying_data_ =
+ EVAL_VERTEX_BUFFER::Create(2,
+ num_total_face_varying_vertices,
+ device_context_);
+ face_varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(
+ face_varying_stencils, device_context_);
+ } else {
+ num_coarse_face_varying_vertices_ = 0;
+ src_face_varying_data_ = NULL;
+ face_varying_stencils_ = NULL;
+ }
+ }
+
+ ~VolatileEvalOutput() {
+ delete src_data_;
+ delete src_varying_data_;
+ delete src_face_varying_data_;
+ delete patch_table_;
+ delete vertex_stencils_;
+ delete varying_stencils_;
+ delete face_varying_stencils_;
+ }
+
+ // TODO(sergey): Implement binding API.
+
+ void updateData(const float* src, int start_vertex, int num_vertices) {
+ src_data_->UpdateData(src, start_vertex, num_vertices, device_context_);
+ }
+
+ void updateVaryingData(const float* src, int start_vertex, int num_vertices) {
+ src_varying_data_->UpdateData(src,
+ start_vertex,
+ num_vertices,
+ device_context_);
+ }
+
+ void updateFaceVaryingData(const float* src,
+ int start_vertex,
+ int num_vertices) {
+ src_face_varying_data_->UpdateData(src,
+ start_vertex,
+ num_vertices,
+ device_context_);
+ }
+
+ bool hasVaryingData() const {
+ // return varying_stencils_ != NULL;
+ // TODO(sergey): Check this based on actual topology.
+ return false;
+ }
+
+ bool hasFaceVaryingData() const {
+ return face_varying_stencils_ != NULL;
+ }
+
+ void refine() {
+ // Evaluate vertex positions.
+ BufferDescriptor dst_desc = src_desc_;
+ dst_desc.offset += num_coarse_vertices_ * src_desc_.stride;
+ const EVALUATOR* eval_instance =
+ OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
+ src_desc_,
+ dst_desc,
+ device_context_);
+ EVALUATOR::EvalStencils(src_data_, src_desc_,
+ src_data_, dst_desc,
+ vertex_stencils_,
+ eval_instance,
+ device_context_);
+ // Evaluate varying data.
+ if (hasVaryingData()) {
+ BufferDescriptor dst_varying_desc = src_varying_desc_;
+ dst_varying_desc.offset +=
+ num_coarse_vertices_ * src_varying_desc_.stride;
+ eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
+ evaluator_cache_,
+ src_varying_desc_,
+ dst_varying_desc,
+ device_context_);
+ EVALUATOR::EvalStencils(src_varying_data_, src_varying_desc_,
+ src_varying_data_, dst_varying_desc,
+ varying_stencils_,
+ eval_instance, device_context_);
+ }
+ // Evaluate face-varying data.
+ if (hasFaceVaryingData()) {
+ BufferDescriptor dst_face_varying_desc = src_face_varying_desc_;
+ dst_face_varying_desc.offset += num_coarse_face_varying_vertices_ *
+ src_face_varying_desc_.stride;
+ eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
+ evaluator_cache_,
+ src_face_varying_desc_,
+ dst_face_varying_desc,
+ device_context_);
+ EVALUATOR::EvalStencils(src_face_varying_data_, src_face_varying_desc_,
+ src_face_varying_data_, dst_face_varying_desc,
+ face_varying_stencils_,
+ eval_instance,
+ device_context_);
+ }
+ }
+
+ void evalPatchCoord(const PatchCoord& patch_coord, float P[3]) {
+ StackAllocatedBuffer<6, 1> vertex_data;
+ // TODO(sergey): Varying data is interleaved in vertex array, so need to
+ // adjust stride if there is a varying data.
+ // BufferDescriptor vertex_desc(0, 3, 6);
+ BufferDescriptor vertex_desc(0, 3, 3);
+ SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
+ const EVALUATOR* eval_instance =
+ OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
+ src_desc_,
+ vertex_desc,
+ device_context_);
+ EVALUATOR::EvalPatches(src_data_,
+ src_desc_,
+ &vertex_data,
+ vertex_desc,
+ patch_coord_buffer.GetNumVertices(),
+ &patch_coord_buffer,
+ patch_table_,
+ eval_instance,
+ device_context_);
+ const float* refined_vertices = vertex_data.BindCpuBuffer();
+ memcpy(P, refined_vertices, sizeof(float) * 3);
+ }
+
+ void evalPatchesWithDerivatives(const PatchCoord& patch_coord,
+ float P[3],
+ float dPdu[3], float dPdv[3]) {
+ StackAllocatedBuffer<6, 1> vertex_data, derivatives;
+ // TODO(sergey): Varying data is interleaved in vertex array, so need to
+ // adjust stride if there is a varying data.
+ // BufferDescriptor vertex_desc(0, 3, 6);
+ BufferDescriptor vertex_desc(0, 3, 3);
+ BufferDescriptor du_desc(0, 3, 6), dv_desc(3, 3, 6);
+ SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
+ const EVALUATOR* eval_instance =
+ OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
+ src_desc_,
+ vertex_desc,
+ du_desc, dv_desc,
+ device_context_);
+ EVALUATOR::EvalPatches(src_data_, src_desc_,
+ &vertex_data, vertex_desc,
+ &derivatives, du_desc,
+ &derivatives, dv_desc,
+ patch_coord_buffer.GetNumVertices(),
+ &patch_coord_buffer,
+ patch_table_,
+ eval_instance,
+ device_context_);
+ const float* refined_vertices = vertex_data.BindCpuBuffer();
+ memcpy(P, refined_vertices, sizeof(float) * 3);
+ if (dPdu != NULL || dPdv != NULL) {
+ const float* refined_derivatives = derivatives.BindCpuBuffer();
+ if (dPdu != NULL) {
+ memcpy(dPdu, refined_derivatives, sizeof(float) * 3);
+ }
+ if (dPdv != NULL) {
+ memcpy(dPdv, refined_derivatives + 3, sizeof(float) * 3);
+ }
+ }
+ }
+
+ void evalPatchVarying(const PatchCoord& patch_coord, float varying[3]) {
+ StackAllocatedBuffer<6, 1> varying_data;
+ BufferDescriptor varying_desc(3, 3, 6);
+ SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
+ const EVALUATOR* eval_instance =
+ OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
+ src_varying_desc_,
+ varying_desc,
+ device_context_);
+ EVALUATOR::EvalPatchesVarying(src_varying_data_, src_varying_desc_,
+ &varying_data, varying_desc,
+ patch_coord_buffer.GetNumVertices(),
+ &patch_coord_buffer,
+ patch_table_,
+ eval_instance,
+ device_context_);
+ const float* refined_varying = varying_data.BindCpuBuffer();
+ memcpy(varying, refined_varying, sizeof(float) * 3);
+ }
+
+ void evalPatchFaceVarying(const PatchCoord& patch_coord,
+ float face_varying[2]) {
+ StackAllocatedBuffer<2, 1> face_varying_data;
+ BufferDescriptor face_varying_desc(0, 2, 2);
+ SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
+ const EVALUATOR* eval_instance =
+ OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
+ src_face_varying_desc_,
+ face_varying_desc,
+ device_context_);
+ EVALUATOR::EvalPatchesFaceVarying(
+ src_face_varying_data_, src_face_varying_desc_,
+ &face_varying_data, face_varying_desc,
+ patch_coord_buffer.GetNumVertices(),
+ &patch_coord_buffer,
+ patch_table_,
+ face_varying_channel_,
+ eval_instance,
+ device_context_);
+ const float* refined_face_varying = face_varying_data.BindCpuBuffer();
+ memcpy(face_varying, refined_face_varying, sizeof(float) * 2);
+ }
+
+ private:
+ SRC_VERTEX_BUFFER* src_data_;
+ SRC_VERTEX_BUFFER* src_varying_data_;
+ EVAL_VERTEX_BUFFER* src_face_varying_data_;
+ PatchCoordBuffer* patch_coords_;
+ PATCH_TABLE* patch_table_;
+ BufferDescriptor src_desc_;
+ BufferDescriptor src_varying_desc_;
+ BufferDescriptor src_face_varying_desc_;
+
+ int num_coarse_vertices_;
+ int face_varying_channel_;
+ int face_varying_width_;
+ int num_coarse_face_varying_vertices_;
+
+ const STENCIL_TABLE* vertex_stencils_;
+ const STENCIL_TABLE* varying_stencils_;
+ const STENCIL_TABLE* face_varying_stencils_;
+
+ EvaluatorCache* evaluator_cache_;
+ DEVICE_CONTEXT* device_context_;
+};
+
+} // namespace
+
+// Note: Define as a class instead of typedcef to make it possible
+// to have anonymous class in opensubdiv_evaluator_internal.h
+class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer,
+ CpuVertexBuffer,
+ StencilTable,
+ CpuPatchTable,
+ CpuEvaluator> {
+ public:
+ CpuEvalOutput(const StencilTable* vertex_stencils,
+ const StencilTable* varying_stencils,
+ const StencilTable* face_varying_stencils,
+ const int face_varying_channel,
+ const int face_varying_width,
+ const PatchTable* patch_table,
+ EvaluatorCache* evaluator_cache = NULL)
+ : VolatileEvalOutput<CpuVertexBuffer,
+ CpuVertexBuffer,
+ StencilTable,
+ CpuPatchTable,
+ CpuEvaluator> (vertex_stencils,
+ varying_stencils,
+ face_varying_stencils,
+ face_varying_channel,
+ face_varying_width,
+ patch_table,
+ evaluator_cache) {
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Evaluator wrapper for anonymous API.
+
+CpuEvalOutputAPI::CpuEvalOutputAPI(CpuEvalOutput* implementation,
+ OpenSubdiv::Far::PatchMap* patch_map)
+ : implementation_(implementation),
+ patch_map_(patch_map) {
+}
+
+CpuEvalOutputAPI::~CpuEvalOutputAPI() {
+ delete implementation_;
+}
+
+void CpuEvalOutputAPI::setCoarsePositions(const float* positions,
+ const int start_vertex_index,
+ const int num_vertices) {
+ // TODO(sergey): Add sanity check on indices.
+ implementation_->updateData(positions, start_vertex_index, num_vertices);
+}
+
+void CpuEvalOutputAPI::setVaryingData(const float* varying_data,
+ const int start_vertex_index,
+ const int num_vertices) {
+ // TODO(sergey): Add sanity check on indices.
+ implementation_->updateVaryingData(varying_data,
+ start_vertex_index,
+ num_vertices);
+}
+
+void CpuEvalOutputAPI::setFaceVaryingData(const float* face_varying_data,
+ const int start_vertex_index,
+ const int num_vertices) {
+ // TODO(sergey): Add sanity check on indices.
+ implementation_->updateFaceVaryingData(face_varying_data,
+ start_vertex_index,
+ num_vertices);
+}
+
+void CpuEvalOutputAPI::setCoarsePositionsFromBuffer(
+ const void* buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices) {
+ // TODO(sergey): Add sanity check on indices.
+ const unsigned char* current_buffer = (unsigned char *)buffer;
+ current_buffer += start_offset;
+ for (int i = 0; i < num_vertices; ++i) {
+ const int current_vertex_index = start_vertex_index + i;
+ implementation_->updateData(reinterpret_cast<const float*>(current_buffer),
+ current_vertex_index, 1);
+ current_buffer += stride;
+ }
+}
+
+void CpuEvalOutputAPI::setVaryingDataFromBuffer(
+ const void* buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices) {
+ // TODO(sergey): Add sanity check on indices.
+ const unsigned char* current_buffer = (unsigned char *)buffer;
+ current_buffer += start_offset;
+ for (int i = 0; i < num_vertices; ++i) {
+ const int current_vertex_index = start_vertex_index + i;
+ implementation_->updateVaryingData(
+ reinterpret_cast<const float*>(current_buffer),
+ current_vertex_index, 1);
+ current_buffer += stride;
+ }
+}
+
+void CpuEvalOutputAPI::setFaceVaryingDataFromBuffer(
+ const void* buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices) {
+ // TODO(sergey): Add sanity check on indices.
+ const unsigned char* current_buffer = (unsigned char *)buffer;
+ current_buffer += start_offset;
+ for (int i = 0; i < num_vertices; ++i) {
+ const int current_vertex_index = start_vertex_index + i;
+ implementation_->updateFaceVaryingData(
+ reinterpret_cast<const float*>(current_buffer),
+ current_vertex_index, 1);
+ current_buffer += stride;
+ }
+}
+
+void CpuEvalOutputAPI::refine() {
+ implementation_->refine();
+}
+
+void CpuEvalOutputAPI::evaluateLimit(const int ptex_face_index,
+ float face_u, float face_v,
+ float P[3], float dPdu[3], float dPdv[3]) {
+ assert(face_u >= 0.0f);
+ assert(face_u <= 1.0f);
+ assert(face_v >= 0.0f);
+ assert(face_v <= 1.0f);
+ const PatchTable::PatchHandle* handle =
+ patch_map_->FindPatch(ptex_face_index, face_u, face_v);
+ PatchCoord patch_coord(*handle, face_u, face_v);
+ if (dPdu != NULL || dPdv != NULL) {
+ implementation_->evalPatchesWithDerivatives(patch_coord, P, dPdu, dPdv);
+ } else {
+ implementation_->evalPatchCoord(patch_coord, P);
+ }}
+
+void CpuEvalOutputAPI::evaluateVarying(const int ptex_face_index,
+ float face_u, float face_v,
+ float varying[3]) {
+ assert(face_u >= 0.0f);
+ assert(face_u <= 1.0f);
+ assert(face_v >= 0.0f);
+ assert(face_v <= 1.0f);
+ const PatchTable::PatchHandle* handle =
+ patch_map_->FindPatch(ptex_face_index, face_u, face_v);
+ PatchCoord patch_coord(*handle, face_u, face_v);
+ implementation_->evalPatchVarying(patch_coord, varying);
+}
+
+void CpuEvalOutputAPI::evaluateFaceVarying(const int ptex_face_index,
+ float face_u, float face_v,
+ float face_varying[2]) {
+ assert(face_u >= 0.0f);
+ assert(face_u <= 1.0f);
+ assert(face_v >= 0.0f);
+ assert(face_v <= 1.0f);
+ const PatchTable::PatchHandle* handle =
+ patch_map_->FindPatch(ptex_face_index, face_u, face_v);
+ PatchCoord patch_coord(*handle, face_u, face_v);
+ implementation_->evalPatchFaceVarying(patch_coord, face_varying);
+}
+
+} // namespace opensubdiv_capi
+
+OpenSubdiv_EvaluatorInternal::OpenSubdiv_EvaluatorInternal()
+ : eval_output(NULL),
+ patch_map(NULL),
+ patch_table(NULL) {
+}
+
+OpenSubdiv_EvaluatorInternal::~OpenSubdiv_EvaluatorInternal() {
+ delete eval_output;
+ delete patch_map;
+ delete patch_table;
+}
+
+OpenSubdiv_EvaluatorInternal* openSubdiv_createEvaluatorInternal(
+ OpenSubdiv_TopologyRefiner* topology_refiner) {
+ TopologyRefiner* refiner = topology_refiner->internal->osd_topology_refiner;
+ if (refiner == NULL) {
+ // Happens on bad topology.
+ return NULL;
+ }
+ // TODO(sergey): Base this on actual topology.
+ // const bool bas_varying_data = false;
+ const bool has_face_varying_data =
+ (refiner->GetNumFVarChannels() != 0);
+ const int level = topology_refiner->getSubdivisionLevel(topology_refiner);
+ // TODO(sergey): Query from topology refiner.
+ const bool is_adaptive = topology_refiner->getIsAdaptive(topology_refiner);
+ // Refine the topology with given settings.
+ // TODO(sergey): What if topology is already refined?
+ if (is_adaptive) {
+ TopologyRefiner::AdaptiveOptions options(level);
+ options.considerFVarChannels = has_face_varying_data;
+ options.useInfSharpPatch = false;
+ refiner->RefineAdaptive(options);
+ } else {
+ TopologyRefiner::UniformOptions options(level);
+ refiner->RefineUniform(options);
+ }
+ // Generate stencil table to update the bi-cubic patches control vertices
+ // after they have been re-posed (both for vertex & varying interpolation).
+ //
+ // Vertex stencils.
+ StencilTableFactory::Options vertex_stencil_options;
+ vertex_stencil_options.generateOffsets = true;
+ vertex_stencil_options.generateIntermediateLevels = is_adaptive;
+ const StencilTable* vertex_stencils =
+ StencilTableFactory::Create(*refiner, vertex_stencil_options);
+ // Varying stencils.
+ //
+ // TODO(sergey): Seems currently varying stencils are always required in
+ // OpenSubdiv itself.
+ const StencilTable* varying_stencils = NULL;
+ StencilTableFactory::Options varying_stencil_options;
+ varying_stencil_options.generateOffsets = true;
+ varying_stencil_options.generateIntermediateLevels = is_adaptive;
+ varying_stencil_options.interpolationMode =
+ StencilTableFactory::INTERPOLATE_VARYING;
+ varying_stencils =
+ StencilTableFactory::Create(*refiner, varying_stencil_options);
+ // Face warying stencil.
+ const StencilTable* face_varying_stencils = NULL;
+ if (has_face_varying_data) {
+ StencilTableFactory::Options face_varying_stencil_options;
+ face_varying_stencil_options.generateOffsets = true;
+ face_varying_stencil_options.generateIntermediateLevels = is_adaptive;
+ face_varying_stencil_options.interpolationMode =
+ StencilTableFactory::INTERPOLATE_FACE_VARYING;
+ // TODO(sergey): Make it configurable which face varying channel is being
+ // interpolated.
+ face_varying_stencil_options.fvarChannel = 0;
+ face_varying_stencils =
+ StencilTableFactory::Create(*refiner, face_varying_stencil_options);
+ }
+ // Generate bi-cubic patch table for the limit surface.
+ // TODO(sergey): Ideally we would want to expose end-cap settings via
+ // C-API to make it more generic. Currently it matches old Blender's
+ // subsurf code.
+ PatchTableFactory::Options patch_options(level);
+ patch_options.SetEndCapType(PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS);
+ patch_options.useInfSharpPatch = false;
+ patch_options.generateFVarTables = has_face_varying_data;
+ patch_options.generateFVarLegacyLinearPatches = false;
+ const PatchTable* patch_table = PatchTableFactory::Create(
+ *refiner, patch_options);
+ // Append local points stencils.
+ const StencilTable* local_point_stencil_table =
+ patch_table->GetLocalPointStencilTable();
+ if (local_point_stencil_table != NULL) {
+ const StencilTable* table =
+ StencilTableFactory::AppendLocalPointStencilTable(
+ *refiner, vertex_stencils, local_point_stencil_table);
+ delete vertex_stencils;
+ vertex_stencils = table;
+ }
+ const StencilTable* local_point_varying_stencil_table =
+ patch_table->GetLocalPointVaryingStencilTable();
+ if (local_point_varying_stencil_table != NULL) {
+ const StencilTable* table =
+ StencilTableFactory::AppendLocalPointStencilTable(
+ *refiner, varying_stencils, local_point_varying_stencil_table);
+ delete varying_stencils;
+ varying_stencils = table;
+ }
+ const StencilTable* local_point_face_varying_stencil_table =
+ patch_table->GetLocalPointFaceVaryingStencilTable();
+ if (local_point_face_varying_stencil_table != NULL) {
+ const StencilTable* table =
+ StencilTableFactory::AppendLocalPointStencilTableFaceVarying(
+ *refiner,
+ face_varying_stencils,
+ local_point_face_varying_stencil_table);
+ delete face_varying_stencils;
+ face_varying_stencils = table;
+ }
+ // Create OpenSubdiv's CPU side evaluator.
+ // TODO(sergey): Make it possible to use different evaluators.
+ opensubdiv_capi::CpuEvalOutput* eval_output =
+ new opensubdiv_capi::CpuEvalOutput(vertex_stencils,
+ varying_stencils,
+ face_varying_stencils,
+ 0, 2,
+ patch_table);
+ OpenSubdiv::Far::PatchMap* patch_map = new PatchMap(*patch_table);
+ // Wrap everything we need into an object which we control from our side.
+ OpenSubdiv_EvaluatorInternal* evaluator_descr;
+ evaluator_descr = OBJECT_GUARDED_NEW(OpenSubdiv_EvaluatorInternal);
+ evaluator_descr->eval_output =
+ new opensubdiv_capi::CpuEvalOutputAPI(eval_output, patch_map);
+ evaluator_descr->patch_map = patch_map;
+ evaluator_descr->patch_table = patch_table;
+ // TOOD(sergey): Look into whether we've got duplicated stencils arrays.
+ delete vertex_stencils;
+ delete varying_stencils;
+ delete face_varying_stencils;
+ return evaluator_descr;
+}
+
+void openSubdiv_deleteEvaluatorInternal(
+ OpenSubdiv_EvaluatorInternal* evaluator) {
+ OBJECT_GUARDED_DELETE(evaluator, OpenSubdiv_EvaluatorInternal);
+}
diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h
new file mode 100644
index 00000000000..cc69db6abc6
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h
@@ -0,0 +1,134 @@
+// Copyright 2018 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_EVALUATOR_INTERNAL_H_
+#define OPENSUBDIV_EVALUATOR_INTERNAL_H_
+
+#ifdef _MSC_VER
+# include <iso646.h>
+#endif
+
+#include <opensubdiv/far/patchMap.h>
+#include <opensubdiv/far/patchTable.h>
+
+struct OpenSubdiv_TopologyRefiner;
+
+namespace opensubdiv_capi {
+
+// Anonymous forward declaration of actual evaluator implementation.
+class CpuEvalOutput;
+
+// Wrapper around implementaiton, which defines API which we are capable to
+// provide over the implementation.
+//
+// TODO(sergey): It is almost the same as C-API object, so ideally need to
+// merge them somehow, but how to do this and keep files with all the templates
+// and such separate?
+class CpuEvalOutputAPI {
+ public:
+ // NOTE: API object becomes an owner of evaluator. Patch we are referencing.
+ CpuEvalOutputAPI(CpuEvalOutput* implementation,
+ OpenSubdiv::Far::PatchMap* patch_map);
+ ~CpuEvalOutputAPI();
+
+ // Set coarse positions from a continuous array of coordinates.
+ void setCoarsePositions(const float* positions,
+ const int start_vertex_index,
+ const int num_vertices);
+ // Set varying data from a continuous array of data.
+ void setVaryingData(const float* varying_data,
+ const int start_vertex_index, const int num_vertices);
+ // Set face varying data from a continuous array of data.
+ //
+ // TODO(sergey): Find a better name for vertex here. It is not the vertex of
+ // geometry, but a vertex of UV map.
+ void setFaceVaryingData(const float* varying_data,
+ const int start_vertex_index, const int num_vertices);
+
+ // Set coarse vertex position from a continuous memory buffer where
+ // first coordinate starts at offset of `start_offset` and there is `stride`
+ // bytes between adjacent vertex coordinates.
+ void setCoarsePositionsFromBuffer(const void* buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices);
+ // Set varying data from a continuous memory buffer where
+ // first coordinate starts at offset of `start_offset` and there is `stride`
+ // bytes between adjacent vertex coordinates.
+ void setVaryingDataFromBuffer(const void* buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices);
+ // Set face varying data from a continuous memory buffer where
+ // first coordinate starts at offset of `start_offset` and there is `stride`
+ // bytes between adjacent vertex coordinates.
+ //
+ // TODO(sergey): Find a better name for vertex here. It is not the vertex of
+ // geometry, but a vertex of UV map.
+ void setFaceVaryingDataFromBuffer(const void* buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices);
+
+ // Refine after coarse positions update.
+ void refine();
+
+ // Evaluate given ptex face at given bilinear coordinate.
+ // If derivatives are NULL, they will not be evaluated.
+ void evaluateLimit(const int ptex_face_index,
+ float face_u, float face_v,
+ float P[3], float dPdu[3], float dPdv[3]);
+
+ // Evaluate varying data at a given bilinear coordinate of given ptex face.
+ void evaluateVarying(const int ptes_face_index,
+ float face_u, float face_v,
+ float varying[3]);
+
+ // Evaluate facee-varying data at a given bilinear coordinate of given
+ // ptex face.
+ void evaluateFaceVarying(const int ptes_face_index,
+ float face_u, float face_v,
+ float face_varying[2]);
+
+ protected:
+ CpuEvalOutput* implementation_;
+ OpenSubdiv::Far::PatchMap* patch_map_;
+};
+
+} // namespace opensubdiv_capi
+
+struct OpenSubdiv_EvaluatorInternal {
+ public:
+ OpenSubdiv_EvaluatorInternal();
+ ~OpenSubdiv_EvaluatorInternal();
+
+ opensubdiv_capi::CpuEvalOutputAPI* eval_output;
+ const OpenSubdiv::Far::PatchMap* patch_map;
+ const OpenSubdiv::Far::PatchTable* patch_table;
+};
+
+OpenSubdiv_EvaluatorInternal* openSubdiv_createEvaluatorInternal(
+ struct OpenSubdiv_TopologyRefiner* topology_refiner);
+
+void openSubdiv_deleteEvaluatorInternal(
+ OpenSubdiv_EvaluatorInternal* evaluator);
+
+#endif // OPENSUBDIV_EVALUATOR_INTERNAL_H_
diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh.cc b/intern/opensubdiv/internal/opensubdiv_gl_mesh.cc
new file mode 100644
index 00000000000..34d27591d0b
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_gl_mesh.cc
@@ -0,0 +1,287 @@
+// Copyright 2013 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+// Contributor(s): Brecht van Lommel
+
+#include "opensubdiv_gl_mesh_capi.h"
+
+#ifdef _MSC_VER
+# include <iso646.h>
+#endif
+
+#include <opensubdiv/far/stencilTable.h>
+#include <opensubdiv/osd/glMesh.h>
+#include <opensubdiv/osd/glPatchTable.h>
+
+using OpenSubdiv::Far::StencilTable;
+using OpenSubdiv::Osd::GLMeshInterface;
+using OpenSubdiv::Osd::GLPatchTable;
+using OpenSubdiv::Osd::Mesh;
+using OpenSubdiv::Osd::MeshBitset;
+
+// CPU backend.
+#include <opensubdiv/osd/cpuEvaluator.h>
+#include <opensubdiv/osd/cpuGLVertexBuffer.h>
+using OpenSubdiv::Osd::CpuGLVertexBuffer;
+using OpenSubdiv::Osd::CpuEvaluator;
+typedef Mesh<CpuGLVertexBuffer,
+ StencilTable,
+ CpuEvaluator,
+ GLPatchTable> OsdCpuMesh;
+// OpenMP backend.
+#ifdef OPENSUBDIV_HAS_OPENMP
+# include <opensubdiv/osd/ompEvaluator.h>
+using OpenSubdiv::Osd::OmpEvaluator;
+typedef Mesh<CpuGLVertexBuffer,
+ StencilTable,
+ OmpEvaluator,
+ GLPatchTable> OsdOmpMesh;
+#endif
+// OpenCL backend.
+#ifdef OPENSUBDIV_HAS_OPENCL
+# include <opensubdiv/osd/clEvaluator.h>
+# include <opensubdiv/osd/clGLVertexBuffer.h>
+# include "opensubdiv_device_context_opencl.h"
+using OpenSubdiv::Osd::CLEvaluator;
+using OpenSubdiv::Osd::CLGLVertexBuffer;
+using OpenSubdiv::Osd::CLStencilTable;
+/* TODO(sergey): Use CLDeviceContext similar to OSD examples? */
+typedef Mesh<CLGLVertexBuffer,
+ CLStencilTable,
+ CLEvaluator,
+ GLPatchTable,
+ CLDeviceContext> OsdCLMesh;
+static CLDeviceContext g_cl_device_context;
+#endif
+// CUDA backend.
+#ifdef OPENSUBDIV_HAS_CUDA
+# include <opensubdiv/osd/cudaEvaluator.h>
+# include <opensubdiv/osd/cudaGLVertexBuffer.h>
+# include "opensubdiv_device_context_cuda.h"
+using OpenSubdiv::Osd::CudaEvaluator;
+using OpenSubdiv::Osd::CudaGLVertexBuffer;
+using OpenSubdiv::Osd::CudaStencilTable;
+typedef Mesh<CudaGLVertexBuffer,
+ CudaStencilTable,
+ CudaEvaluator,
+ GLPatchTable> OsdCudaMesh;
+static CudaDeviceContext g_cuda_device_context;
+#endif
+// Transform feedback backend.
+#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
+# include <opensubdiv/osd/glVertexBuffer.h>
+# include <opensubdiv/osd/glXFBEvaluator.h>
+using OpenSubdiv::Osd::GLXFBEvaluator;
+using OpenSubdiv::Osd::GLStencilTableTBO;
+using OpenSubdiv::Osd::GLVertexBuffer;
+typedef Mesh<GLVertexBuffer,
+ GLStencilTableTBO,
+ GLXFBEvaluator,
+ GLPatchTable> OsdGLSLTransformFeedbackMesh;
+#endif
+// GLSL compute backend.
+#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
+# include <opensubdiv/osd/glComputeEvaluator.h>
+# include <opensubdiv/osd/glVertexBuffer.h>
+using OpenSubdiv::Osd::GLComputeEvaluator;
+using OpenSubdiv::Osd::GLStencilTableSSBO;
+using OpenSubdiv::Osd::GLVertexBuffer;
+typedef Mesh<GLVertexBuffer,
+ GLStencilTableSSBO,
+ GLComputeEvaluator,
+ GLPatchTable> OsdGLSLComputeMesh;
+#endif
+
+#include <string>
+#include <vector>
+
+#include "MEM_guardedalloc.h"
+
+#include "opensubdiv_topology_refiner_capi.h"
+#include "internal/opensubdiv_gl_mesh_draw.h"
+#include "internal/opensubdiv_gl_mesh_fvar.h"
+#include "internal/opensubdiv_gl_mesh_internal.h"
+#include "internal/opensubdiv_topology_refiner_internal.h"
+
+namespace {
+
+GLMeshInterface* createGLMeshInterface(
+ OpenSubdiv::Far::TopologyRefiner* topology_refiner,
+ const MeshBitset& bits,
+ const int num_vertex_elements,
+ const int num_varying_elements,
+ const int level,
+ eOpenSubdivEvaluator evaluator_type) {
+ GLMeshInterface* mesh = NULL;
+ switch (evaluator_type) {
+#define CHECK_EVALUATOR_TYPE(type, class) \
+ case OPENSUBDIV_EVALUATOR_##type: \
+ mesh = new class(topology_refiner, \
+ num_vertex_elements, \
+ num_varying_elements, \
+ level, \
+ bits); \
+ break;
+
+#define CHECK_EVALUATOR_TYPE_STUB(type) \
+ case OPENSUBDIV_EVALUATOR_##type: \
+ mesh = NULL; \
+ break;
+
+ CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh)
+#ifdef OPENSUBDIV_HAS_OPENMP
+ CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh)
+#else
+ CHECK_EVALUATOR_TYPE_STUB(OPENMP)
+#endif
+#ifdef OPENSUBDIV_HAS_OPENCL
+ CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh)
+#else
+ CHECK_EVALUATOR_TYPE_STUB(OPENCL)
+#endif
+#ifdef OPENSUBDIV_HAS_CUDA
+ CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh)
+#else
+ CHECK_EVALUATOR_TYPE_STUB(CUDA)
+#endif
+#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
+ CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK, OsdGLSLTransformFeedbackMesh)
+#else
+ CHECK_EVALUATOR_TYPE_STUB(GLSL_TRANSFORM_FEEDBACK)
+#endif
+#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
+ CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh)
+#else
+ CHECK_EVALUATOR_TYPE_STUB(GLSL_COMPUTE)
+#endif
+
+#undef CHECK_EVALUATOR_TYPE
+#undef CHECK_EVALUATOR_TYPE_STUB
+ }
+ return mesh;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// GLMesh structure "methods".
+
+opensubdiv_capi::GLMeshFVarData* createFVarData(
+ OpenSubdiv::Far::TopologyRefiner* topology_refiner,
+ GLMeshInterface* mesh,
+ const float *fvar_src_buffer) {
+ using opensubdiv_capi::GLMeshFVarData;
+ GLMeshFVarData* fvar_data = new GLMeshFVarData();
+ fvar_data->create(topology_refiner,
+ mesh->GetFarPatchTable(),
+ 2,
+ fvar_src_buffer);
+ return fvar_data;
+}
+
+unsigned int getPatchIndexBuffer(OpenSubdiv_GLMesh* gl_mesh) {
+ return gl_mesh->internal->mesh_interface
+ ->GetPatchTable()
+ ->GetPatchIndexBuffer();
+}
+
+void bindVertexBuffer(OpenSubdiv_GLMesh* gl_mesh) {
+ gl_mesh->internal->mesh_interface->BindVertexBuffer();
+}
+
+void setCoarsePositions(OpenSubdiv_GLMesh* gl_mesh,
+ const float* positions,
+ const int start_vertex,
+ const int num_vertices) {
+ gl_mesh->internal->mesh_interface->UpdateVertexBuffer(positions,
+ start_vertex,
+ num_vertices);
+}
+
+void refine(OpenSubdiv_GLMesh* gl_mesh) {
+ gl_mesh->internal->mesh_interface->Refine();
+}
+
+void synchronize(struct OpenSubdiv_GLMesh* gl_mesh) {
+ gl_mesh->internal->mesh_interface->Synchronize();
+}
+
+void assignFunctionPointers(OpenSubdiv_GLMesh* gl_mesh) {
+ gl_mesh->getPatchIndexBuffer = getPatchIndexBuffer;
+ gl_mesh->bindVertexBuffer = bindVertexBuffer;
+ gl_mesh->setCoarsePositions = setCoarsePositions;
+ gl_mesh->refine = refine;
+ gl_mesh->synchronize = synchronize;
+
+ gl_mesh->prepareDraw = opensubdiv_capi::GLMeshDisplayPrepare;
+ gl_mesh->drawPatches = opensubdiv_capi::GLMeshDisplayDrawPatches;
+}
+
+} // namespace
+
+struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
+ OpenSubdiv_TopologyRefiner* topology_refiner,
+ eOpenSubdivEvaluator evaluator_type) {
+ using OpenSubdiv::Far::TopologyRefiner;
+ TopologyRefiner* osd_topology_refiner =
+ topology_refiner->internal->osd_topology_refiner;
+ // TODO(sergey): Query this from refiner.
+ const bool is_adaptive = false;
+ MeshBitset bits;
+ bits.set(OpenSubdiv::Osd::MeshAdaptive, is_adaptive);
+ bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, 0);
+ bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, 1);
+ bits.set(OpenSubdiv::Osd::MeshFVarData, 1);
+ bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, 1);
+ const int num_vertex_elements = 3;
+ const int num_varying_elements = 3;
+ GLMeshInterface* mesh = createGLMeshInterface(
+ osd_topology_refiner,
+ bits,
+ num_vertex_elements,
+ num_varying_elements,
+ osd_topology_refiner->GetMaxLevel(),
+ evaluator_type);
+ if (mesh == NULL) {
+ return NULL;
+ }
+ OpenSubdiv_GLMesh* gl_mesh = OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh);
+ assignFunctionPointers(gl_mesh);
+ gl_mesh->internal = new OpenSubdiv_GLMeshInternal();
+ gl_mesh->internal->evaluator_type = evaluator_type;
+ gl_mesh->internal->mesh_interface = mesh;
+ // Face-varying support.
+ // TODO(sergey): This part needs to be re-done.
+ if (osd_topology_refiner->GetNumFVarChannels() > 0) {
+ // TODO(sergey): This is a temporary stub to get things compiled. Need
+ // to store base level UVs somewhere else.
+ std::vector<float> uvs;
+ std::vector<float> fvar_data_buffer;
+ opensubdiv_capi::interpolateFVarData(*osd_topology_refiner,
+ uvs,
+ &fvar_data_buffer);
+ gl_mesh->internal->fvar_data = createFVarData(osd_topology_refiner,
+ mesh,
+ &fvar_data_buffer[0]);
+ } else {
+ gl_mesh->internal->fvar_data = NULL;
+ }
+ return gl_mesh;
+}
+
+void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh) {
+ delete gl_mesh->internal;
+ OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh);
+}
diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.cc b/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.cc
new file mode 100644
index 00000000000..0d2f8dc9842
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.cc
@@ -0,0 +1,587 @@
+// Copyright 2013 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#include "internal/opensubdiv_gl_mesh_draw.h"
+
+#ifdef _MSC_VER
+# include <iso646.h>
+#endif
+
+#include <GL/glew.h>
+#include <cmath>
+#include <cstdio>
+
+#include <opensubdiv/osd/glMesh.h>
+
+#ifdef OPENSUBDIV_HAS_CUDA
+# include <opensubdiv/osd/cudaGLVertexBuffer.h>
+#endif // OPENSUBDIV_HAS_CUDA
+
+#include <opensubdiv/osd/cpuEvaluator.h>
+#include <opensubdiv/osd/cpuGLVertexBuffer.h>
+
+#include "internal/opensubdiv_gl_mesh_fvar.h"
+#include "internal/opensubdiv_gl_mesh_internal.h"
+#include "opensubdiv_capi.h"
+#include "opensubdiv_gl_mesh_capi.h"
+
+using OpenSubdiv::Osd::GLMeshInterface;
+
+extern "C" char datatoc_gpu_shader_opensubdiv_vertex_glsl[];
+extern "C" char datatoc_gpu_shader_opensubdiv_geometry_glsl[];
+extern "C" char datatoc_gpu_shader_opensubdiv_fragment_glsl[];
+
+// TODO(sergey): Those are a bit of bad level calls :S
+extern "C" {
+void copy_m3_m3(float m1[3][3], float m2[3][3]);
+void copy_m3_m4(float m1[3][3], float m2[4][4]);
+void adjoint_m3_m3(float m1[3][3], float m[3][3]);
+float determinant_m3_array(float m[3][3]);
+bool invert_m3_m3(float m1[3][3], float m2[3][3]);
+bool invert_m3(float m[3][3]);
+void transpose_m3(float mat[3][3]);
+}
+
+#define MAX_LIGHTS 8
+#define SUPPORT_COLOR_MATERIAL
+
+typedef struct Light {
+ float position[4];
+ float ambient[4];
+ float diffuse[4];
+ float specular[4];
+ float spot_direction[4];
+#ifdef SUPPORT_COLOR_MATERIAL
+ float constant_attenuation;
+ float linear_attenuation;
+ float quadratic_attenuation;
+ float spot_cutoff;
+ float spot_exponent;
+ float spot_cos_cutoff;
+ float pad, pad2;
+#endif
+} Light;
+
+typedef struct Lighting {
+ Light lights[MAX_LIGHTS];
+ int num_enabled;
+} Lighting;
+
+typedef struct Transform {
+ float projection_matrix[16];
+ float model_view_matrix[16];
+ float normal_matrix[9];
+} Transform;
+
+static bool g_use_osd_glsl = false;
+static int g_active_uv_index = 0;
+
+static GLuint g_flat_fill_solid_program = 0;
+static GLuint g_flat_fill_texture2d_program = 0;
+static GLuint g_smooth_fill_solid_program = 0;
+static GLuint g_smooth_fill_texture2d_program = 0;
+
+static GLuint g_flat_fill_solid_shadeless_program = 0;
+static GLuint g_flat_fill_texture2d_shadeless_program = 0;
+static GLuint g_smooth_fill_solid_shadeless_program = 0;
+static GLuint g_smooth_fill_texture2d_shadeless_program = 0;
+
+static GLuint g_wireframe_program = 0;
+
+static GLuint g_lighting_ub = 0;
+static Lighting g_lighting_data;
+static Transform g_transform;
+
+namespace {
+
+GLuint compileShader(GLenum shaderType,
+ const char* version,
+ const char* define,
+ const char* source) {
+ const char* sources[] = {
+ version, define,
+#ifdef SUPPORT_COLOR_MATERIAL
+ "#define SUPPORT_COLOR_MATERIAL\n",
+#else
+ "",
+#endif
+ source,
+ };
+
+ GLuint shader = glCreateShader(shaderType);
+ glShaderSource(shader, 4, sources, NULL);
+ glCompileShader(shader);
+
+ GLint status;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+ if (status == GL_FALSE) {
+ GLchar emsg[1024];
+ glGetShaderInfoLog(shader, sizeof(emsg), 0, emsg);
+ fprintf(stderr, "Error compiling GLSL: %s\n", emsg);
+ fprintf(stderr, "Version: %s\n", version);
+ fprintf(stderr, "Defines: %s\n", define);
+ fprintf(stderr, "Source: %s\n", source);
+ return 0;
+ }
+
+ return shader;
+}
+
+GLuint linkProgram(const char* version, const char* define) {
+ GLuint vertexShader =
+ compileShader(GL_VERTEX_SHADER, version, define,
+ datatoc_gpu_shader_opensubdiv_vertex_glsl);
+ if (vertexShader == 0) {
+ return 0;
+ }
+ GLuint geometryShader =
+ compileShader(GL_GEOMETRY_SHADER, version, define,
+ datatoc_gpu_shader_opensubdiv_geometry_glsl);
+ if (geometryShader == 0) {
+ return 0;
+ }
+ GLuint fragmentShader =
+ compileShader(GL_FRAGMENT_SHADER, version, define,
+ datatoc_gpu_shader_opensubdiv_fragment_glsl);
+ if (fragmentShader == 0) {
+ return 0;
+ }
+
+ GLuint program = glCreateProgram();
+
+ glAttachShader(program, vertexShader);
+ glAttachShader(program, geometryShader);
+ glAttachShader(program, fragmentShader);
+
+ glBindAttribLocation(program, 0, "position");
+ glBindAttribLocation(program, 1, "normal");
+
+ glLinkProgram(program);
+
+ glDeleteShader(vertexShader);
+ glDeleteShader(geometryShader);
+ glDeleteShader(fragmentShader);
+
+ GLint status;
+ glGetProgramiv(program, GL_LINK_STATUS, &status);
+ if (status == GL_FALSE) {
+ GLchar emsg[1024];
+ glGetProgramInfoLog(program, sizeof(emsg), 0, emsg);
+ fprintf(stderr, "Error linking GLSL program : %s\n", emsg);
+ fprintf(stderr, "Defines: %s\n", define);
+ glDeleteProgram(program);
+ return 0;
+ }
+
+ glUniformBlockBinding(program, glGetUniformBlockIndex(program, "Lighting"),
+ 0);
+
+ if (GLEW_VERSION_4_1) {
+ glProgramUniform1i(
+ program, glGetUniformLocation(program, "texture_buffer"), 0);
+ glProgramUniform1i(
+ program, glGetUniformLocation(program, "FVarDataOffsetBuffer"), 30);
+ glProgramUniform1i(
+ program, glGetUniformLocation(program, "FVarDataBuffer"), 31);
+ } else {
+ glUseProgram(program);
+ glUniform1i(glGetUniformLocation(program, "texture_buffer"), 0);
+ glUniform1i(glGetUniformLocation(program, "FVarDataOffsetBuffer"), 30);
+ glUniform1i(glGetUniformLocation(program, "FVarDataBuffer"), 31);
+ glUseProgram(0);
+ }
+
+ return program;
+}
+
+void bindProgram(OpenSubdiv_GLMesh* gl_mesh, int program) {
+ glUseProgram(program);
+ // Matrices
+ glUniformMatrix4fv(glGetUniformLocation(program, "modelViewMatrix"),
+ 1,
+ false,
+ g_transform.model_view_matrix);
+ glUniformMatrix4fv(glGetUniformLocation(program, "projectionMatrix"),
+ 1,
+ false,
+ g_transform.projection_matrix);
+ glUniformMatrix3fv(glGetUniformLocation(program, "normalMatrix"),
+ 1,
+ false,
+ g_transform.normal_matrix);
+ // Lighting.
+ glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub);
+ glBufferSubData(
+ GL_UNIFORM_BUFFER, 0, sizeof(g_lighting_data), &g_lighting_data);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ glBindBufferBase(GL_UNIFORM_BUFFER, 0, g_lighting_ub);
+ // Color.
+ {
+ // TODO(sergey): Stop using glGetMaterial.
+ float color[4];
+ glGetMaterialfv(GL_FRONT, GL_DIFFUSE, color);
+ glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color);
+ glGetMaterialfv(GL_FRONT, GL_SPECULAR, color);
+ glUniform4fv(glGetUniformLocation(program, "specular"), 1, color);
+ glGetMaterialfv(GL_FRONT, GL_SHININESS, color);
+ glUniform1f(glGetUniformLocation(program, "shininess"), color[0]);
+ }
+ // Face-vertex data.
+ opensubdiv_capi::GLMeshFVarData* fvar_data = gl_mesh->internal->fvar_data;
+ if (fvar_data != NULL) {
+ if (fvar_data->texture_buffer) {
+ glActiveTexture(GL_TEXTURE31);
+ glBindTexture(GL_TEXTURE_BUFFER, fvar_data->texture_buffer);
+ glActiveTexture(GL_TEXTURE0);
+ }
+ if (fvar_data->offset_buffer) {
+ glActiveTexture(GL_TEXTURE30);
+ glBindTexture(GL_TEXTURE_BUFFER, fvar_data->offset_buffer);
+ glActiveTexture(GL_TEXTURE0);
+ }
+ glUniform1i(glGetUniformLocation(program, "osd_fvar_count"),
+ fvar_data->fvar_width);
+ if (fvar_data->channel_offsets.size() > 0 && g_active_uv_index >= 0) {
+ glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"),
+ fvar_data->channel_offsets[g_active_uv_index]);
+ } else {
+ glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0);
+ }
+ } else {
+ glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0);
+ glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0);
+ }
+}
+
+} // namespace
+
+bool openSubdiv_initGLMeshDrawingResources(void) {
+ static bool need_init = true;
+ static bool init_success = false;
+ if (!need_init) {
+ return init_success;
+ }
+ // TODO(sergey): Update OSD drawing to OpenGL 3.3 core,
+ // then remove following line.
+ return false;
+ const char* version = "";
+ if (GLEW_VERSION_3_2) {
+ version = "#version 150 compatibility\n";
+ } else if (GLEW_VERSION_3_1) {
+ version = "#version 140\n"
+ "#extension GL_ARB_compatibility: enable\n";
+ } else {
+ version = "#version 130\n";
+ // Minimum supported for OpenSubdiv.
+ }
+ g_flat_fill_solid_program = linkProgram(version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_LIGHTING\n"
+ "#define FLAT_SHADING\n");
+ g_flat_fill_texture2d_program = linkProgram(version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_LIGHTING\n"
+ "#define USE_TEXTURE_2D\n"
+ "#define FLAT_SHADING\n");
+ g_smooth_fill_solid_program = linkProgram(version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_LIGHTING\n"
+ "#define SMOOTH_SHADING\n");
+ g_smooth_fill_texture2d_program = linkProgram(version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_LIGHTING\n"
+ "#define USE_TEXTURE_2D\n"
+ "#define SMOOTH_SHADING\n");
+
+ g_flat_fill_solid_shadeless_program =
+ linkProgram(version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define FLAT_SHADING\n");
+ g_flat_fill_texture2d_shadeless_program =
+ linkProgram(version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_TEXTURE_2D\n"
+ "#define FLAT_SHADING\n");
+ g_smooth_fill_solid_shadeless_program =
+ linkProgram(version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define SMOOTH_SHADING\n");
+ g_smooth_fill_texture2d_shadeless_program =
+ linkProgram(version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_TEXTURE_2D\n"
+ "#define SMOOTH_SHADING\n");
+ g_wireframe_program = linkProgram(version, "#define WIREFRAME\n");
+
+ glGenBuffers(1, &g_lighting_ub);
+ glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub);
+ glBufferData(GL_UNIFORM_BUFFER,
+ sizeof(g_lighting_data),
+ NULL,
+ GL_STATIC_DRAW);
+ need_init = false;
+ init_success = g_flat_fill_solid_program != 0 &&
+ g_flat_fill_texture2d_program != 0 &&
+ g_smooth_fill_solid_program != 0 &&
+ g_smooth_fill_texture2d_program != 0 && g_wireframe_program;
+ return init_success;
+}
+
+void openSubdiv_deinitGLMeshDrawingResources(void) {
+ if (g_lighting_ub != 0) {
+ glDeleteBuffers(1, &g_lighting_ub);
+ }
+#define SAFE_DELETE_PROGRAM(program) \
+ do { \
+ if (program) { \
+ glDeleteProgram(program); \
+ } \
+ } while (false)
+
+ SAFE_DELETE_PROGRAM(g_flat_fill_solid_program);
+ SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_program);
+ SAFE_DELETE_PROGRAM(g_smooth_fill_solid_program);
+ SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_program);
+ SAFE_DELETE_PROGRAM(g_flat_fill_solid_shadeless_program);
+ SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_shadeless_program);
+ SAFE_DELETE_PROGRAM(g_smooth_fill_solid_shadeless_program);
+ SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_shadeless_program);
+ SAFE_DELETE_PROGRAM(g_wireframe_program);
+
+#undef SAFE_DELETE_PROGRAM
+}
+
+namespace opensubdiv_capi {
+
+namespace {
+
+GLuint prepare_patchDraw(OpenSubdiv_GLMesh* gl_mesh, bool fill_quads) {
+ GLint program = 0;
+ if (!g_use_osd_glsl) {
+ glGetIntegerv(GL_CURRENT_PROGRAM, &program);
+ if (program) {
+ GLint model;
+ glGetIntegerv(GL_SHADE_MODEL, &model);
+ GLint location = glGetUniformLocation(program, "osd_flat_shading");
+ if (location != -1) {
+ glUniform1i(location, model == GL_FLAT);
+ }
+ // Face-vertex data.
+ opensubdiv_capi::GLMeshFVarData* fvar_data = gl_mesh->internal->fvar_data;
+ if (fvar_data != NULL) {
+ if (fvar_data->texture_buffer) {
+ glActiveTexture(GL_TEXTURE31);
+ glBindTexture(GL_TEXTURE_BUFFER, fvar_data->texture_buffer);
+ glActiveTexture(GL_TEXTURE0);
+ }
+ if (fvar_data->offset_buffer) {
+ glActiveTexture(GL_TEXTURE30);
+ glBindTexture(GL_TEXTURE_BUFFER, fvar_data->offset_buffer);
+ glActiveTexture(GL_TEXTURE0);
+ }
+ GLint location = glGetUniformLocation(program, "osd_fvar_count");
+ if (location != -1) {
+ glUniform1i(location, fvar_data->fvar_width);
+ }
+ location = glGetUniformLocation(program, "osd_active_uv_offset");
+ if (location != -1) {
+ if (fvar_data->channel_offsets.size() > 0 && g_active_uv_index >= 0) {
+ glUniform1i(location,
+ fvar_data->channel_offsets[g_active_uv_index]);
+ } else {
+ glUniform1i(location, 0);
+ }
+ }
+ } else {
+ glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0);
+ glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0);
+ }
+ }
+ return program;
+ }
+ if (fill_quads) {
+ int model;
+ GLboolean use_texture_2d;
+ glGetIntegerv(GL_SHADE_MODEL, &model);
+ glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d);
+ if (model == GL_FLAT) {
+ if (use_texture_2d) {
+ program = g_flat_fill_texture2d_program;
+ } else {
+ program = g_flat_fill_solid_program;
+ }
+ } else {
+ if (use_texture_2d) {
+ program = g_smooth_fill_texture2d_program;
+ } else {
+ program = g_smooth_fill_solid_program;
+ }
+ }
+
+ } else {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ program = g_wireframe_program;
+ }
+ bindProgram(gl_mesh, program);
+ return program;
+}
+
+void perform_drawElements(GLuint program,
+ int patch_index,
+ int num_elements,
+ int start_element) {
+ if (program) {
+ glUniform1i(glGetUniformLocation(program, "PrimitiveIdBase"), patch_index);
+ }
+ glDrawElements(GL_LINES_ADJACENCY,
+ num_elements,
+ GL_UNSIGNED_INT,
+ reinterpret_cast<void*>(start_element * sizeof(unsigned int)));
+}
+
+void finishPatchDraw(bool fill_quads) {
+ // TODO(sergey): Some of the stuff could be done once after the whole
+ // mesh is displayed.
+ /// Restore state.
+ if (!fill_quads) {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+ glBindVertexArray(0);
+ if (g_use_osd_glsl) {
+ // TODO(sergey): Store previously used program and roll back to it?
+ glUseProgram(0);
+ }
+}
+
+void drawPartitionPatchesRange(GLMeshInterface* mesh,
+ GLuint program,
+ int start_patch,
+ int num_patches) {
+ int traversed_patches = 0, num_remained_patches = num_patches;
+ const OpenSubdiv::Osd::PatchArrayVector &patches =
+ mesh->GetPatchTable()->GetPatchArrays();
+ for (int i = 0; i < patches.size(); ++i) {
+ const OpenSubdiv::Osd::PatchArray &patch = patches[i];
+ OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor();
+ OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType();
+ if (patchType == OpenSubdiv::Far::PatchDescriptor::QUADS) {
+ const int num_block_patches = patch.GetNumPatches();
+ if (start_patch >= traversed_patches &&
+ start_patch < traversed_patches + num_block_patches) {
+ const int num_control_verts = desc.GetNumControlVertices();
+ const int start_draw_patch = start_patch - traversed_patches;
+ const int num_draw_patches = std::min(
+ num_remained_patches, num_block_patches - start_draw_patch);
+ perform_drawElements(
+ program, i + start_draw_patch, num_draw_patches * num_control_verts,
+ patch.GetIndexBase() + start_draw_patch * num_control_verts);
+ num_remained_patches -= num_draw_patches;
+ }
+ if (num_remained_patches == 0) {
+ break;
+ }
+ traversed_patches += num_block_patches;
+ }
+ }
+}
+
+static void drawAllPatches(GLMeshInterface* mesh, GLuint program) {
+ const OpenSubdiv::Osd::PatchArrayVector &patches =
+ mesh->GetPatchTable()->GetPatchArrays();
+ for (int i = 0; i < patches.size(); ++i) {
+ const OpenSubdiv::Osd::PatchArray &patch = patches[i];
+ OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor();
+ OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType();
+
+ if (patchType == OpenSubdiv::Far::PatchDescriptor::QUADS) {
+ perform_drawElements(program, i,
+ patch.GetNumPatches() * desc.GetNumControlVertices(),
+ patch.GetIndexBase());
+ }
+ }
+}
+
+} // namespace
+
+void GLMeshDisplayPrepare(struct OpenSubdiv_GLMesh* /*gl_mesh*/,
+ const bool use_osd_glsl,
+ const int active_uv_index) {
+ g_active_uv_index = active_uv_index;
+ g_use_osd_glsl = (use_osd_glsl != 0);
+ // Update transformation matrices.
+ glGetFloatv(GL_PROJECTION_MATRIX, g_transform.projection_matrix);
+ glGetFloatv(GL_MODELVIEW_MATRIX, g_transform.model_view_matrix);
+ copy_m3_m4((float(*)[3])g_transform.normal_matrix,
+ (float(*)[4])g_transform.model_view_matrix);
+ invert_m3((float(*)[3])g_transform.normal_matrix);
+ transpose_m3((float(*)[3])g_transform.normal_matrix);
+ // Update OpenGL lights positions, colors etc.
+ g_lighting_data.num_enabled = 0;
+ for (int i = 0; i < MAX_LIGHTS; ++i) {
+ GLboolean enabled;
+ glGetBooleanv(GL_LIGHT0 + i, &enabled);
+ if (enabled) {
+ g_lighting_data.num_enabled++;
+ }
+ // TODO(sergey): Stop using glGetLight.
+ glGetLightfv(GL_LIGHT0 + i, GL_POSITION,
+ g_lighting_data.lights[i].position);
+ glGetLightfv(GL_LIGHT0 + i, GL_AMBIENT, g_lighting_data.lights[i].ambient);
+ glGetLightfv(GL_LIGHT0 + i, GL_DIFFUSE, g_lighting_data.lights[i].diffuse);
+ glGetLightfv(GL_LIGHT0 + i, GL_SPECULAR,
+ g_lighting_data.lights[i].specular);
+ glGetLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION,
+ g_lighting_data.lights[i].spot_direction);
+#ifdef SUPPORT_COLOR_MATERIAL
+ glGetLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION,
+ &g_lighting_data.lights[i].constant_attenuation);
+ glGetLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION,
+ &g_lighting_data.lights[i].linear_attenuation);
+ glGetLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION,
+ &g_lighting_data.lights[i].quadratic_attenuation);
+ glGetLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF,
+ &g_lighting_data.lights[i].spot_cutoff);
+ glGetLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT,
+ &g_lighting_data.lights[i].spot_exponent);
+ g_lighting_data.lights[i].spot_cos_cutoff =
+ cos(g_lighting_data.lights[i].spot_cutoff);
+#endif
+ }
+}
+
+void GLMeshDisplayDrawPatches(OpenSubdiv_GLMesh* gl_mesh,
+ const bool fill_quads,
+ const int start_patch,
+ const int num_patches) {
+ GLMeshInterface* mesh = gl_mesh->internal->mesh_interface;
+ // Make sure all global invariants are initialized.
+ if (!openSubdiv_initGLMeshDrawingResources()) {
+ return;
+ }
+ /// Setup GLSL/OpenGL to draw patches in current context.
+ GLuint program = prepare_patchDraw(gl_mesh, fill_quads != 0);
+ if (start_patch != -1) {
+ drawPartitionPatchesRange(mesh, program, start_patch, num_patches);
+ } else {
+ drawAllPatches(mesh, program);
+ }
+ // Finish patch drawing by restoring all changes to the OpenGL context.
+ finishPatchDraw(fill_quads != 0);
+}
+
+} // namespace opensubdiv_capi
diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.h b/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.h
new file mode 100644
index 00000000000..5421b5cf707
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.h
@@ -0,0 +1,39 @@
+// Copyright 2013 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_GL_MESH_DRAW_H_
+#define OPENSUBDIV_GL_MESH_DRAW_H_
+
+#include <stdint.h> // for bool
+
+struct OpenSubdiv_GLMesh;
+
+namespace opensubdiv_capi {
+
+void GLMeshDisplayPrepare(struct OpenSubdiv_GLMesh* gl_mesh,
+ const bool use_osd_glsl,
+ const int active_uv_index);
+
+void GLMeshDisplayDrawPatches(OpenSubdiv_GLMesh* gl_mesh,
+ const bool fill_quads,
+ const int start_patch,
+ const int num_patches);
+
+} // namespace opensubdiv_capi
+
+#endif // OPENSUBDIV_GL_MESH_DRAW_H_
diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.cc b/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.cc
new file mode 100644
index 00000000000..5c9033c8dd1
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.cc
@@ -0,0 +1,175 @@
+// Copyright 2013 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#include "internal/opensubdiv_gl_mesh_fvar.h"
+
+#include <GL/glew.h>
+#include <opensubdiv/far/primvarRefiner.h>
+
+namespace opensubdiv_capi {
+
+////////////////////////////////////////////////////////////////////////////////
+// GLMeshFVarData
+
+GLMeshFVarData::GLMeshFVarData()
+ : texture_buffer(0),
+ offset_buffer(0) {
+}
+
+GLMeshFVarData::~GLMeshFVarData() {
+ release();
+}
+
+void GLMeshFVarData::release() {
+ if (texture_buffer) {
+ glDeleteTextures(1, &texture_buffer);
+ }
+ if (offset_buffer) {
+ glDeleteTextures(1, &offset_buffer);
+ }
+ texture_buffer = 0;
+ offset_buffer = 0;
+ fvar_width = 0;
+ channel_offsets.clear();
+}
+
+void GLMeshFVarData::create(
+ const OpenSubdiv::Far::TopologyRefiner* topology_refiner,
+ const OpenSubdiv::Far::PatchTable* patch_table,
+ int fvar_width,
+ const float* fvar_src_data) {
+ release();
+ this->fvar_width = fvar_width;
+ /// Expand fvar data to per-patch array.
+ const int max_level = topology_refiner->GetMaxLevel();
+ const int num_channels = patch_table->GetNumFVarChannels();
+ std::vector<float> data;
+ int fvar_data_offset = 0;
+ channel_offsets.resize(num_channels);
+ for (int channel = 0; channel < num_channels; ++channel) {
+ OpenSubdiv::Far::ConstIndexArray indices =
+ patch_table->GetFVarValues(channel);
+ channel_offsets[channel] = data.size();
+ data.reserve(data.size() + indices.size() * fvar_width);
+ for (int fvert = 0; fvert < indices.size(); ++fvert) {
+ int index = indices[fvert] * fvar_width;
+ for (int i = 0; i < fvar_width; ++i) {
+ data.push_back(fvar_src_data[fvar_data_offset + index++]);
+ }
+ }
+ if (topology_refiner->IsUniform()) {
+ const int num_values_max =
+ topology_refiner->GetLevel(max_level).GetNumFVarValues(channel);
+ fvar_data_offset += num_values_max * fvar_width;
+ } else {
+ const int num_values_total =
+ topology_refiner->GetNumFVarValuesTotal(channel);
+ fvar_data_offset += num_values_total * fvar_width;
+ }
+ }
+ GLuint buffer;
+ glGenBuffers(1, &buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ glBufferData(GL_ARRAY_BUFFER,
+ data.size() * sizeof(float), &data[0],
+ GL_STATIC_DRAW);
+ glGenTextures(1, &texture_buffer);
+ glBindTexture(GL_TEXTURE_BUFFER, texture_buffer);
+ glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, buffer);
+ glDeleteBuffers(1, &buffer);
+ glGenBuffers(1, &buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ glBufferData(GL_ARRAY_BUFFER,
+ channel_offsets.size() * sizeof(int),
+ &channel_offsets[0],
+ GL_STATIC_DRAW);
+ glGenTextures(1, &offset_buffer);
+ glBindTexture(GL_TEXTURE_BUFFER, offset_buffer);
+ glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, buffer);
+ glBindTexture(GL_TEXTURE_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Helper functions.
+
+struct FVarVertex {
+ float u, v;
+
+ void Clear() {
+ u = v = 0.0f;
+ }
+
+ void AddWithWeight(FVarVertex const& src, float weight) {
+ u += weight * src.u;
+ v += weight * src.v;
+ }
+};
+
+void interpolateFVarData(const OpenSubdiv::Far::TopologyRefiner& refiner,
+ const std::vector<float>& uvs,
+ std::vector<float>* fvar_data) {
+ const int fvar_width = 2;
+ const int max_level = refiner.GetMaxLevel();
+ size_t fvar_data_offset = 0, values_offset = 0;
+ for (int channel = 0; channel < refiner.GetNumFVarChannels(); ++channel) {
+ const int num_values = refiner.GetLevel(0).GetNumFVarValues(channel) * 2;
+ const int num_values_max =
+ refiner.GetLevel(max_level).GetNumFVarValues(channel);
+ const int num_values_total = refiner.GetNumFVarValuesTotal(channel);
+ if (num_values_total <= 0) {
+ continue;
+ }
+ OpenSubdiv::Far::PrimvarRefiner primvar_refiner(refiner);
+ if (refiner.IsUniform()) {
+ // For uniform we only keep the highest level of refinement.
+ fvar_data->resize(fvar_data->size() + num_values_max * fvar_width);
+ std::vector<FVarVertex> buffer(num_values_total - num_values_max);
+ FVarVertex* src = &buffer[0];
+ memcpy(src, &uvs[values_offset], num_values * sizeof(float));
+ // Defer the last level to treat separately with its alternate
+ // destination.
+ for (int level = 1; level < max_level; ++level) {
+ FVarVertex* dst =
+ src + refiner.GetLevel(level - 1).GetNumFVarValues(channel);
+ primvar_refiner.InterpolateFaceVarying(level, src, dst, channel);
+ src = dst;
+ }
+ FVarVertex* dst =
+ reinterpret_cast<FVarVertex*>(&(*fvar_data)[fvar_data_offset]);
+ primvar_refiner.InterpolateFaceVarying(max_level, src, dst, channel);
+ fvar_data_offset += num_values_max * fvar_width;
+ } else {
+ // For adaptive we keep all levels.
+ fvar_data->resize(fvar_data->size() + num_values_total * fvar_width);
+ FVarVertex* src =
+ reinterpret_cast<FVarVertex*>(&(*fvar_data)[fvar_data_offset]);
+ memcpy(src, &uvs[values_offset], num_values * sizeof(float));
+ for (int level = 1; level <= max_level; ++level) {
+ FVarVertex* dst =
+ src + refiner.GetLevel(level - 1).GetNumFVarValues(channel);
+ primvar_refiner.InterpolateFaceVarying(level, src, dst, channel);
+ src = dst;
+ }
+ fvar_data_offset += num_values_total * fvar_width;
+ }
+ values_offset += num_values;
+ }
+}
+
+} // namespace opensubdiv_capi
diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.h b/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.h
new file mode 100644
index 00000000000..039a94eaf86
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.h
@@ -0,0 +1,57 @@
+// Copyright 2013 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_GL_MESH_FVAR_H_
+#define OPENSUBDIV_GL_MESH_FVAR_H_
+
+// NOTE: This is a [sane(er)] port of previous ground work for getting UVs to
+// work. Still needs a lot of work to make it easy, correct and have proper
+// data ownership.
+
+#include <opensubdiv/far/topologyRefiner.h>
+#include <opensubdiv/far/patchTable.h>
+
+#include <vector>
+
+namespace opensubdiv_capi {
+
+// The buffer which holds GPU resources for face-varying elements.
+class GLMeshFVarData {
+ public:
+ GLMeshFVarData();
+ ~GLMeshFVarData();
+
+ void release();
+ void create(const OpenSubdiv::Far::TopologyRefiner* refiner,
+ const OpenSubdiv::Far::PatchTable* patch_table,
+ int fvar_width,
+ const float* fvar_src_data);
+
+ unsigned int texture_buffer;
+ unsigned int offset_buffer;
+ std::vector<int> channel_offsets;
+ int fvar_width;
+};
+
+void interpolateFVarData(const OpenSubdiv::Far::TopologyRefiner& refiner,
+ const std::vector<float>& uvs,
+ std::vector<float>* fvar_data);
+
+} // namespace opensubdiv_capi
+
+#endif // OPENSUBDIV_GL_MESH_FVAR_H_
diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.cc b/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.cc
new file mode 100644
index 00000000000..3abba9cf8f8
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.cc
@@ -0,0 +1,32 @@
+// Copyright 2018 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#include "internal/opensubdiv_gl_mesh_internal.h"
+
+#include "internal/opensubdiv_gl_mesh_fvar.h"
+
+OpenSubdiv_GLMeshInternal::OpenSubdiv_GLMeshInternal()
+ : evaluator_type(OPENSUBDIV_EVALUATOR_CPU),
+ mesh_interface(NULL),
+ fvar_data(NULL) {
+}
+
+OpenSubdiv_GLMeshInternal::~OpenSubdiv_GLMeshInternal() {
+ delete mesh_interface;
+ delete fvar_data;
+}
diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.h b/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.h
new file mode 100644
index 00000000000..7796b450e69
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.h
@@ -0,0 +1,43 @@
+// Copyright 2018 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_GL_MESH_INTERNAL_H_
+#define OPENSUBDIV_GL_MESH_INTERNAL_H_
+
+#ifdef _MSC_VER
+# include <iso646.h>
+#endif
+
+#include <opensubdiv/osd/glMesh.h>
+
+#include "opensubdiv_capi_type.h"
+
+namespace opensubdiv_capi {
+class GLMeshFVarData;
+} // namespace opensubdiv_capi
+
+typedef struct OpenSubdiv_GLMeshInternal {
+ OpenSubdiv_GLMeshInternal();
+ ~OpenSubdiv_GLMeshInternal();
+
+ eOpenSubdivEvaluator evaluator_type;
+ OpenSubdiv::Osd::GLMeshInterface* mesh_interface;
+ opensubdiv_capi::GLMeshFVarData* fvar_data;
+} OpenSubdiv_GLMeshInternal;
+
+#endif // OPENSUBDIV_GL_MESH_INTERNAL_H_
diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/internal/opensubdiv_gpu.cc
index d28b48ddd18..d28b48ddd18 100644
--- a/intern/opensubdiv/opensubdiv_gpu_capi.cc
+++ b/intern/opensubdiv/internal/opensubdiv_gpu.cc
diff --git a/intern/opensubdiv/internal/opensubdiv_internal.h b/intern/opensubdiv/internal/opensubdiv_internal.h
new file mode 100644
index 00000000000..b9d196bbe9e
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_internal.h
@@ -0,0 +1,38 @@
+// Copyright 2015 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_INTERNAL_H_
+#define OPENSUBDIV_INTERNAL_H_
+
+// Perform full topology validation when exporting it to OpenSubdiv.
+#ifdef NDEBUG
+// Never do for release builds.
+# undef OPENSUBDIV_VALIDATE_TOPOLOGY
+#else
+// TODO(sergey): Always disabled for now, the check doesn't handle multiple
+// non-manifolds from the OpenSubdiv side currently.
+// # undef OPENSUBDIV_VALIDATE_TOPOLOGY
+# define OPENSUBDIV_VALIDATE_TOPOLOGY
+#endif
+
+// Currently OpenSubdiv expects topology to be oriented, but sometimes it's
+// handy to disable orientation code to check whether it causes some weird
+// issues by using pre-oriented model.
+#define OPENSUBDIV_ORIENT_TOPOLOGY
+
+#endif // OPENSUBDIV_INTERNAL_H_
diff --git a/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc b/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc
new file mode 100644
index 00000000000..aa6ba953ef9
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc
@@ -0,0 +1,315 @@
+// Copyright 2018 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#include "opensubdiv_topology_refiner_capi.h"
+
+#include <vector>
+
+#include "MEM_guardedalloc.h"
+#include "internal/opensubdiv_converter_factory.h"
+#include "internal/opensubdiv_converter_internal.h"
+#include "internal/opensubdiv_internal.h"
+#include "internal/opensubdiv_topology_refiner_internal.h"
+
+namespace {
+
+const OpenSubdiv::Far::TopologyRefiner* getOSDTopologyRefiner(
+ const OpenSubdiv_TopologyRefiner* topology_refiner) {
+ return topology_refiner->internal->osd_topology_refiner;
+}
+
+const OpenSubdiv::Far::TopologyLevel* getOSDTopologyBaseLevel(
+ const OpenSubdiv_TopologyRefiner* topology_refiner) {
+ return &getOSDTopologyRefiner(topology_refiner)->GetLevel(0);
+}
+
+int getSubdivisionLevel(const OpenSubdiv_TopologyRefiner* topology_refiner) {
+ return topology_refiner->internal->settings.level;
+}
+
+bool getIsAdaptive(const OpenSubdiv_TopologyRefiner* topology_refiner) {
+ return topology_refiner->internal->settings.is_adaptive;
+}
+
+int getNumVertices(const OpenSubdiv_TopologyRefiner* topology_refiner) {
+ return getOSDTopologyBaseLevel(topology_refiner)->GetNumVertices();
+}
+
+int getNumEdges(const OpenSubdiv_TopologyRefiner* topology_refiner) {
+ return getOSDTopologyBaseLevel(topology_refiner)->GetNumEdges();
+}
+
+int getNumFaces(const OpenSubdiv_TopologyRefiner* topology_refiner) {
+ return getOSDTopologyBaseLevel(topology_refiner)->GetNumFaces();
+}
+
+int getNumFaceVertices(const OpenSubdiv_TopologyRefiner* topology_refiner,
+ const int face_index) {
+ const OpenSubdiv::Far::TopologyLevel* base_level =
+ getOSDTopologyBaseLevel(topology_refiner);
+ return base_level->GetFaceVertices(face_index).size();
+}
+
+int getNumFacePtexFaces(const OpenSubdiv_TopologyRefiner* topology_refiner,
+ const int face_index) {
+ const int num_face_vertices =
+ topology_refiner->getNumFaceVertices(topology_refiner, face_index);
+ if (num_face_vertices == 4) {
+ return 1;
+ } else {
+ return num_face_vertices;
+ }
+}
+
+int getNumPtexFaces(const OpenSubdiv_TopologyRefiner* topology_refiner) {
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ int num_ptex_faces = 0;
+ for (int face_index = 0; face_index < num_faces; ++face_index) {
+ num_ptex_faces +=
+ topology_refiner->getNumFacePtexFaces(topology_refiner, face_index);
+ }
+ return num_ptex_faces;
+}
+
+void fillFacePtexIndexOffset(const OpenSubdiv_TopologyRefiner* topology_refiner,
+ int* face_ptex_index_offset) {
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ int num_ptex_faces = 0;
+ for (int face_index = 0; face_index < num_faces; ++face_index) {
+ face_ptex_index_offset[face_index] = num_ptex_faces;
+ num_ptex_faces +=
+ topology_refiner->getNumFacePtexFaces(topology_refiner, face_index);
+ }
+}
+
+void assignFunctionPointers(OpenSubdiv_TopologyRefiner* topology_refiner) {
+ topology_refiner->getSubdivisionLevel = getSubdivisionLevel;
+ topology_refiner->getIsAdaptive = getIsAdaptive;
+
+ topology_refiner->getNumVertices = getNumVertices;
+ topology_refiner->getNumEdges = getNumEdges;
+ topology_refiner->getNumFaces = getNumFaces;
+ topology_refiner->getNumFaceVertices = getNumFaceVertices;
+
+ topology_refiner->getNumFacePtexFaces = getNumFacePtexFaces;
+ topology_refiner->getNumPtexFaces = getNumPtexFaces;
+ topology_refiner->fillFacePtexIndexOffset = fillFacePtexIndexOffset;
+}
+
+OpenSubdiv_TopologyRefiner* allocateTopologyRefiner() {
+ OpenSubdiv_TopologyRefiner* topology_refiner =
+ OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefiner);
+ topology_refiner->internal =
+ OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefinerInternal);
+ assignFunctionPointers(topology_refiner);
+ return topology_refiner;
+}
+
+} // namespace
+
+OpenSubdiv_TopologyRefiner* openSubdiv_createTopologyRefinerFromConverter(
+ OpenSubdiv_Converter* converter,
+ const OpenSubdiv_TopologyRefinerSettings* settings) {
+ OpenSubdiv_TopologyRefiner* topology_refiner = allocateTopologyRefiner();
+ topology_refiner->internal->osd_topology_refiner =
+ opensubdiv_capi::createOSDTopologyRefinerFromConverter(converter);
+ // Store setting which we want to keep track of and which can not be stored
+ // in OpenSubdiv's descriptor yet.
+ topology_refiner->internal->settings = *settings;
+ return topology_refiner;
+}
+
+void openSubdiv_deleteTopologyRefiner(
+ OpenSubdiv_TopologyRefiner* topology_refiner) {
+ OBJECT_GUARDED_DELETE(topology_refiner->internal,
+ OpenSubdiv_TopologyRefinerInternal);
+ OBJECT_GUARDED_DELETE(topology_refiner, OpenSubdiv_TopologyRefiner);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Comparison with converter.
+
+namespace {
+
+///////////////////////////////////////////////////////////
+// Quick preliminary checks.
+
+bool checkSchemeTypeMatches(
+ const OpenSubdiv::Far::TopologyRefiner* topology_refiner,
+ const OpenSubdiv_Converter* converter) {
+ const OpenSubdiv::Sdc::SchemeType converter_scheme_type =
+ opensubdiv_capi::getSchemeTypeFromCAPI(
+ converter->getSchemeType(converter));
+ return (converter_scheme_type == topology_refiner->GetSchemeType());
+}
+
+bool checkOptionsMatches(
+ const OpenSubdiv::Far::TopologyRefiner* topology_refiner,
+ const OpenSubdiv_Converter* converter) {
+ typedef OpenSubdiv::Sdc::Options Options;
+ const Options options = topology_refiner->GetSchemeOptions();
+ const Options::FVarLinearInterpolation fvar_interpolation =
+ options.GetFVarLinearInterpolation();
+ const Options::FVarLinearInterpolation converter_fvar_interpolation =
+ opensubdiv_capi::getFVarLinearInterpolationFromCAPI(
+ converter->getFVarLinearInterpolation(converter));
+ if (fvar_interpolation != converter_fvar_interpolation) {
+ return false;
+ }
+ return true;
+}
+
+bool checkGeometryCoountersMatches(
+ const OpenSubdiv::Far::TopologyRefiner* topology_refiner,
+ const OpenSubdiv_Converter* converter) {
+ using OpenSubdiv::Far::TopologyLevel;
+ const TopologyLevel& base_level = topology_refiner->GetLevel(0);
+ return (
+ (converter->getNumVertices(converter) == base_level.GetNumVertices()) &&
+ (converter->getNumEdges(converter) == base_level.GetNumEdges()) &&
+ (converter->getNumFaces(converter) == base_level.GetNumFaces()));
+}
+
+bool checkPreliminaryMatches(
+ const OpenSubdiv::Far::TopologyRefiner* topology_refiner,
+ const OpenSubdiv_Converter* converter) {
+ return checkSchemeTypeMatches(topology_refiner, converter) &&
+ checkOptionsMatches(topology_refiner, converter) &&
+ checkGeometryCoountersMatches(topology_refiner, converter);
+}
+
+///////////////////////////////////////////////////////////
+// Geometry comparison.
+
+bool checkGeometryEdgesMatch(
+ const OpenSubdiv::Far::TopologyRefiner* topology_refiner,
+ const OpenSubdiv_Converter* converter) {
+ using OpenSubdiv::Far::ConstIndexArray;
+ using OpenSubdiv::Far::TopologyLevel;
+ const TopologyLevel& base_level = topology_refiner->GetLevel(0);
+ const int num_edges = base_level.GetNumEdges();
+ for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
+ const ConstIndexArray& edge_vertices =
+ base_level.GetEdgeVertices(edge_index);
+ int conv_edge_vertices[2];
+ converter->getEdgeVertices(converter, edge_index, conv_edge_vertices);
+ if (conv_edge_vertices[0] != edge_vertices[0] ||
+ conv_edge_vertices[1] != edge_vertices[1]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool checkGeometryFacesMatch(
+ const OpenSubdiv::Far::TopologyRefiner* topology_refiner,
+ const OpenSubdiv_Converter* converter) {
+ using OpenSubdiv::Far::ConstIndexArray;
+ using OpenSubdiv::Far::TopologyLevel;
+ const TopologyLevel& base_level = topology_refiner->GetLevel(0);
+ const int num_faces = base_level.GetNumFaces();
+ // TODO(sergey): Consider using data structure which keeps handful of
+ // elements on stack before doing heep allocation.
+ std::vector<int> conv_face_vertices;
+ for (int face_index = 0; face_index < num_faces; ++face_index) {
+ const ConstIndexArray& face_vertices =
+ base_level.GetFaceVertices(face_index);
+ const int num_face_vertices = face_vertices.size();
+ if (num_face_vertices !=
+ converter->getNumFaceVertices(converter, face_index)) {
+ return false;
+ }
+ conv_face_vertices.resize(num_face_vertices);
+ converter->getFaceVertices(converter, face_index, &conv_face_vertices[0]);
+ // Check face-vertex indices in the direct order (assuming topology
+ // orientation is disabled or did not flip order of the face-vertices).
+ //
+ // TODO(sergey): Can we simply memcmp() with OpenSubdiv's array?
+ bool direct_match = true;
+ for (int face_vertex_index = 0; face_vertex_index < num_face_vertices;
+ ++face_vertex_index) {
+ if (conv_face_vertices[face_vertex_index] !=
+ face_vertices[face_vertex_index]) {
+ direct_match = false;
+ break;
+ }
+ }
+ if (!direct_match) {
+// If face didn't match in direct direction we also test if it matches in
+// reversed direction. This is because conversion might reverse loops to
+// make normals consistent.
+#ifdef OPENSUBDIV_ORIENT_TOPOLOGY
+ for (int face_vertex_index = 0; face_vertex_index < num_face_vertices;
+ ++face_vertex_index) {
+ if (conv_face_vertices[face_vertex_index] !=
+ face_vertices[num_face_vertices - face_vertex_index - 1]) {
+ return false;
+ }
+ }
+#endif
+ return false;
+ }
+ }
+ return true;
+}
+
+bool checkGeometryMatches(
+ const OpenSubdiv::Far::TopologyRefiner* topology_refiner,
+ const OpenSubdiv_Converter* converter) {
+ return checkGeometryEdgesMatch(topology_refiner, converter) &&
+ checkGeometryFacesMatch(topology_refiner, converter);
+}
+
+///////////////////////////////////////////////////////////
+// Compare attributes which affects on topology
+
+bool checkEdgeSharpnessMatch(
+ const OpenSubdiv::Far::TopologyRefiner* topology_refiner,
+ const OpenSubdiv_Converter* converter) {
+ using OpenSubdiv::Far::ConstIndexArray;
+ using OpenSubdiv::Far::TopologyLevel;
+ const TopologyLevel& base_level = topology_refiner->GetLevel(0);
+ const int num_edges = base_level.GetNumEdges();
+ for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
+ const float sharpness = base_level.GetEdgeSharpness(edge_index);
+ const float conv_sharpness =
+ opensubdiv_capi::getCompatibleEdgeSharpness(converter, edge_index);
+ if (sharpness != conv_sharpness) {
+ return false;
+ }
+ }
+ return false;
+}
+
+bool checkTopologyAttributesMatch(
+ const OpenSubdiv::Far::TopologyRefiner* topology_refiner,
+ const OpenSubdiv_Converter* converter) {
+ return checkEdgeSharpnessMatch(topology_refiner, converter);
+}
+
+} // namespace
+
+bool openSubdiv_topologyRefinerCompareWithConverter(
+ const OpenSubdiv_TopologyRefiner* topology_refiner,
+ const OpenSubdiv_Converter* converter) {
+ const OpenSubdiv::Far::TopologyRefiner* refiner =
+ getOSDTopologyRefiner(topology_refiner);
+ return (checkPreliminaryMatches(refiner, converter) &&
+ checkGeometryMatches(refiner, converter) &&
+ checkTopologyAttributesMatch(refiner, converter));
+}
diff --git a/intern/opensubdiv/opensubdiv_topology_refiner.h b/intern/opensubdiv/internal/opensubdiv_topology_refiner.h
index b00f6a54201..b00f6a54201 100644
--- a/intern/opensubdiv/opensubdiv_topology_refiner.h
+++ b/intern/opensubdiv/internal/opensubdiv_topology_refiner.h
diff --git a/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.cc b/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.cc
new file mode 100644
index 00000000000..4636679761f
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.cc
@@ -0,0 +1,26 @@
+// Copyright 2016 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#include "internal/opensubdiv_topology_refiner_internal.h"
+
+OpenSubdiv_TopologyRefinerInternal::OpenSubdiv_TopologyRefinerInternal()
+ : osd_topology_refiner(NULL) {}
+
+OpenSubdiv_TopologyRefinerInternal::~OpenSubdiv_TopologyRefinerInternal() {
+ delete osd_topology_refiner;
+}
diff --git a/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.h b/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.h
new file mode 100644
index 00000000000..f7ca6a7ad5e
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.h
@@ -0,0 +1,47 @@
+// Copyright 2016 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_TOPOLOGY_REFINER_INTERNAL_H_
+#define OPENSUBDIV_TOPOLOGY_REFINER_INTERNAL_H_
+
+#ifdef _MSC_VER
+# include <iso646.h>
+#endif
+
+#include <opensubdiv/far/topologyRefiner.h>
+
+#include "opensubdiv_topology_refiner_capi.h"
+
+struct OpenSubdiv_TopologyRefinerInternal {
+ public:
+ OpenSubdiv_TopologyRefinerInternal();
+ ~OpenSubdiv_TopologyRefinerInternal();
+
+ OpenSubdiv::Far::TopologyRefiner* osd_topology_refiner;
+
+ // Subdivision settingsa this refiner is created for.
+ //
+ // We store it here since OpenSubdiv's refiner will only know about level and
+ // "adaptivity" after performing actual "refine" step.
+ //
+ // Ideally, we would also support refining topology without re-importing it
+ // from external world, but that is for later.
+ OpenSubdiv_TopologyRefinerSettings settings;
+};
+
+#endif // OPENSUBDIV_TOPOLOGY_REFINER_H_
diff --git a/intern/opensubdiv/internal/opensubdiv_util.cc b/intern/opensubdiv/internal/opensubdiv_util.cc
new file mode 100644
index 00000000000..87bfce2116c
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_util.cc
@@ -0,0 +1,61 @@
+// Copyright 2013 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+// Contributor(s): Brecht van Lommel
+
+#include "internal/opensubdiv_util.h"
+
+#include <GL/glew.h>
+#include <cstring>
+
+#ifdef _MSC_VER
+# include <iso646.h>
+#endif
+
+namespace opensubdiv_capi {
+
+void stringSplit(std::vector<std::string>* tokens,
+ const std::string& str,
+ const std::string& separators,
+ bool skip_empty) {
+ size_t token_start = 0, token_length = 0;
+ for (size_t i = 0; i < str.length(); ++i) {
+ const char ch = str[i];
+ if (separators.find(ch) == std::string::npos) {
+ // Append non-separator char to a token.
+ ++token_length;
+ } else {
+ // Append current token to the list (if any).
+ if (token_length > 0 || !skip_empty) {
+ std::string token = str.substr(token_start, token_length);
+ tokens->push_back(token);
+ }
+ // Re-set token pointers,
+ token_start = i + 1;
+ token_length = 0;
+ }
+ }
+ // Append token which might be at the end of the string.
+ if ((token_length != 0) ||
+ (!skip_empty && token_start > 0 &&
+ separators.find(str[token_start-1]) != std::string::npos)) {
+ std::string token = str.substr(token_start, token_length);
+ tokens->push_back(token);
+ }
+}
+
+} // namespace opensubdiv_capi
diff --git a/intern/opensubdiv/internal/opensubdiv_util.h b/intern/opensubdiv/internal/opensubdiv_util.h
new file mode 100644
index 00000000000..6ed19b37e33
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_util.h
@@ -0,0 +1,39 @@
+// Copyright 2013 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+// Contributor(s): Brecht van Lommel
+
+#ifndef OPENSUBDIV_UTIL_H_
+#define OPENSUBDIV_UTIL_H_
+
+#include <vector>
+#include <string>
+
+namespace opensubdiv_capi {
+
+#define STRINGIFY_ARG(x) "" #x
+#define STRINGIFY_APPEND(a, b) "" a #b
+#define STRINGIFY(x) STRINGIFY_APPEND("", x)
+
+void stringSplit(std::vector<std::string>* tokens,
+ const std::string& str,
+ const std::string& separators,
+ bool skip_empty);
+
+} // namespace opensubdiv_capi
+
+#endif // OPENSUBDIV_UTIL_H_
diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc
deleted file mode 100644
index 638039f4f3e..00000000000
--- a/intern/opensubdiv/opensubdiv_capi.cc
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2013 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Sergey Sharybin.
- * Brecht van Lommel
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "opensubdiv_capi.h"
-
-#ifdef _MSC_VER
-# include "iso646.h"
-#endif
-
-#include <stdlib.h>
-#include <GL/glew.h>
-
-#include <opensubdiv/version.h>
-#include <opensubdiv/osd/glMesh.h>
-
-/* CPU Backend */
-#include <opensubdiv/osd/cpuGLVertexBuffer.h>
-#include <opensubdiv/osd/cpuEvaluator.h>
-
-#ifdef OPENSUBDIV_HAS_OPENMP
-# include <opensubdiv/osd/ompEvaluator.h>
-#endif /* OPENSUBDIV_HAS_OPENMP */
-
-#ifdef OPENSUBDIV_HAS_OPENCL
-# include <opensubdiv/osd/clGLVertexBuffer.h>
-# include <opensubdiv/osd/clEvaluator.h>
-# include "opensubdiv_device_context_opencl.h"
-#endif /* OPENSUBDIV_HAS_OPENCL */
-
-#ifdef OPENSUBDIV_HAS_CUDA
-# include <opensubdiv/osd/cudaGLVertexBuffer.h>
-# include <opensubdiv/osd/cudaEvaluator.h>
-# include "opensubdiv_device_context_cuda.h"
-#endif /* OPENSUBDIV_HAS_CUDA */
-
-#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
-# include <opensubdiv/osd/glXFBEvaluator.h>
-# include <opensubdiv/osd/glVertexBuffer.h>
-#endif /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */
-
-#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
-# include <opensubdiv/osd/glComputeEvaluator.h>
-# include <opensubdiv/osd/glVertexBuffer.h>
-#endif /* OPENSUBDIV_HAS_GLSL_COMPUTE */
-
-#include <opensubdiv/osd/glPatchTable.h>
-#include <opensubdiv/far/stencilTable.h>
-#include <opensubdiv/far/primvarRefiner.h>
-
-#include "opensubdiv_gl_mesh.h"
-#include "opensubdiv_intern.h"
-#include "opensubdiv_topology_refiner.h"
-
-#include "MEM_guardedalloc.h"
-
-#include <string>
-#include <vector>
-
-using std::string;
-using std::vector;
-
-#define STRINGIFY_ARG(x) "" #x
-#define STRINGIFY_APPEND(a, b) "" a #b
-#define STRINGIFY(x) STRINGIFY_APPEND("", x)
-
-/* **************** Types declaration **************** */
-
-using OpenSubdiv::Osd::GLMeshInterface;
-using OpenSubdiv::Osd::Mesh;
-using OpenSubdiv::Osd::MeshBitset;
-using OpenSubdiv::Far::StencilTable;
-using OpenSubdiv::Osd::GLPatchTable;
-
-using OpenSubdiv::Osd::Mesh;
-
-/* CPU backend */
-using OpenSubdiv::Osd::CpuGLVertexBuffer;
-using OpenSubdiv::Osd::CpuEvaluator;
-typedef Mesh<CpuGLVertexBuffer,
- StencilTable,
- CpuEvaluator,
- GLPatchTable> OsdCpuMesh;
-
-#ifdef OPENSUBDIV_HAS_OPENMP
-using OpenSubdiv::Osd::OmpEvaluator;
-typedef Mesh<CpuGLVertexBuffer,
- StencilTable,
- OmpEvaluator,
- GLPatchTable> OsdOmpMesh;
-#endif /* OPENSUBDIV_HAS_OPENMP */
-
-#ifdef OPENSUBDIV_HAS_OPENCL
-using OpenSubdiv::Osd::CLEvaluator;
-using OpenSubdiv::Osd::CLGLVertexBuffer;
-using OpenSubdiv::Osd::CLStencilTable;
-/* TODO(sergey): Use CLDeviceCOntext similar to OSD examples? */
-typedef Mesh<CLGLVertexBuffer,
- CLStencilTable,
- CLEvaluator,
- GLPatchTable,
- CLDeviceContext> OsdCLMesh;
-static CLDeviceContext g_clDeviceContext;
-#endif /* OPENSUBDIV_HAS_OPENCL */
-
-#ifdef OPENSUBDIV_HAS_CUDA
-using OpenSubdiv::Osd::CudaEvaluator;
-using OpenSubdiv::Osd::CudaGLVertexBuffer;
-using OpenSubdiv::Osd::CudaStencilTable;
-typedef Mesh<CudaGLVertexBuffer,
- CudaStencilTable,
- CudaEvaluator,
- GLPatchTable> OsdCudaMesh;
-static CudaDeviceContext g_cudaDeviceContext;
-#endif /* OPENSUBDIV_HAS_CUDA */
-
-#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
-using OpenSubdiv::Osd::GLXFBEvaluator;
-using OpenSubdiv::Osd::GLStencilTableTBO;
-using OpenSubdiv::Osd::GLVertexBuffer;
-typedef Mesh<GLVertexBuffer,
- GLStencilTableTBO,
- GLXFBEvaluator,
- GLPatchTable> OsdGLSLTransformFeedbackMesh;
-#endif /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */
-
-#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
-using OpenSubdiv::Osd::GLComputeEvaluator;
-using OpenSubdiv::Osd::GLStencilTableSSBO;
-using OpenSubdiv::Osd::GLVertexBuffer;
-typedef Mesh<GLVertexBuffer,
- GLStencilTableSSBO,
- GLComputeEvaluator,
- GLPatchTable> OsdGLSLComputeMesh;
-#endif
-
-namespace {
-
-#if !defined(OPENSUBDIV_VERSION_NUMBER) && !defined(OPENSUBDIV_VERSION_MINOR)
-void stringSplit(vector<string>* tokens,
- const string& str,
- const string& separators,
- bool skip_empty) {
- size_t token_start = 0, token_length = 0;
- for (size_t i = 0; i < str.length(); ++i) {
- const char ch = str[i];
- if (separators.find(ch) == string::npos) {
- /* Append non-separator char to a token. */
- ++token_length;
- } else {
- /* Append current token to the list (if any). */
- if (token_length > 0 || !skip_empty) {
- string token = str.substr(token_start, token_length);
- tokens->push_back(token);
- }
- /* Re-set token pointers, */
- token_start = i + 1;
- token_length = 0;
- }
- }
- /* Append token which might be at the end of the string. */
- if ((token_length != 0) ||
- (!skip_empty && token_start > 0 &&
- separators.find(str[token_start-1]) != string::npos)) {
- string token = str.substr(token_start, token_length);
- tokens->push_back(token);
- }
-}
-#endif
-
-struct FVarVertex {
- float u, v;
- void Clear() {
- u = v = 0.0f;
- }
- void AddWithWeight(FVarVertex const & src, float weight) {
- u += weight * src.u;
- v += weight * src.v;
- }
-};
-
-static void interpolate_fvar_data(OpenSubdiv::Far::TopologyRefiner& refiner,
- const std::vector<float> uvs,
- std::vector<float> &fvar_data) {
- /* TODO(sergey): Make it somehow more generic way. */
- const int fvar_width = 2;
- const int max_level = refiner.GetMaxLevel();
- size_t fvar_data_offset = 0, values_offset = 0;
- for (int channel = 0; channel < refiner.GetNumFVarChannels(); ++channel) {
- const int num_values = refiner.GetLevel(0).GetNumFVarValues(channel) * 2,
- num_values_max = refiner.GetLevel(max_level).GetNumFVarValues(channel),
- num_values_total = refiner.GetNumFVarValuesTotal(channel);
- if (num_values_total <= 0) {
- continue;
- }
- OpenSubdiv::Far::PrimvarRefiner primvar_refiner(refiner);
- if (refiner.IsUniform()) {
- /* For uniform we only keep the highest level of refinement. */
- fvar_data.resize(fvar_data.size() + num_values_max * fvar_width);
- std::vector<FVarVertex> buffer(num_values_total - num_values_max);
- FVarVertex *src = &buffer[0];
- memcpy(src, &uvs[values_offset], num_values * sizeof(float));
- /* Defer the last level to treat separately with its alternate
- * destination.
- */
- for (int level = 1; level < max_level; ++level) {
- FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);
- primvar_refiner.InterpolateFaceVarying(level, src, dst, channel);
- src = dst;
- }
- FVarVertex *dst = reinterpret_cast<FVarVertex *>(&fvar_data[fvar_data_offset]);
- primvar_refiner.InterpolateFaceVarying(max_level, src, dst, channel);
- fvar_data_offset += num_values_max * fvar_width;
- } else {
- /* For adaptive we keep all levels. */
- fvar_data.resize(fvar_data.size() + num_values_total * fvar_width);
- FVarVertex *src = reinterpret_cast<FVarVertex *>(&fvar_data[fvar_data_offset]);
- memcpy(src, &uvs[values_offset], num_values * sizeof(float));
- for (int level = 1; level <= max_level; ++level) {
- FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);
- primvar_refiner.InterpolateFaceVarying(level, src, dst, channel);
- src = dst;
- }
- fvar_data_offset += num_values_total * fvar_width;
- }
- values_offset += num_values;
- }
-}
-
-} // namespace
-
-struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
- OpenSubdiv_TopologyRefinerDescr *topology_refiner,
- int evaluator_type,
- int level)
-{
- using OpenSubdiv::Far::TopologyRefiner;
-
- MeshBitset bits;
- /* TODO(sergey): Adaptive subdivisions are not currently
- * possible because of the lack of tessellation shader.
- */
- bits.set(OpenSubdiv::Osd::MeshAdaptive, 0);
- bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, 0);
- bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, 1);
- bits.set(OpenSubdiv::Osd::MeshFVarData, 1);
- bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, 1);
-
- const int num_vertex_elements = 3;
- const int num_varying_elements = 3;
-
- GLMeshInterface *mesh = NULL;
- TopologyRefiner *refiner = topology_refiner->osd_refiner;
-
- switch(evaluator_type) {
-#define CHECK_EVALUATOR_TYPE(type, class) \
- case OPENSUBDIV_EVALUATOR_ ## type: \
- mesh = new class(refiner, \
- num_vertex_elements, \
- num_varying_elements, \
- level, \
- bits); \
- break;
-
- CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh)
-
-#ifdef OPENSUBDIV_HAS_OPENMP
- CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh)
-#endif
-
-#ifdef OPENSUBDIV_HAS_OPENCL
- CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh)
-#endif
-
-#ifdef OPENSUBDIV_HAS_CUDA
- CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh)
-#endif
-
-#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
- CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK,
- OsdGLSLTransformFeedbackMesh)
-#endif
-
-#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
- CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh)
-#endif
-
-#undef CHECK_EVALUATOR_TYPE
- }
-
- if (mesh == NULL) {
- return NULL;
- }
-
- OpenSubdiv_GLMesh *gl_mesh =
- (OpenSubdiv_GLMesh *) OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh);
- gl_mesh->evaluator_type = evaluator_type;
- gl_mesh->descriptor = (OpenSubdiv_GLMeshDescr *) mesh;
- gl_mesh->topology_refiner = topology_refiner;
-
- if (refiner->GetNumFVarChannels() > 0) {
- std::vector<float> fvar_data;
- interpolate_fvar_data(*refiner, topology_refiner->uvs, fvar_data);
- openSubdiv_osdGLAllocFVar(topology_refiner, gl_mesh, &fvar_data[0]);
- }
- else {
- gl_mesh->fvar_data = NULL;
- }
-
- return gl_mesh;
-}
-
-void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh)
-{
- openSubdiv_osdGLDestroyFVar(gl_mesh);
- switch (gl_mesh->evaluator_type) {
-#define CHECK_EVALUATOR_TYPE(type, class) \
- case OPENSUBDIV_EVALUATOR_ ## type: \
- delete (class *) gl_mesh->descriptor; \
- break;
-
- CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh)
-
-#ifdef OPENSUBDIV_HAS_OPENMP
- CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh)
-#endif
-
-#ifdef OPENSUBDIV_HAS_OPENCL
- CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh)
-#endif
-
-#ifdef OPENSUBDIV_HAS_CUDA
- CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh)
-#endif
-
-#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
- CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK,
- OsdGLSLTransformFeedbackMesh)
-#endif
-
-#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
- CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh)
-#endif
-
-#undef CHECK_EVALUATOR_TYPE
- }
-
- /* NOTE: OSD refiner was owned by gl_mesh, no need to free it here. */
- OBJECT_GUARDED_DELETE(gl_mesh->topology_refiner, OpenSubdiv_TopologyRefinerDescr);
- OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh);
-}
-
-unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer(struct OpenSubdiv_GLMesh *gl_mesh)
-{
- return ((GLMeshInterface *)gl_mesh->descriptor)->GetPatchTable()->GetPatchIndexBuffer();
-}
-
-unsigned int openSubdiv_getOsdGLMeshVertexBuffer(struct OpenSubdiv_GLMesh *gl_mesh)
-{
- return ((GLMeshInterface *)gl_mesh->descriptor)->BindVertexBuffer();
-}
-
-void openSubdiv_osdGLMeshUpdateVertexBuffer(struct OpenSubdiv_GLMesh *gl_mesh,
- const float *vertex_data,
- int start_vertex,
- int num_verts)
-{
- ((GLMeshInterface *)gl_mesh->descriptor)->UpdateVertexBuffer(vertex_data,
- start_vertex,
- num_verts);
-}
-
-void openSubdiv_osdGLMeshRefine(struct OpenSubdiv_GLMesh *gl_mesh)
-{
- ((GLMeshInterface *)gl_mesh->descriptor)->Refine();
-}
-
-void openSubdiv_osdGLMeshSynchronize(struct OpenSubdiv_GLMesh *gl_mesh)
-{
- ((GLMeshInterface *)gl_mesh->descriptor)->Synchronize();
-}
-
-void openSubdiv_osdGLMeshBindVertexBuffer(OpenSubdiv_GLMesh *gl_mesh)
-{
- ((GLMeshInterface *)gl_mesh->descriptor)->BindVertexBuffer();
-}
-
-const struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_getGLMeshTopologyRefiner(
- OpenSubdiv_GLMesh *gl_mesh)
-{
- return gl_mesh->topology_refiner;
-}
-
-int openSubdiv_getVersionHex(void)
-{
-#if defined(OPENSUBDIV_VERSION_NUMBER)
- return OPENSUBDIV_VERSION_NUMBER;
-#elif defined(OPENSUBDIV_VERSION_MAJOR)
- return OPENSUBDIV_VERSION_MAJOR * 10000 +
- OPENSUBDIV_VERSION_MINOR * 100 +
- OPENSUBDIV_VERSION_PATCH;
-#elif defined(OPENSUBDIV_VERSION)
- const char* version = STRINGIFY(OPENSUBDIV_VERSION);
- if (version[0] == 'v') {
- version += 1;
- }
- int major = 0, minor = 0, patch = 0;
- vector<string> tokens;
- stringSplit(&tokens, version, "_", true);
- if (tokens.size() == 3) {
- major = atoi(tokens[0].c_str());
- minor = atoi(tokens[1].c_str());
- patch = atoi(tokens[2].c_str());
- }
- return major * 10000 + minor * 100 + patch;
-#else
- return 0;
-#endif
-}
diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h
index c29d08a77e1..a26ea36b863 100644
--- a/intern/opensubdiv/opensubdiv_capi.h
+++ b/intern/opensubdiv/opensubdiv_capi.h
@@ -1,163 +1,43 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2013 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Sergey Sharybin
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __OPENSUBDIV_CAPI_H__
-#define __OPENSUBDIV_CAPI_H__
+// Copyright 2013 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_CAPI_H_
+#define OPENSUBDIV_CAPI_H_
+
+#include "opensubdiv_capi_type.h"
#ifdef __cplusplus
extern "C" {
#endif
-// Types declaration.
-struct OpenSubdiv_GLMesh;
-struct OpenSubdiv_GLMeshDescr;
-struct OpenSubdiv_GLMeshFVarData;
-struct OpenSubdiv_TopologyRefinerDescr;
-
-typedef struct OpenSubdiv_GLMesh OpenSubdiv_GLMesh;
-
-// Keep this a bitmask os it's possible to pass available
-// evaluators to Blender.
-enum {
- OPENSUBDIV_EVALUATOR_CPU = (1 << 0),
- OPENSUBDIV_EVALUATOR_OPENMP = (1 << 1),
- OPENSUBDIV_EVALUATOR_OPENCL = (1 << 2),
- OPENSUBDIV_EVALUATOR_CUDA = (1 << 3),
- OPENSUBDIV_EVALUATOR_GLSL_TRANSFORM_FEEDBACK = (1 << 4),
- OPENSUBDIV_EVALUATOR_GLSL_COMPUTE = (1 << 5),
-};
-
-enum {
- OPENSUBDIV_SCHEME_CATMARK,
- OPENSUBDIV_SCHEME_BILINEAR,
- OPENSUBDIV_SCHEME_LOOP,
-};
-
-/* TODO(sergey): Re-name and avoid bad level data access. */
-OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
- struct OpenSubdiv_TopologyRefinerDescr *topology_refiner,
- int evaluator_type,
- int level);
-
-void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh);
-unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer(
- OpenSubdiv_GLMesh *gl_mesh);
-unsigned int openSubdiv_getOsdGLMeshVertexBuffer(OpenSubdiv_GLMesh *gl_mesh);
-void openSubdiv_osdGLMeshUpdateVertexBuffer(OpenSubdiv_GLMesh *gl_mesh,
- const float *vertex_data,
- int start_vertex,
- int num_verts);
-void openSubdiv_osdGLMeshRefine(OpenSubdiv_GLMesh *gl_mesh);
-void openSubdiv_osdGLMeshSynchronize(OpenSubdiv_GLMesh *gl_mesh);
-void openSubdiv_osdGLMeshBindVertexBuffer(OpenSubdiv_GLMesh *gl_mesh);
-
-const struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_getGLMeshTopologyRefiner(
- OpenSubdiv_GLMesh *gl_mesh);
-
-/* ============================= Evaluator API ============================== */
-
-struct OpenSubdiv_EvaluatorDescr;
-typedef struct OpenSubdiv_EvaluatorDescr OpenSubdiv_EvaluatorDescr;
-
-/* TODO(sergey): Avoid bad-level data access, */
-OpenSubdiv_EvaluatorDescr *openSubdiv_createEvaluatorDescr(
- struct OpenSubdiv_TopologyRefinerDescr *topology_refiner,
- int subsurf_level);
-
-void openSubdiv_deleteEvaluatorDescr(
- OpenSubdiv_EvaluatorDescr *evaluator_descr);
-
-void openSubdiv_setEvaluatorCoarsePositions(
- OpenSubdiv_EvaluatorDescr *evaluator_descr,
- const float *positions,
- int start_vertex_index,
- int num_vertices);
-void openSubdiv_setEvaluatorVaryingData(
- OpenSubdiv_EvaluatorDescr *evaluator_descr,
- const float *varying_data,
- int start_vertex_index,
- int num_vertices);
-
-void openSubdiv_setEvaluatorCoarsePositionsFromBuffer(
- OpenSubdiv_EvaluatorDescr *evaluator_descr,
- const void *buffer,
- int start_offset,
- int stride,
- int start_vertex_index,
- int num_vertices);
-
-void openSubdiv_refineEvaluator(OpenSubdiv_EvaluatorDescr *evaluator_descr);
-
-void openSubdiv_evaluateLimit(OpenSubdiv_EvaluatorDescr *evaluator_descr,
- int osd_face_index,
- float face_u, float face_v,
- float P[3],
- float dPdu[3],
- float dPdv[3]);
-
-void openSubdiv_evaluateVarying(OpenSubdiv_EvaluatorDescr *evaluator_descr,
- int osd_face_index,
- float face_u, float face_v,
- float varying[3]);
-
-/* ============================== Mesh drawing =============================== */
-
-/* Initialize/Deinitialize global OpenGL drawing buffers/GLSL programs. */
-bool openSubdiv_osdGLDisplayInit(void);
-void openSubdiv_osdGLDisplayDeinit(void);
-
-/* Initialize all the invariants which stays the same for every single path,
- * for example lighting model stays untouched for the whole mesh.
- *
- * TODO(sergey): Some of the stuff could be initialized once for all meshes.
- */
-void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl, int active_uv_index);
-
-/* Draw specified patches. */
-void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
- int fill_quads,
- int start_patch,
- int num_patches);
-
-void openSubdiv_osdGLAllocFVar(
- struct OpenSubdiv_TopologyRefinerDescr *topology_refiner,
- OpenSubdiv_GLMesh *gl_mesh,
- const float *fvar_data);
-
-void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh);
-
-/* =========================== Utility functions ============================ */
-
-int openSubdiv_getAvailableEvaluators(void);
+// Global initialization/deinitialization.
+//
+// Supposed to be called from main thread.
void openSubdiv_init(void);
void openSubdiv_cleanup(void);
+// Bitmask of eOpenSubdivEvaluator.
+int openSubdiv_getAvailableEvaluators(void);
+
int openSubdiv_getVersionHex(void);
#ifdef __cplusplus
}
#endif
-#endif // __OPENSUBDIV_CAPI_H__
+#endif // OPENSUBDIV_CAPI_H_
diff --git a/intern/opensubdiv/opensubdiv_capi_type.h b/intern/opensubdiv/opensubdiv_capi_type.h
new file mode 100644
index 00000000000..04fe2afff53
--- /dev/null
+++ b/intern/opensubdiv/opensubdiv_capi_type.h
@@ -0,0 +1,41 @@
+// Copyright 2013 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_CAPI_TYPES_H_
+#define OPENSUBDIV_CAPI_TYPES_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Keep this a bitmask os it's possible to pass available
+// evaluators to Blender.
+typedef enum eOpenSubdivEvaluator {
+ OPENSUBDIV_EVALUATOR_CPU = (1 << 0),
+ OPENSUBDIV_EVALUATOR_OPENMP = (1 << 1),
+ OPENSUBDIV_EVALUATOR_OPENCL = (1 << 2),
+ OPENSUBDIV_EVALUATOR_CUDA = (1 << 3),
+ OPENSUBDIV_EVALUATOR_GLSL_TRANSFORM_FEEDBACK = (1 << 4),
+ OPENSUBDIV_EVALUATOR_GLSL_COMPUTE = (1 << 5),
+} eOpenSubdivEvaluator;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // OPENSUBDIV_CAPI_TYPES_H_
diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc
deleted file mode 100644
index fec15b118ae..00000000000
--- a/intern/opensubdiv/opensubdiv_converter.cc
+++ /dev/null
@@ -1,764 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2015 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Sergey Sharybin.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include <cstdio>
-#include <vector>
-
-#ifdef _MSC_VER
-# include "iso646.h"
-#endif
-
-#include <opensubdiv/far/topologyRefinerFactory.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "opensubdiv_converter_capi.h"
-#include "opensubdiv_intern.h"
-#include "opensubdiv_topology_refiner.h"
-
-
-#include <stack>
-
-#ifdef OPENSUBDIV_ORIENT_TOPOLOGY
-namespace {
-
-inline void reverse_face_verts(int *face_verts, int num_verts)
-{
- int last_vert = face_verts[num_verts - 1];
- for (int i = num_verts - 1; i > 0; --i) {
- face_verts[i] = face_verts[i - 1];
- }
- face_verts[0] = last_vert;
-}
-
-struct TopologyRefinerData {
- const OpenSubdiv_Converter& conv;
- std::vector<float> *uvs;
-};
-
-} /* namespace */
-#endif /* OPENSUBDIV_ORIENT_TOPOLOGY */
-
-namespace OpenSubdiv {
-namespace OPENSUBDIV_VERSION {
-namespace Far {
-
-namespace {
-
-template <typename T>
-inline int findInArray(T array, int value)
-{
- return (int)(std::find(array.begin(), array.end(), value) - array.begin());
-}
-
-#ifdef OPENSUBDIV_ORIENT_TOPOLOGY
-inline int get_loop_winding(int vert0_of_face, int vert1_of_face)
-{
- int delta_face = vert1_of_face - vert0_of_face;
- if (abs(delta_face) != 1) {
- if (delta_face > 0) {
- delta_face = -1;
- }
- else {
- delta_face = 1;
- }
- }
- return delta_face;
-}
-
-inline void reverse_face_loops(IndexArray face_verts, IndexArray face_edges)
-{
- for (int i = 0; i < face_verts.size() / 2; ++i) {
- int j = face_verts.size() - i - 1;
- if (i != j) {
- std::swap(face_verts[i], face_verts[j]);
- std::swap(face_edges[i], face_edges[j]);
- }
- }
- reverse_face_verts(&face_verts[0], face_verts.size());
-}
-
-inline void check_oriented_vert_connectivity(const int num_vert_edges,
- const int num_vert_faces,
- const int *vert_edges,
- const int *vert_faces,
- const int *dst_vert_edges,
- const int *dst_vert_faces)
-{
-# ifndef NDEBUG
- for (int i = 0; i < num_vert_faces; ++i) {
- bool found = false;
- for (int j = 0; j < num_vert_faces; ++j) {
- if (vert_faces[i] == dst_vert_faces[j]) {
- found = true;
- break;
- }
- }
- if (!found) {
- assert(!"vert-faces connectivity ruined");
- }
- }
- for (int i = 0; i < num_vert_edges; ++i) {
- bool found = false;
- for (int j = 0; j < num_vert_edges; ++j) {
- if (vert_edges[i] == dst_vert_edges[j]) {
- found = true;
- break;
- }
- }
- if (!found) {
- assert(!"vert-edges connectivity ruined");
- }
- }
-# else
- (void)num_vert_edges;
- (void)num_vert_faces;
- (void)vert_edges;
- (void)vert_faces;
- (void)dst_vert_edges;
- (void)dst_vert_faces;
-# endif
-}
-#endif
-
-} /* namespace */
-
-template <>
-inline bool TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology(
- TopologyRefiner& refiner,
- const TopologyRefinerData& cb_data)
-{
- const OpenSubdiv_Converter& conv = cb_data.conv;
- /* Faces and face-verts */
- const int num_faces = conv.get_num_faces(&conv);
- setNumBaseFaces(refiner, num_faces);
- for (int face = 0; face < num_faces; ++face) {
- const int num_verts = conv.get_num_face_verts(&conv, face);
- setNumBaseFaceVertices(refiner, face, num_verts);
- }
- /* Edges and edge-faces. */
- const int num_edges = conv.get_num_edges(&conv);
- setNumBaseEdges(refiner, num_edges);
- for (int edge = 0; edge < num_edges; ++edge) {
- const int num_edge_faces = conv.get_num_edge_faces(&conv, edge);
- setNumBaseEdgeFaces(refiner, edge, num_edge_faces);
- }
- /* Vertices and vert-faces and vert-edges/ */
- const int num_verts = conv.get_num_verts(&conv);
- setNumBaseVertices(refiner, num_verts);
- for (int vert = 0; vert < num_verts; ++vert) {
- const int num_vert_edges = conv.get_num_vert_edges(&conv, vert),
- num_vert_faces = conv.get_num_vert_faces(&conv, vert);
- setNumBaseVertexEdges(refiner, vert, num_vert_edges);
- setNumBaseVertexFaces(refiner, vert, num_vert_faces);
- }
- return true;
-}
-
-template <>
-inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology(
- TopologyRefiner& refiner,
- const TopologyRefinerData &cb_data)
-{
- const OpenSubdiv_Converter& conv = cb_data.conv;
- using Far::IndexArray;
- /* Face relations. */
- const int num_faces = conv.get_num_faces(&conv);
- for (int face = 0; face < num_faces; ++face) {
- IndexArray dst_face_verts = getBaseFaceVertices(refiner, face);
- conv.get_face_verts(&conv, face, &dst_face_verts[0]);
- IndexArray dst_face_edges = getBaseFaceEdges(refiner, face);
- conv.get_face_edges(&conv, face, &dst_face_edges[0]);
- }
- /* Edge relations. */
- const int num_edges = conv.get_num_edges(&conv);
- for (int edge = 0; edge < num_edges; ++edge) {
- /* Edge-vertices */
- IndexArray dst_edge_verts = getBaseEdgeVertices(refiner, edge);
- conv.get_edge_verts(&conv, edge, &dst_edge_verts[0]);
- /* Edge-faces */
- IndexArray dst_edge_faces = getBaseEdgeFaces(refiner, edge);
- conv.get_edge_faces(&conv, edge, &dst_edge_faces[0]);
- }
-#ifdef OPENSUBDIV_ORIENT_TOPOLOGY
- /* Make face normals consistent. */
- bool *face_used = new bool[num_faces];
- memset(face_used, 0, sizeof(bool) * num_faces);
- std::stack<int> traverse_stack;
- int face_start = 0, num_traversed_faces = 0;
- /* Traverse all islands. */
- while (num_traversed_faces != num_faces) {
- /* Find first face of any untraversed islands. */
- while (face_used[face_start]) {
- ++face_start;
- }
- /* Add first face to the stack. */
- traverse_stack.push(face_start);
- face_used[face_start] = true;
- /* Go over whole connected component. */
- while (!traverse_stack.empty()) {
- int face = traverse_stack.top();
- traverse_stack.pop();
- IndexArray face_edges = getBaseFaceEdges(refiner, face);
- ConstIndexArray face_verts = getBaseFaceVertices(refiner, face);
- for (int edge_index = 0; edge_index < face_edges.size(); ++edge_index) {
- const int edge = face_edges[edge_index];
- ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge);
- if (edge_faces.size() != 2) {
- /* Can't make consistent normals for non-manifolds. */
- continue;
- }
- ConstIndexArray edge_verts = getBaseEdgeVertices(refiner, edge);
- /* Get winding of the reference face. */
- int vert0_of_face = findInArray(face_verts, edge_verts[0]),
- vert1_of_face = findInArray(face_verts, edge_verts[1]);
- int delta_face = get_loop_winding(vert0_of_face, vert1_of_face);
- for (int edge_face = 0; edge_face < edge_faces.size(); ++edge_face) {
- int other_face = edge_faces[edge_face];
- /* Never re-traverse faces, only move forward. */
- if (face_used[other_face]) {
- continue;
- }
- IndexArray other_face_verts = getBaseFaceVertices(refiner,
- other_face);
- int vert0_of_other_face = findInArray(other_face_verts,
- edge_verts[0]),
- vert1_of_other_face = findInArray(other_face_verts,
- edge_verts[1]);
- int delta_other_face = get_loop_winding(vert0_of_other_face,
- vert1_of_other_face);
- if (delta_face * delta_other_face > 0) {
- IndexArray other_face_verts = getBaseFaceVertices(refiner,
- other_face),
- other_face_edges = getBaseFaceEdges(refiner,
- other_face);
- reverse_face_loops(other_face_verts,
- other_face_edges);
- }
- traverse_stack.push(other_face);
- face_used[other_face] = true;
- }
- }
- ++num_traversed_faces;
- }
- }
-#endif /* OPENSUBDIV_ORIENT_TOPOLOGY */
- /* Vertex relations */
- const int num_verts = conv.get_num_verts(&conv);
- for (int vert = 0; vert < num_verts; ++vert) {
-
- /* Vert-Faces */
- IndexArray dst_vert_faces = getBaseVertexFaces(refiner, vert);
- int num_vert_faces = conv.get_num_vert_faces(&conv, vert);
- int *vert_faces = new int[num_vert_faces];
- conv.get_vert_faces(&conv, vert, vert_faces);
- /* Vert-Edges */
- IndexArray dst_vert_edges = getBaseVertexEdges(refiner, vert);
- int num_vert_edges = conv.get_num_vert_edges(&conv, vert);
- int *vert_edges = new int[num_vert_edges];
- conv.get_vert_edges(&conv, vert, vert_edges);
-#ifdef OPENSUBDIV_ORIENT_TOPOLOGY
- /* ** Order vertex edges and faces in a CCW order. ** */
- memset(face_used, 0, sizeof(bool) * num_faces);
- /* Number of edges and faces added to the ordered array. */
- int edge_count_ordered = 0, face_count_ordered = 0;
- /* Add loose edges straight into the edges array. */
- bool has_fan_connections = false;
- for (int i = 0; i < num_vert_edges; ++i) {
- IndexArray edge_faces = getBaseEdgeFaces(refiner, vert_edges[i]);
- if (edge_faces.size() == 0) {
- dst_vert_edges[edge_count_ordered++] = vert_edges[i];
- }
- else if (edge_faces.size() > 2) {
- has_fan_connections = true;
- }
- }
- if (has_fan_connections) {
- /* OpenSubdiv currently doesn't give us clues how to handle
- * fan face connections. and since handling such connections
- * complicates the loop below we simply don't do special
- * orientation for them.
- */
- memcpy(&dst_vert_edges[0], vert_edges, sizeof(int) * num_vert_edges);
- memcpy(&dst_vert_faces[0], vert_faces, sizeof(int) * num_vert_faces);
- delete [] vert_edges;
- delete [] vert_faces;
- continue;
- }
- /* Perform at max numbder of vert-edges iteration and try to avoid
- * deadlock here for malformed mesh.
- */
- for (int global_iter = 0; global_iter < num_vert_edges; ++global_iter) {
- /* Numbr of edges and faces which are still to be ordered. */
- int num_vert_edges_remained = num_vert_edges - edge_count_ordered,
- num_vert_faces_remained = num_vert_faces - face_count_ordered;
- if (num_vert_edges_remained == 0 && num_vert_faces_remained == 0) {
- /* All done, nothing to do anymore. */
- break;
- }
- /* Face, edge and face-vertex inndex to start traversal from. */
- int face_start = -1, edge_start = -1, face_vert_start = -1;
- if (num_vert_edges_remained == num_vert_faces_remained) {
- /* Vertex is eitehr complete manifold or is connected to seevral
- * manifold islands (hourglass-like configuration), can pick up
- * random edge unused and start from it.
- */
- /* TODO(sergey): Start from previous edge from which traversal
- * began at previous iteration.
- */
- for (int i = 0; i < num_vert_edges; ++i) {
- face_start = vert_faces[i];
- if (!face_used[face_start]) {
- ConstIndexArray
- face_verts = getBaseFaceVertices(refiner, face_start),
- face_edges = getBaseFaceEdges(refiner, face_start);
- face_vert_start = findInArray(face_verts, vert);
- edge_start = face_edges[face_vert_start];
- break;
- }
- }
- }
- else {
- /* Special handle of non-manifold vertex. */
- for (int i = 0; i < num_vert_edges; ++i) {
- edge_start = vert_edges[i];
- IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_start);
- if (edge_faces.size() == 1) {
- face_start = edge_faces[0];
- if (!face_used[face_start]) {
- ConstIndexArray
- face_verts = getBaseFaceVertices(refiner, face_start),
- face_edges = getBaseFaceEdges(refiner, face_start);
- face_vert_start = findInArray(face_verts, vert);
- if (edge_start == face_edges[face_vert_start]) {
- break;
- }
- }
- }
- /* Reset indices for sanity check below. */
- face_start = edge_start = face_vert_start = -1;
- }
- }
- /* Sanity check. */
- assert(face_start != -1 &&
- edge_start != -1 &&
- face_vert_start != -1);
- /* Traverse faces starting from the current one. */
- int edge_first = edge_start;
- dst_vert_faces[face_count_ordered++] = face_start;
- dst_vert_edges[edge_count_ordered++] = edge_start;
- face_used[face_start] = true;
- while (edge_count_ordered < num_vert_edges) {
- IndexArray face_verts = getBaseFaceVertices(refiner, face_start);
- IndexArray face_edges = getBaseFaceEdges(refiner, face_start);
- int face_edge_start = face_vert_start;
- int face_edge_next = (face_edge_start > 0) ? (face_edge_start - 1) : (face_verts.size() - 1);
- Index edge_next = face_edges[face_edge_next];
- if (edge_next == edge_first) {
- /* Multiple manifolds found, stop for now and handle rest
- * in the next iteration.
- */
- break;
- }
- dst_vert_edges[edge_count_ordered++] = edge_next;
- if (face_count_ordered < num_vert_faces) {
- IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_next);
- assert(edge_faces.size() != 0);
- if (edge_faces.size() == 1) {
- assert(edge_faces[0] == face_start);
- break;
- }
- else if (edge_faces.size() != 2) {
- break;
- }
- assert(edge_faces.size() == 2);
- face_start = edge_faces[(edge_faces[0] == face_start) ? 1 : 0];
- face_vert_start = findInArray(getBaseFaceEdges(refiner, face_start), edge_next);
- dst_vert_faces[face_count_ordered++] = face_start;
- face_used[face_start] = true;
- }
- edge_start = edge_next;
- }
- }
- /* Verify ordering doesn't ruin connectivity information. */
- assert(face_count_ordered == num_vert_faces);
- assert(edge_count_ordered == num_vert_edges);
- check_oriented_vert_connectivity(num_vert_edges,
- num_vert_faces,
- vert_edges,
- vert_faces,
- &dst_vert_edges[0],
- &dst_vert_faces[0]);
- /* For the release builds we're failing mesh construction so instead
- * of nasty bugs the unsupported mesh will simply disappear from the
- * viewport.
- */
- if (face_count_ordered != num_vert_faces ||
- edge_count_ordered != num_vert_edges)
- {
- delete [] vert_edges;
- delete [] vert_faces;
- return false;
- }
-#else /* OPENSUBDIV_ORIENT_TOPOLOGY */
- memcpy(&dst_vert_edges[0], vert_edges, sizeof(int) * num_vert_edges);
- memcpy(&dst_vert_faces[0], vert_faces, sizeof(int) * num_vert_faces);
-#endif /* OPENSUBDIV_ORIENT_TOPOLOGY */
- delete [] vert_edges;
- delete [] vert_faces;
- }
-#ifdef OPENSUBDIV_ORIENT_TOPOLOGY
- delete [] face_used;
-#endif
- populateBaseLocalIndices(refiner);
- return true;
-};
-
-template <>
-inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags(
- TopologyRefiner& refiner,
- const TopologyRefinerData& cb_data)
-{
- const OpenSubdiv_Converter& conv = cb_data.conv;
- typedef OpenSubdiv::Sdc::Crease Crease;
-
- int num_edges = conv.get_num_edges(&conv);
- for (int edge = 0; edge < num_edges; ++edge) {
- float sharpness;
- ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge);
- if (edge_faces.size() == 2) {
- sharpness = conv.get_edge_sharpness(&conv, edge);
- }
- else {
- /* Non-manifold edges must be sharp. */
- sharpness = Crease::SHARPNESS_INFINITE;
- }
- setBaseEdgeSharpness(refiner, edge, sharpness);
- }
-
- /* OpenSubdiv expects non-manifold vertices to be sharp but at the
- * time it handles correct cases when vertex is a corner of plane.
- * Currently mark verts which are adjacent to a loose edge as sharp,
- * but this decision needs some more investigation.
- */
- int num_vert = conv.get_num_verts(&conv);
- for (int vert = 0; vert < num_vert; ++vert) {
- ConstIndexArray vert_edges = getBaseVertexEdges(refiner, vert);
- for (int edge_index = 0; edge_index < vert_edges.size(); ++edge_index) {
- int edge = vert_edges[edge_index];
- ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge);
- if (edge_faces.size() == 0) {
- setBaseVertexSharpness(refiner, vert, Crease::SHARPNESS_INFINITE);
- break;
- }
- }
- if (vert_edges.size() == 2) {
- int edge0 = vert_edges[0],
- edge1 = vert_edges[1];
- float sharpness0 = conv.get_edge_sharpness(&conv, edge0),
- sharpness1 = conv.get_edge_sharpness(&conv, edge1);
- float sharpness = std::min(sharpness0, sharpness1);
- setBaseVertexSharpness(refiner, vert, sharpness);
- }
- }
-
- return true;
-}
-
-template <>
-inline void TopologyRefinerFactory<TopologyRefinerData>::reportInvalidTopology(
- TopologyError /*errCode*/,
- const char *msg,
- const TopologyRefinerData& /*mesh*/)
-{
- printf("OpenSubdiv Error: %s\n", msg);
-}
-
-template <>
-inline bool TopologyRefinerFactory<TopologyRefinerData>::assignFaceVaryingTopology(
- TopologyRefiner& refiner,
- const TopologyRefinerData& cb_data)
-{
- const OpenSubdiv_Converter& conv = cb_data.conv;
- const int num_layers = conv.get_num_uv_layers(&conv);
- if (num_layers <= 0) {
- /* No UV maps, we can skip any face-varying data. */
- return true;
- }
- const int num_faces = getNumBaseFaces(refiner);
- size_t uvs_offset = 0;
- for (int layer = 0; layer < num_layers; ++layer) {
- conv.precalc_uv_layer(&conv, layer);
- const int num_uvs = conv.get_num_uvs(&conv);
- /* Fill in UV coordinates. */
- cb_data.uvs->resize(cb_data.uvs->size() + num_uvs * 2);
- conv.get_uvs(&conv, &cb_data.uvs->at(uvs_offset));
- uvs_offset += num_uvs * 2;
- /* Fill in per-corner index of the UV. */
- const int channel = createBaseFVarChannel(refiner, num_uvs);
- for (int face = 0; face < num_faces; ++face) {
- Far::IndexArray dst_face_uvs = getBaseFaceFVarValues(refiner,
- face,
- channel);
- for (int corner = 0; corner < dst_face_uvs.size(); ++corner) {
- const int uv_index = conv.get_face_corner_uv_index(&conv,
- face,
- corner);
- dst_face_uvs[corner] = uv_index;
- }
- }
- conv.finish_uv_layer(&conv);
- }
- return true;
-}
-
-} /* namespace Far */
-} /* namespace OPENSUBDIV_VERSION */
-} /* namespace OpenSubdiv */
-
-namespace {
-
-OpenSubdiv::Sdc::SchemeType get_capi_scheme_type(OpenSubdiv_SchemeType type)
-{
- switch (type) {
- case OSD_SCHEME_BILINEAR:
- return OpenSubdiv::Sdc::SCHEME_BILINEAR;
- case OSD_SCHEME_CATMARK:
- return OpenSubdiv::Sdc::SCHEME_CATMARK;
- case OSD_SCHEME_LOOP:
- return OpenSubdiv::Sdc::SCHEME_LOOP;
- }
- assert(!"Unknown scheme type passed via C-API");
- return OpenSubdiv::Sdc::SCHEME_CATMARK;
-}
-
-OpenSubdiv::Sdc::Options::FVarLinearInterpolation
-get_capi_fvar_linear_interpolation(
- OpenSubdiv_FVarLinearInterpolation linear_interpolation)
-{
- typedef OpenSubdiv::Sdc::Options Options;
- switch (linear_interpolation) {
- case OSD_FVAR_LINEAR_INTERPOLATION_NONE:
- return Options::FVAR_LINEAR_NONE;
- case OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY:
- return Options::FVAR_LINEAR_CORNERS_ONLY;
- case OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES:
- return Options::FVAR_LINEAR_BOUNDARIES;
- case OSD_FVAR_LINEAR_INTERPOLATION_ALL:
- return Options::FVAR_LINEAR_ALL;
- }
- assert(!"Unknown fvar linear interpolation passed via C-API");
- return Options::FVAR_LINEAR_NONE;
-}
-
-} /* namespace */
-
-struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr(
- OpenSubdiv_Converter *converter)
-{
- typedef OpenSubdiv::Sdc::Options Options;
-
- using OpenSubdiv::Far::TopologyRefinerFactory;
- const OpenSubdiv::Sdc::SchemeType scheme_type =
- get_capi_scheme_type(converter->get_scheme_type(converter));
- const Options::FVarLinearInterpolation linear_interpolation =
- get_capi_fvar_linear_interpolation(
- converter->get_fvar_linear_interpolation(converter));
- Options options;
- options.SetVtxBoundaryInterpolation(Options::VTX_BOUNDARY_EDGE_ONLY);
- options.SetCreasingMethod(Options::CREASE_UNIFORM);
- options.SetFVarLinearInterpolation(linear_interpolation);
-
- TopologyRefinerFactory<TopologyRefinerData>::Options
- topology_options(scheme_type, options);
-#ifdef OPENSUBDIV_VALIDATE_TOPOLOGY
- topology_options.validateFullTopology = true;
-#endif
- OpenSubdiv_TopologyRefinerDescr *result = OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefinerDescr);
- TopologyRefinerData cb_data = {*converter, &result->uvs};
- /* We don't use guarded allocation here so we can re-use the refiner
- * for GL mesh creation directly.
- */
- result->osd_refiner =
- TopologyRefinerFactory<TopologyRefinerData>::Create(
- cb_data,
- topology_options);
-
- return result;
-}
-
-void openSubdiv_deleteTopologyRefinerDescr(
- OpenSubdiv_TopologyRefinerDescr *topology_refiner)
-{
- delete topology_refiner->osd_refiner;
- OBJECT_GUARDED_DELETE(topology_refiner, OpenSubdiv_TopologyRefinerDescr);
-}
-
-int openSubdiv_topologyRefinerGetSubdivLevel(
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner)
-{
- using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = topology_refiner->osd_refiner;
- return refiner->GetMaxLevel();
-}
-
-int openSubdiv_topologyRefinerGetNumVerts(
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner)
-{
- using OpenSubdiv::Far::TopologyLevel;
- using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = topology_refiner->osd_refiner;
- const TopologyLevel &base_level = refiner->GetLevel(0);
- return base_level.GetNumVertices();
-}
-
-int openSubdiv_topologyRefinerGetNumEdges(
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner)
-{
- using OpenSubdiv::Far::TopologyLevel;
- using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = topology_refiner->osd_refiner;
- const TopologyLevel &base_level = refiner->GetLevel(0);
- return base_level.GetNumEdges();
-}
-
-int openSubdiv_topologyRefinerGetNumFaces(
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner)
-{
- using OpenSubdiv::Far::TopologyLevel;
- using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = topology_refiner->osd_refiner;
- const TopologyLevel &base_level = refiner->GetLevel(0);
- return base_level.GetNumFaces();
-}
-
-int openSubdiv_topologyRefinerGetNumFaceVerts(
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner,
- int face)
-{
- using OpenSubdiv::Far::TopologyLevel;
- using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = topology_refiner->osd_refiner;
- const TopologyLevel &base_level = refiner->GetLevel(0);
- return base_level.GetFaceVertices(face).size();
-}
-
-int openSubdiv_topologyRefnerCompareConverter(
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner,
- OpenSubdiv_Converter *converter)
-{
- typedef OpenSubdiv::Sdc::Options Options;
- using OpenSubdiv::Far::ConstIndexArray;
- using OpenSubdiv::Far::TopologyRefiner;
- using OpenSubdiv::Far::TopologyLevel;
- const TopologyRefiner *refiner = topology_refiner->osd_refiner;
- const TopologyLevel &base_level = refiner->GetLevel(0);
- const int num_verts = base_level.GetNumVertices();
- const int num_edges = base_level.GetNumEdges();
- const int num_faces = base_level.GetNumFaces();
- /* Quick preliminary check. */
- OpenSubdiv::Sdc::SchemeType scheme_type =
- get_capi_scheme_type(converter->get_scheme_type(converter));
- if (scheme_type != refiner->GetSchemeType()) {
- return false;
- }
- const Options options = refiner->GetSchemeOptions();
- const Options::FVarLinearInterpolation interp =
- options.GetFVarLinearInterpolation();
- const Options::FVarLinearInterpolation new_interp =
- get_capi_fvar_linear_interpolation(
- converter->get_fvar_linear_interpolation(converter));
- if (new_interp != interp) {
- return false;
- }
- if (converter->get_num_verts(converter) != num_verts ||
- converter->get_num_edges(converter) != num_edges ||
- converter->get_num_faces(converter) != num_faces)
- {
- return false;
- }
- /* Compare all edges. */
- for (int edge = 0; edge < num_edges; ++edge) {
- ConstIndexArray edge_verts = base_level.GetEdgeVertices(edge);
- int conv_edge_verts[2];
- converter->get_edge_verts(converter, edge, conv_edge_verts);
- if (conv_edge_verts[0] != edge_verts[0] ||
- conv_edge_verts[1] != edge_verts[1])
- {
- return false;
- }
- }
- /* Compare all faces. */
- std::vector<int> conv_face_verts;
- for (int face = 0; face < num_faces; ++face) {
- ConstIndexArray face_verts = base_level.GetFaceVertices(face);
- if (face_verts.size() != converter->get_num_face_verts(converter,
- face))
- {
- return false;
- }
- conv_face_verts.resize(face_verts.size());
- converter->get_face_verts(converter, face, &conv_face_verts[0]);
- bool direct_match = true;
- for (int i = 0; i < face_verts.size(); ++i) {
- if (conv_face_verts[i] != face_verts[i]) {
- direct_match = false;
- break;
- }
- }
- if (!direct_match) {
- /* If face didn't match in direct direction we also test if it
- * matches in reversed direction. This is because conversion might
- * reverse loops to make normals consistent.
- */
-#ifdef OPENSUBDIV_ORIENT_TOPOLOGY
- reverse_face_verts(&conv_face_verts[0], conv_face_verts.size());
- for (int i = 0; i < face_verts.size(); ++i) {
- if (conv_face_verts[i] != face_verts[i]) {
- return false;
- }
- }
-#else
- return false;
-#endif
- }
- }
- /* Compare sharpness. */
- for (int edge = 0; edge < num_edges; ++edge) {
- ConstIndexArray edge_faces = base_level.GetEdgeFaces(edge);
- float sharpness = base_level.GetEdgeSharpness(edge);
- float conv_sharpness;
- if (edge_faces.size() == 2) {
- conv_sharpness = converter->get_edge_sharpness(converter, edge);
- }
- else {
- conv_sharpness = OpenSubdiv::Sdc::Crease::SHARPNESS_INFINITE;
- }
- if (sharpness != conv_sharpness) {
- return false;
- }
- }
- return true;
-}
diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h
index ea4f20c5961..1d76da4d76b 100644
--- a/intern/opensubdiv/opensubdiv_converter_capi.h
+++ b/intern/opensubdiv/opensubdiv_converter_capi.h
@@ -1,149 +1,150 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2015 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Sergey Sharybin.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __OPENSUBDIV_CONVERTER_CAPI_H__
-#define __OPENSUBDIV_CONVERTER_CAPI_H__
+// Copyright 2015 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_CONVERTER_CAPI_H_
+#define OPENSUBDIV_CONVERTER_CAPI_H_
#ifdef __cplusplus
extern "C" {
#endif
-struct OpenSubdiv_TopologyRefinerDescr;
-typedef struct OpenSubdiv_TopologyRefinerDescr OpenSubdiv_TopologyRefinerDescr;
-
-typedef struct OpenSubdiv_Converter OpenSubdiv_Converter;
-
typedef enum OpenSubdiv_SchemeType {
- OSD_SCHEME_BILINEAR,
- OSD_SCHEME_CATMARK,
- OSD_SCHEME_LOOP,
+ OSD_SCHEME_BILINEAR,
+ OSD_SCHEME_CATMARK,
+ OSD_SCHEME_LOOP,
} OpenSubdiv_SchemeType;
typedef enum OpenSubdiv_FVarLinearInterpolation {
- OSD_FVAR_LINEAR_INTERPOLATION_NONE,
- OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY,
- OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES,
- OSD_FVAR_LINEAR_INTERPOLATION_ALL,
+ OSD_FVAR_LINEAR_INTERPOLATION_NONE,
+ OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY,
+ OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES,
+ OSD_FVAR_LINEAR_INTERPOLATION_ALL,
} OpenSubdiv_FVarLinearInterpolation;
typedef struct OpenSubdiv_Converter {
- /* TODO(sergey): Needs to be implemented. */
- /* OpenSubdiv::Sdc::Options get_options() const; */
-
- OpenSubdiv_SchemeType (*get_scheme_type)(
- const OpenSubdiv_Converter *converter);
-
- OpenSubdiv_FVarLinearInterpolation (*get_fvar_linear_interpolation)(
- const OpenSubdiv_Converter *converter);
-
- int (*get_num_faces)(const OpenSubdiv_Converter *converter);
- int (*get_num_edges)(const OpenSubdiv_Converter *converter);
- int (*get_num_verts)(const OpenSubdiv_Converter *converter);
-
- /* Face relationships. */
- int (*get_num_face_verts)(const OpenSubdiv_Converter *converter,
- int face);
- void (*get_face_verts)(const OpenSubdiv_Converter *converter,
- int face,
- int *face_verts);
- void (*get_face_edges)(const OpenSubdiv_Converter *converter,
- int face,
- int *face_edges);
-
- /* Edge relationships. */
- void (*get_edge_verts)(const OpenSubdiv_Converter *converter,
- int edge,
- int *edge_verts);
- int (*get_num_edge_faces)(const OpenSubdiv_Converter *converter,
- int edge);
- void (*get_edge_faces)(const OpenSubdiv_Converter *converter,
- int edge,
- int *edge_faces);
- float (*get_edge_sharpness)(const OpenSubdiv_Converter *converter,
- int edge);
-
- /* Vertex relationships. */
- int (*get_num_vert_edges)(const OpenSubdiv_Converter *converter, int vert);
- void (*get_vert_edges)(const OpenSubdiv_Converter *converter,
- int vert,
- int *vert_edges);
- int (*get_num_vert_faces)(const OpenSubdiv_Converter *converter, int vert);
- void (*get_vert_faces)(const OpenSubdiv_Converter *converter,
- int vert,
- int *vert_faces);
-
- /* Face-varying data. */
- int (*get_num_uv_layers)(const OpenSubdiv_Converter *converter);
-
- void (*precalc_uv_layer)(const OpenSubdiv_Converter *converter, int layer);
- void (*finish_uv_layer)(const OpenSubdiv_Converter *converter);
-
- int (*get_num_uvs)(const OpenSubdiv_Converter *converter);
- void (*get_uvs)(const OpenSubdiv_Converter *converter, float *uvs);
-
- int (*get_face_corner_uv_index)(const OpenSubdiv_Converter *converter,
- int face,
- int corner);
-
- /* User data associated with this converter. */
- void (*free_user_data)(const OpenSubdiv_Converter *converter);
- void *user_data;
+ OpenSubdiv_SchemeType (*getSchemeType)(
+ const struct OpenSubdiv_Converter* converter);
+
+ OpenSubdiv_FVarLinearInterpolation (*getFVarLinearInterpolation)(
+ const struct OpenSubdiv_Converter* converter);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Global geometry counters.
+ // Number of faces/edges/vertices in the base mesh.
+ int (*getNumFaces)(const struct OpenSubdiv_Converter* converter);
+ int (*getNumEdges)(const struct OpenSubdiv_Converter* converter);
+ int (*getNumVertices)(const struct OpenSubdiv_Converter* converter);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Face relationships.
+
+ // Number of vertices the face consists of.
+ int (*getNumFaceVertices)(const struct OpenSubdiv_Converter* converter,
+ const int face_index);
+ // Array of vertex indices the face consists of.
+ void (*getFaceVertices)(const struct OpenSubdiv_Converter* converter,
+ const int face_index,
+ int* face_vertices);
+ // Array of edge indices the face consists of.
+ // Aligned with the vertex indices array, edge i connects face vertex i
+ // with face index i+1.
+ void (*getFaceEdges)(const struct OpenSubdiv_Converter *converter,
+ const int face_index,
+ int *face_edges);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Edge relationships.
+
+ // Vertices the edge consists of.
+ void (*getEdgeVertices)(const struct OpenSubdiv_Converter* converter,
+ const int edge_index,
+ int edge_vertices[2]);
+ // Number of faces which are sharing the given edge.
+ int (*getNumEdgeFaces)(const struct OpenSubdiv_Converter* converter,
+ const int edge_index);
+ // Array of face indices which are sharing the given edge.
+ void (*getEdgeFaces)(const struct OpenSubdiv_Converter* converter,
+ const int edge,
+ int* edge_faces);
+ // Edge sharpness (aka crease).
+ float (*getEdgeSharpness)(const struct OpenSubdiv_Converter* converter,
+ const int edge_index);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Vertex relationships.
+
+ // Number of edges which are adjacent to the given vertex.
+ int (*getNumVertexEdges)(const struct OpenSubdiv_Converter* converter,
+ const int vertex_index);
+ // Array fo edge indices which are adjacent to the given vertex.
+ void (*getVertexEdges)(const struct OpenSubdiv_Converter* converter,
+ const int vertex_index,
+ int* vertex_edges);
+ // Number of faces which are adjacent to the given vertex.
+ int (*getNumVertexFaces)(const struct OpenSubdiv_Converter* converter,
+ const int vertex_index);
+ // Array fo face indices which are adjacent to the given vertex.
+ void (*getVertexFaces)(const struct OpenSubdiv_Converter* converter,
+ const int vertex_index,
+ int* vertex_faces);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Face-varying data.
+
+ /////////////////////////////////////
+ // UV coordinates.
+
+ // Number of UV layers.
+ int (*getNumUVLayers)(const struct OpenSubdiv_Converter* converter);
+
+ // We need some corner connectivity information, which might not be trivial
+ // to be gathered (might require multiple matching calculations per corver
+ // query).
+ // precalc() is called before any corner connectivity or UV coordinate is
+ // queried from the given layer, allowing converter to calculate and cache
+ // complex complex-to-calculate information.
+ // finish() is called after converter is done porting UV layer to OpenSubdiv,
+ // allowing to free cached data.
+ void (*precalcUVLayer)(const struct OpenSubdiv_Converter* converter,
+ const int layer_index);
+ void (*finishUVLayer)(const struct OpenSubdiv_Converter* converter);
+
+ // Get number of UV coordinates in the current layer (layer which was
+ // specified in precalcUVLayer().
+ int (*getNumUVCoordinates)(const struct OpenSubdiv_Converter* converter);
+ // Get cooridnates themselves.
+ void (*getUVCoordinates)(const struct OpenSubdiv_Converter* converter,
+ float* uvs_coordinates);
+ // For the given face index and its corner (known as loop in Blender)
+ // get corrsponding UV coordinate index.
+ int (*getFaceCornerUVIndex)(const struct OpenSubdiv_Converter* converter,
+ const int face_index,
+ const int corner_index);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // User data associated with this converter.
+
+ void (*freeUserData)(const struct OpenSubdiv_Converter* converter);
+ void* user_data;
} OpenSubdiv_Converter;
-OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr(
- OpenSubdiv_Converter *converter);
-
-void openSubdiv_deleteTopologyRefinerDescr(
- OpenSubdiv_TopologyRefinerDescr *topology_refiner);
-
-/* TODO(sergey): Those calls are not strictly related to conversion.
- * needs some dedicated file perhaps.
- */
-
-int openSubdiv_topologyRefinerGetSubdivLevel(
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner);
-
-int openSubdiv_topologyRefinerGetNumVerts(
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner);
-
-int openSubdiv_topologyRefinerGetNumEdges(
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner);
-
-int openSubdiv_topologyRefinerGetNumFaces(
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner);
-
-int openSubdiv_topologyRefinerGetNumFaceVerts(
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner,
- int face);
-
-int openSubdiv_topologyRefnerCompareConverter(
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner,
- OpenSubdiv_Converter *converter);
-
#ifdef __cplusplus
}
#endif
-#endif /* __OPENSUBDIV_CONVERTER_CAPI_H__ */
+#endif /* OPENSUBDIV_CONVERTER_CAPI_H_ */
diff --git a/intern/opensubdiv/opensubdiv_device_context_cuda.cc b/intern/opensubdiv/opensubdiv_device_context_cuda.cc
deleted file mode 100644
index 46b66a6b35e..00000000000
--- a/intern/opensubdiv/opensubdiv_device_context_cuda.cc
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Adopted from OpenSubdiv with the following license:
- *
- * 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.
- */
-
-#ifdef OPENSUBDIV_HAS_CUDA
-
-#ifdef _MSC_VER
-# include "iso646.h"
-#endif
-
-#include "opensubdiv_device_context_cuda.h"
-
-#if defined(_WIN32)
-# include <windows.h>
-#elif defined(__APPLE__)
-# include <OpenGL/OpenGL.h>
-#else
-# include <X11/Xlib.h>
-# include <GL/glx.h>
-#endif
-
-#include <cstdio>
-#include <algorithm>
-#include <cuda.h>
-#include <cuda_runtime_api.h>
-#include <cuda_gl_interop.h>
-
-#define message(fmt, ...)
-//#define message(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
-#define error(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
-
-static int _GetCudaDeviceForCurrentGLContext()
-{
- // Find and use the CUDA device for the current GL context
- unsigned int interopDeviceCount = 0;
- int interopDevices[1];
- cudaError_t status = cudaGLGetDevices(&interopDeviceCount, interopDevices,
- 1, cudaGLDeviceListCurrentFrame);
- if (status == cudaErrorNoDevice or interopDeviceCount != 1) {
- message("CUDA no interop devices found.\n");
- return 0;
- }
- int device = interopDevices[0];
-
-#if defined(_WIN32)
- return device;
-
-#elif defined(__APPLE__)
- return device;
-
-#else // X11
- Display * display = glXGetCurrentDisplay();
- int screen = DefaultScreen(display);
- if (device != screen) {
- error("The CUDA interop device (%d) does not match "
- "the screen used by the current GL context (%d), "
- "which may cause slow performance on systems "
- "with multiple GPU devices.", device, screen);
- }
- message("CUDA init using device for current GL context: %d\n", device);
- return device;
-#endif
-}
-
-/* From "NVIDIA GPU Computing SDK 4.2/C/common/inc/cutil_inline_runtime.h": */
-
-/* Beginning of GPU Architecture definitions */
-inline int _ConvertSMVer2Cores_local(int major, int minor)
-{
- /* Defines for GPU Architecture types (using the SM version to determine
- * the # of cores per SM
- */
- typedef struct {
- int SM; /* 0xMm (hexidecimal notation),
- * M = SM Major version,
- * and m = SM minor version
- */
- int Cores;
- } sSMtoCores;
-
- sSMtoCores nGpuArchCoresPerSM[] =
- { { 0x10, 8 }, /* Tesla Generation (SM 1.0) G80 class */
- { 0x11, 8 }, /* Tesla Generation (SM 1.1) G8x class */
- { 0x12, 8 }, /* Tesla Generation (SM 1.2) G9x class */
- { 0x13, 8 }, /* Tesla Generation (SM 1.3) GT200 class */
- { 0x20, 32 }, /* Fermi Generation (SM 2.0) GF100 class */
- { 0x21, 48 }, /* Fermi Generation (SM 2.1) GF10x class */
- { 0x30, 192}, /* Fermi Generation (SM 3.0) GK10x class */
- { -1, -1 }
- };
-
- int index = 0;
- while (nGpuArchCoresPerSM[index].SM != -1) {
- if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor)) {
- return nGpuArchCoresPerSM[index].Cores;
- }
- index++;
- }
- printf("MapSMtoCores undefined SMversion %d.%d!\n", major, minor);
- return -1;
-}
-/* End of GPU Architecture definitions. */
-
-/* This function returns the best GPU (with maximum GFLOPS) */
-inline int cutGetMaxGflopsDeviceId()
-{
- int current_device = 0, sm_per_multiproc = 0;
- int max_compute_perf = 0, max_perf_device = -1;
- int device_count = 0, best_SM_arch = 0;
- int compat_major, compat_minor;
-
- cuDeviceGetCount(&device_count);
- /* Find the best major SM Architecture GPU device. */
- while (current_device < device_count) {
- cuDeviceComputeCapability(&compat_major, &compat_minor, current_device);
- if (compat_major > 0 && compat_major < 9999) {
- best_SM_arch = std::max(best_SM_arch, compat_major);
- }
- current_device++;
- }
-
- /* Find the best CUDA capable GPU device. */
- current_device = 0;
- while (current_device < device_count) {
- cuDeviceComputeCapability(&compat_major, &compat_minor, current_device);
- if (compat_major == 9999 && compat_minor == 9999) {
- sm_per_multiproc = 1;
- } else {
- sm_per_multiproc = _ConvertSMVer2Cores_local(compat_major,
- compat_minor);
- }
- int multi_processor_count;
- cuDeviceGetAttribute(&multi_processor_count,
- CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT,
- current_device);
- int clock_rate;
- cuDeviceGetAttribute(&clock_rate,
- CU_DEVICE_ATTRIBUTE_CLOCK_RATE,
- current_device);
- int compute_perf = multi_processor_count * sm_per_multiproc * clock_rate;
- if (compute_perf > max_compute_perf) {
- /* If we find GPU with SM major > 2, search only these */
- if (best_SM_arch > 2) {
- /* If our device==dest_SM_arch, choose this, or else pass. */
- if (compat_major == best_SM_arch) {
- max_compute_perf = compute_perf;
- max_perf_device = current_device;
- }
- } else {
- max_compute_perf = compute_perf;
- max_perf_device = current_device;
- }
- }
- ++current_device;
- }
- return max_perf_device;
-}
-
-bool CudaDeviceContext::HAS_CUDA_VERSION_4_0()
-{
-#ifdef OPENSUBDIV_HAS_CUDA
- static bool cudaInitialized = false;
- static bool cudaLoadSuccess = true;
- if (!cudaInitialized) {
- cudaInitialized = true;
-
-# ifdef OPENSUBDIV_HAS_CUEW
- cudaLoadSuccess = cuewInit(CUEW_INIT_CUDA) == CUEW_SUCCESS;
- if (!cudaLoadSuccess) {
- fprintf(stderr, "Loading CUDA failed.\n");
- }
-# endif
- // Need to initialize CUDA here so getting device
- // with the maximum FPLOS works fine.
- if (cuInit(0) == CUDA_SUCCESS) {
- // This is to deal with cases like NVidia Optimus,
- // when there might be CUDA library installed but
- // NVidia card is not being active.
- if (cutGetMaxGflopsDeviceId() < 0) {
- cudaLoadSuccess = false;
- }
- }
- else {
- cudaLoadSuccess = false;
- }
- }
- return cudaLoadSuccess;
-#else
- return false;
-#endif
-}
-
-CudaDeviceContext::CudaDeviceContext()
- : _initialized(false) {
-}
-
-CudaDeviceContext::~CudaDeviceContext() {
- cudaDeviceReset();
-}
-
-bool CudaDeviceContext::Initialize()
-{
- /* See if any cuda device is available. */
- int deviceCount = 0;
- cudaGetDeviceCount(&deviceCount);
- message("CUDA device count: %d\n", deviceCount);
- if (deviceCount <= 0) {
- return false;
- }
- cudaGLSetGLDevice(_GetCudaDeviceForCurrentGLContext());
- _initialized = true;
- return true;
-}
-
-#endif /* OPENSUBDIV_HAS_CUDA */
diff --git a/intern/opensubdiv/opensubdiv_device_context_cuda.h b/intern/opensubdiv/opensubdiv_device_context_cuda.h
deleted file mode 100644
index eb30b76f507..00000000000
--- a/intern/opensubdiv/opensubdiv_device_context_cuda.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Adopted from OpenSubdiv with the following license:
- *
- * 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 __OPENSUBDIV_DEV_CE_CONTEXT_CUDA_H__
-#define __OPENSUBDIV_DEV_CE_CONTEXT_CUDA_H__
-
-struct ID3D11Device;
-
-class CudaDeviceContext {
-public:
- CudaDeviceContext();
- ~CudaDeviceContext();
-
- static bool HAS_CUDA_VERSION_4_0();
-
- /* Initialze cuda device from the current GL context. */
- bool Initialize();
-
- /* Initialze cuda device from the ID3D11Device/ */
- bool Initialize(ID3D11Device *device);
-
- /* Returns true if the cuda device has already been initialized. */
- bool IsInitialized() const {
- return _initialized;
- }
-private:
- bool _initialized;
-};
-
-#endif /* __OPENSUBDIV_DEV_CE_CONTEXT_OPENCL_H__ */
diff --git a/intern/opensubdiv/opensubdiv_device_context_opencl.cc b/intern/opensubdiv/opensubdiv_device_context_opencl.cc
deleted file mode 100644
index 4cacdc9e845..00000000000
--- a/intern/opensubdiv/opensubdiv_device_context_opencl.cc
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Adopted from OpenSubdiv with the following license:
- *
- * 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.
- *
- */
-
-#ifdef OPENSUBDIV_HAS_OPENCL
-
-#ifdef _MSC_VER
-# include "iso646.h"
-#endif
-
-#include "opensubdiv_device_context_opencl.h"
-
-#if defined(_WIN32)
-# include <windows.h>
-#elif defined(__APPLE__)
-# include <OpenGL/OpenGL.h>
-#else
-# include <GL/glx.h>
-#endif
-
-#include <cstdio>
-#include <cstring>
-#include <string>
-
-#define message(...) // fprintf(stderr, __VA_ARGS__)
-#define error(...) fprintf(stderr, __VA_ARGS__)
-
-/* Returns the first found platform. */
-static cl_platform_id findPlatform() {
- cl_uint numPlatforms;
- cl_int ciErrNum = clGetPlatformIDs(0, NULL, &numPlatforms);
- if (ciErrNum != CL_SUCCESS) {
- error("Error %d in clGetPlatformIDs call.\n", ciErrNum);
- return NULL;
- }
- if (numPlatforms == 0) {
- error("No OpenCL platform found.\n");
- return NULL;
- }
- cl_platform_id *clPlatformIDs = new cl_platform_id[numPlatforms];
- ciErrNum = clGetPlatformIDs(numPlatforms, clPlatformIDs, NULL);
- char chBuffer[1024];
- for (cl_uint i = 0; i < numPlatforms; ++i) {
- ciErrNum = clGetPlatformInfo(clPlatformIDs[i], CL_PLATFORM_NAME,
- 1024, chBuffer,NULL);
- if (ciErrNum == CL_SUCCESS) {
- cl_platform_id platformId = clPlatformIDs[i];
- delete[] clPlatformIDs;
- return platformId;
- }
- }
- delete[] clPlatformIDs;
- return NULL;
-}
-
-/* Return. the device in clDevices which supports the extension. */
-static int findExtensionSupportedDevice(cl_device_id *clDevices,
- int numDevices,
- const char *extensionName) {
- /* Find a device that supports sharing with GL/D3D11
- * (SLI / X-fire configurations)
- */
- cl_int ciErrNum;
- for (int i = 0; i < numDevices; ++i) {
- /* Get extensions string size. */
- size_t extensionSize;
- ciErrNum = clGetDeviceInfo(clDevices[i],
- CL_DEVICE_EXTENSIONS, 0, NULL,
- &extensionSize);
- if (ciErrNum != CL_SUCCESS) {
- error("Error %d in clGetDeviceInfo\n", ciErrNum);
- return -1;
- }
- if (extensionSize > 0) {
- /* Get extensions string. */
- char *extensions = new char[extensionSize];
- ciErrNum = clGetDeviceInfo(clDevices[i], CL_DEVICE_EXTENSIONS,
- extensionSize, extensions,
- &extensionSize);
- if (ciErrNum != CL_SUCCESS) {
- error("Error %d in clGetDeviceInfo\n", ciErrNum);
- delete[] extensions;
- continue;
- }
- std::string extString(extensions);
- delete[] extensions;
- /* Parse string. This is bit deficient since the extentions
- * is space separated.
- *
- * The actual string would be "cl_khr_d3d11_sharing"
- * or "cl_nv_d3d11_sharing"
- */
- if (extString.find(extensionName) != std::string::npos) {
- return i;
- }
- }
- }
- return -1;
-}
-
-CLDeviceContext::CLDeviceContext()
- : _clContext(NULL),
- _clCommandQueue(NULL) {
-}
-
-CLDeviceContext::~CLDeviceContext() {
- if (_clCommandQueue)
- clReleaseCommandQueue(_clCommandQueue);
- if (_clContext)
- clReleaseContext(_clContext);
-}
-
-bool CLDeviceContext::HAS_CL_VERSION_1_1()
-{
-#ifdef OPENSUBDIV_HAS_CLEW
- static bool clewInitialized = false;
- static bool clewLoadSuccess;
- if (not clewInitialized) {
- clewInitialized = true;
- clewLoadSuccess = clewInit() == CLEW_SUCCESS;
- if (!clewLoadSuccess) {
- error("Loading OpenCL failed.\n");
- }
- }
- return clewLoadSuccess;
-#endif
- return true;
-}
-
-bool CLDeviceContext::Initialize()
-{
-#ifdef OPENSUBDIV_HAS_CLEW
- if (!clGetPlatformIDs) {
- error("Error clGetPlatformIDs function not bound.\n");
- return false;
- }
-#endif
- cl_int ciErrNum;
- cl_platform_id cpPlatform = findPlatform();
-
-#if defined(_WIN32)
- cl_context_properties props[] = {
- CL_GL_CONTEXT_KHR, (cl_context_properties)wglGetCurrentContext(),
- CL_WGL_HDC_KHR, (cl_context_properties)wglGetCurrentDC(),
- CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform,
- 0
- };
-#elif defined(__APPLE__)
- CGLContextObj kCGLContext = CGLGetCurrentContext();
- CGLShareGroupObj kCGLShareGroup = CGLGetShareGroup(kCGLContext);
- cl_context_properties props[] = {
- CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE, (cl_context_properties)kCGLShareGroup,
- 0
- };
-#else
- cl_context_properties props[] = {
- CL_GL_CONTEXT_KHR, (cl_context_properties)glXGetCurrentContext(),
- CL_GLX_DISPLAY_KHR, (cl_context_properties)glXGetCurrentDisplay(),
- CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform,
- 0
- };
-#endif
-
-#if defined(__APPLE__)
- _clContext = clCreateContext(props, 0, NULL, clLogMessagesToStdoutAPPLE,
- NULL, &ciErrNum);
- if (ciErrNum != CL_SUCCESS) {
- error("Error %d in clCreateContext\n", ciErrNum);
- return false;
- }
-
- size_t devicesSize = 0;
- clGetGLContextInfoAPPLE(_clContext, kCGLContext,
- CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE,
- 0, NULL, &devicesSize);
- int numDevices = int(devicesSize / sizeof(cl_device_id));
- if (numDevices == 0) {
- error("No sharable devices.\n");
- return false;
- }
- cl_device_id *clDevices = new cl_device_id[numDevices];
- clGetGLContextInfoAPPLE(_clContext, kCGLContext,
- CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE,
- numDevices * sizeof(cl_device_id), clDevices, NULL);
- int clDeviceUsed = 0;
-
-#else // not __APPLE__
- /* Get the number of GPU devices available to the platform. */
- cl_uint numDevices = 0;
- clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 0, NULL, &numDevices);
- if (numDevices == 0) {
- error("No CL GPU device found.\n");
- return false;
- }
-
- /* Create the device list. */
- cl_device_id *clDevices = new cl_device_id[numDevices];
- clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, numDevices, clDevices, NULL);
-
- const char *extension = "cl_khr_gl_sharing";
- int clDeviceUsed = findExtensionSupportedDevice(clDevices, numDevices,
- extension);
-
- if (clDeviceUsed < 0) {
- error("No device found that supports CL/GL context sharing\n");
- delete[] clDevices;
- return false;
- }
-
- _clContext = clCreateContext(props, 1, &clDevices[clDeviceUsed],
- NULL, NULL, &ciErrNum);
-#endif // not __APPLE__
- if (ciErrNum != CL_SUCCESS) {
- error("Error %d in clCreateContext\n", ciErrNum);
- delete[] clDevices;
- return false;
- }
- _clCommandQueue = clCreateCommandQueue(_clContext, clDevices[clDeviceUsed],
- 0, &ciErrNum);
- delete[] clDevices;
- if (ciErrNum != CL_SUCCESS) {
- error("Error %d in clCreateCommandQueue\n", ciErrNum);
- return false;
- }
- return true;
-}
-
-#endif /* OPENSUBDIV_HAS_OPENCL */
diff --git a/intern/opensubdiv/opensubdiv_device_context_opencl.h b/intern/opensubdiv/opensubdiv_device_context_opencl.h
deleted file mode 100644
index a640dce1f07..00000000000
--- a/intern/opensubdiv/opensubdiv_device_context_opencl.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Adopted from OpenSubdiv with the following license:
- *
- * 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 __OPENSUBDIV_DEV_CE_CONTEXT_OPENCL_H__
-#define __OPENSUBDIV_DEV_CE_CONTEXT_OPENCL_H__
-
-#include <opensubdiv/osd/opencl.h>
-
-class CLDeviceContext {
-public:
- CLDeviceContext();
- ~CLDeviceContext();
-
- static bool HAS_CL_VERSION_1_1 ();
-
- bool Initialize();
-
- bool IsInitialized() const {
- return (_clContext != NULL);
- }
-
- cl_context GetContext() const {
- return _clContext;
- }
- cl_command_queue GetCommandQueue() const {
- return _clCommandQueue;
- }
-
-protected:
- cl_context _clContext;
- cl_command_queue _clCommandQueue;
-};
-
-#endif /* __OPENSUBDIV_DEV_CE_CONTEXT_OPENCL_H__ */
diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.cc b/intern/opensubdiv/opensubdiv_evaluator_capi.cc
deleted file mode 100644
index fb5313b8501..00000000000
--- a/intern/opensubdiv/opensubdiv_evaluator_capi.cc
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2015 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Sergey Sharybin.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "opensubdiv_capi.h"
-
-#include <cstdio>
-#include <vector>
-
-#ifdef _MSC_VER
-# include "iso646.h"
-#endif
-
-#include <opensubdiv/far/patchMap.h>
-#include <opensubdiv/far/patchTable.h>
-#include <opensubdiv/far/patchTableFactory.h>
-#include <opensubdiv/osd/cpuEvaluator.h>
-#include <opensubdiv/osd/cpuPatchTable.h>
-#include <opensubdiv/osd/cpuVertexBuffer.h>
-#include <opensubdiv/osd/mesh.h>
-#include <opensubdiv/osd/types.h>
-
-#include "opensubdiv_intern.h"
-#include "opensubdiv_topology_refiner.h"
-
-#include "MEM_guardedalloc.h"
-
-using OpenSubdiv::Osd::BufferDescriptor;
-using OpenSubdiv::Osd::PatchCoord;
-using OpenSubdiv::Far::PatchMap;
-using OpenSubdiv::Far::PatchTable;
-using OpenSubdiv::Far::PatchTableFactory;
-using OpenSubdiv::Far::StencilTable;
-using OpenSubdiv::Far::StencilTableFactory;
-using OpenSubdiv::Far::TopologyRefiner;
-
-namespace {
-
-/* Helper class to wrap numerous of patch coords into a buffer.
- * Used to pass coordinates to the CPU evaluator. Other evaluators
- * are not supported.
- */
-class PatchCoordBuffer : public std::vector<PatchCoord> {
-public:
- static PatchCoordBuffer *Create(int size)
- {
- PatchCoordBuffer *buffer = new PatchCoordBuffer();
- buffer->resize(size);
- return buffer;
- }
- PatchCoord *BindCpuBuffer() {
- return (PatchCoord*)&(*this)[0];
- }
- int GetNumVertices() {
- return size();
- }
- void UpdateData(const PatchCoord *patch_coords,
- int num_patch_coords)
- {
- memcpy(&(*this)[0],
- (void*)patch_coords,
- num_patch_coords * sizeof(PatchCoord));
- }
-};
-
-/* Helper class to wrap single of patch coord into a buffer.
- * Used to pass coordinates to the CPU evaluator. Other evaluators
- * are not supported.
- */
-class SinglePatchCoordBuffer {
-public:
- SinglePatchCoordBuffer() {
- }
- SinglePatchCoordBuffer(const PatchCoord& patch_coord)
- : patch_coord_(patch_coord){
- }
- static SinglePatchCoordBuffer *Create()
- {
- SinglePatchCoordBuffer *buffer = new SinglePatchCoordBuffer();
- return buffer;
- }
- PatchCoord *BindCpuBuffer() {
- return (PatchCoord*)&patch_coord_;
- }
- int GetNumVertices() {
- return 1;
- }
- void UpdateData(const PatchCoord& patch_coord)
- {
- patch_coord_ = patch_coord;
- }
-protected:
- PatchCoord patch_coord_;
-};
-
-/* Helper class which is aimed to be used in cases when buffer
- * is small enough and better to be allocated in stack rather
- * than in heap.
- *
- * TODO(sergey): Check if bare arrays could be used by CPU evaluator.
- */
-template <int element_size, int num_verts>
-class StackAllocatedBuffer {
-public:
- static PatchCoordBuffer *Create(int /*size*/)
- {
- StackAllocatedBuffer<element_size, num_verts> *buffer =
- new StackAllocatedBuffer<element_size, num_verts>();
- return buffer;
- }
- float *BindCpuBuffer() {
- return &data_[0];
- }
- int GetNumVertices() {
- return num_verts;
- }
- /* TODO(sergey): Support UpdateData(). */
-protected:
- float data_[element_size * num_verts];
-};
-
-/* Volatile evaluator which can be used from threads.
- *
- * TODO(sergey): Make it possible to evaluate coordinates in chunks.
- */
-template<typename SRC_VERTEX_BUFFER,
- typename EVAL_VERTEX_BUFFER,
- typename STENCIL_TABLE,
- typename PATCH_TABLE,
- typename EVALUATOR,
- typename DEVICE_CONTEXT = void>
-class VolatileEvalOutput {
-public:
- typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache;
-
- VolatileEvalOutput(const StencilTable *vertex_stencils,
- const StencilTable *varying_stencils,
- int num_coarse_verts,
- int num_total_verts,
- const PatchTable *patch_table,
- EvaluatorCache *evaluator_cache = NULL,
- DEVICE_CONTEXT *device_context = NULL)
- : src_desc_( /*offset*/ 0, /*length*/ 3, /*stride*/ 3),
- src_varying_desc_(/*offset*/ 0, /*length*/ 3, /*stride*/ 3),
- num_coarse_verts_(num_coarse_verts),
- evaluator_cache_ (evaluator_cache),
- device_context_(device_context)
- {
- using OpenSubdiv::Osd::convertToCompatibleStencilTable;
- src_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_verts, device_context_);
- src_varying_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_verts, device_context_);
- patch_table_ = PATCH_TABLE::Create(patch_table, device_context_);
- patch_coords_ = NULL;
- vertex_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(vertex_stencils,
- device_context_);
- varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(varying_stencils,
- device_context_);
- }
-
- ~VolatileEvalOutput()
- {
- delete src_data_;
- delete src_varying_data_;
- delete patch_table_;
- delete vertex_stencils_;
- delete varying_stencils_;
- }
-
- void UpdateData(const float *src, int start_vertex, int num_vertices)
- {
- src_data_->UpdateData(src, start_vertex, num_vertices, device_context_);
- }
-
- void UpdateVaryingData(const float *src, int start_vertex, int num_vertices)
- {
- src_varying_data_->UpdateData(src,
- start_vertex,
- num_vertices,
- device_context_);
- }
-
- void Refine()
- {
- BufferDescriptor dst_desc = src_desc_;
- dst_desc.offset += num_coarse_verts_ * src_desc_.stride;
-
- const EVALUATOR *eval_instance =
- OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
- src_desc_,
- dst_desc,
- device_context_);
-
- EVALUATOR::EvalStencils(src_data_, src_desc_,
- src_data_, dst_desc,
- vertex_stencils_,
- eval_instance,
- device_context_);
-
- dst_desc = src_varying_desc_;
- dst_desc.offset += num_coarse_verts_ * src_varying_desc_.stride;
- eval_instance =
- OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
- src_varying_desc_,
- dst_desc,
- device_context_);
-
- EVALUATOR::EvalStencils(src_varying_data_, src_varying_desc_,
- src_varying_data_, dst_desc,
- varying_stencils_,
- eval_instance,
- device_context_);
- }
-
- void EvalPatchCoord(PatchCoord& patch_coord, float P[3])
- {
- StackAllocatedBuffer<6, 1> vertex_data;
- BufferDescriptor vertex_desc(0, 3, 6);
- SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
- const EVALUATOR *eval_instance =
- OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
- src_desc_,
- vertex_desc,
- device_context_);
- EVALUATOR::EvalPatches(src_data_, src_desc_,
- &vertex_data, vertex_desc,
- patch_coord_buffer.GetNumVertices(),
- &patch_coord_buffer,
- patch_table_, eval_instance, device_context_);
- float *refined_verts = vertex_data.BindCpuBuffer();
- memcpy(P, refined_verts, sizeof(float) * 3);
- }
-
- void EvalPatchesWithDerivatives(PatchCoord& patch_coord,
- float P[3],
- float dPdu[3],
- float dPdv[3])
- {
- StackAllocatedBuffer<6, 1> vertex_data, derivatives;
- BufferDescriptor vertex_desc(0, 3, 6),
- du_desc(0, 3, 6),
- dv_desc(3, 3, 6);
- SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
- const EVALUATOR *eval_instance =
- OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
- src_desc_,
- vertex_desc,
- du_desc,
- dv_desc,
- device_context_);
- EVALUATOR::EvalPatches(src_data_, src_desc_,
- &vertex_data, vertex_desc,
- &derivatives, du_desc,
- &derivatives, dv_desc,
- patch_coord_buffer.GetNumVertices(),
- &patch_coord_buffer,
- patch_table_, eval_instance, device_context_);
- float *refined_verts = vertex_data.BindCpuBuffer();
- memcpy(P, refined_verts, sizeof(float) * 3);
- if (dPdu != NULL || dPdv != NULL) {
- float *refined_drivatives = derivatives.BindCpuBuffer();
- if (dPdu) {
- memcpy(dPdu, refined_drivatives, sizeof(float) * 3);
- }
- if (dPdv) {
- memcpy(dPdv, refined_drivatives + 3, sizeof(float) * 3);
- }
- }
- }
-
- void EvalPatchVarying(PatchCoord& patch_coord,
- float varying[3]) {
- StackAllocatedBuffer<3, 1> varying_data;
- BufferDescriptor varying_desc(0, 3, 3);
- SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
- EVALUATOR const *eval_instance =
- OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
- src_varying_desc_,
- varying_desc,
- device_context_);
-
- EVALUATOR::EvalPatches(src_varying_data_, src_varying_desc_,
- &varying_data, varying_desc,
- patch_coord_buffer.GetNumVertices(),
- &patch_coord_buffer,
- patch_table_, eval_instance, device_context_);
- float *refined_varying = varying_data.BindCpuBuffer();
- memcpy(varying, refined_varying, sizeof(float) * 3);
- }
-private:
- SRC_VERTEX_BUFFER *src_data_;
- SRC_VERTEX_BUFFER *src_varying_data_;
- PatchCoordBuffer *patch_coords_;
- PATCH_TABLE *patch_table_;
- BufferDescriptor src_desc_;
- BufferDescriptor src_varying_desc_;
- int num_coarse_verts_;
-
- const STENCIL_TABLE *vertex_stencils_;
- const STENCIL_TABLE *varying_stencils_;
-
- EvaluatorCache *evaluator_cache_;
- DEVICE_CONTEXT *device_context_;
-};
-
-} /* namespace */
-
-typedef VolatileEvalOutput<OpenSubdiv::Osd::CpuVertexBuffer,
- OpenSubdiv::Osd::CpuVertexBuffer,
- OpenSubdiv::Far::StencilTable,
- OpenSubdiv::Osd::CpuPatchTable,
- OpenSubdiv::Osd::CpuEvaluator> CpuEvalOutput;
-
-typedef struct OpenSubdiv_EvaluatorDescr {
- CpuEvalOutput *eval_output;
- const PatchMap *patch_map;
- const PatchTable *patch_table;
-} OpenSubdiv_EvaluatorDescr;
-
-OpenSubdiv_EvaluatorDescr *openSubdiv_createEvaluatorDescr(
- OpenSubdiv_TopologyRefinerDescr *topology_refiner,
- int subsurf_level)
-{
- /* TODO(sergey): Look into re-using refiner with GLMesh. */
- TopologyRefiner *refiner = topology_refiner->osd_refiner;
- if(refiner == NULL) {
- /* Happens on bad topology. */
- return NULL;
- }
- /* Apply uniform refinement to the mesh so that we can use the
- * limit evaluation API features.
- */
- TopologyRefiner::UniformOptions options(subsurf_level);
- refiner->RefineUniform(options);
- /* Generate stencil table to update the bi-cubic patches control
- * vertices after they have been re-posed (both for vertex & varying
- * interpolation).
- */
- StencilTableFactory::Options vertex_stencil_options;
- vertex_stencil_options.generateOffsets = true;
- vertex_stencil_options.generateIntermediateLevels = false;
- const StencilTable *vertex_stencils =
- StencilTableFactory::Create(*refiner, vertex_stencil_options);
- StencilTableFactory::Options varying_stencil_options;
- varying_stencil_options.generateOffsets = true;
- varying_stencil_options.generateIntermediateLevels = false;
- varying_stencil_options.interpolationMode =
- StencilTableFactory::INTERPOLATE_VARYING;
- const StencilTable *varying_stencils =
- StencilTableFactory::Create(*refiner, varying_stencil_options);
- /* Generate bi-cubic patch table for the limit surface. */
- PatchTableFactory::Options poptions;
- poptions.SetEndCapType(PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS);
- const PatchTable *patch_table =
- PatchTableFactory::Create(*refiner, poptions);
- /* Append local points stencils. */
- const StencilTable *local_point_stencil_table =
- patch_table->GetLocalPointStencilTable();
- if (local_point_stencil_table != NULL) {
- const StencilTable *table =
- StencilTableFactory::AppendLocalPointStencilTable(
- *refiner,
- vertex_stencils,
- local_point_stencil_table);
- delete vertex_stencils;
- vertex_stencils = table;
- }
- const StencilTable *local_point_varying_stencil_table =
- patch_table->GetLocalPointVaryingStencilTable();
- if (local_point_varying_stencil_table != NULL) {
- const StencilTable *table =
- StencilTableFactory::AppendLocalPointStencilTable(
- *refiner,
- varying_stencils,
- local_point_varying_stencil_table);
- delete varying_stencils;
- varying_stencils = table;
- }
-
- /* Total number of vertices = coarse verts + refined verts + gregory
- * basis verts.
- */
- const int num_total_verts = vertex_stencils->GetNumControlVertices() +
- vertex_stencils->GetNumStencils();
- const int num_coarse_verts = refiner->GetLevel(0).GetNumVertices();
- /* Create OpenSubdiv's CPU side evaluator. */
- CpuEvalOutput *eval_output = new CpuEvalOutput(vertex_stencils,
- varying_stencils,
- num_coarse_verts,
- num_total_verts,
- patch_table);
- OpenSubdiv::Far::PatchMap *patch_map = new PatchMap(*patch_table);
- /* Wrap everything we need into an object which we control from our
- * side.
- */
- OpenSubdiv_EvaluatorDescr *evaluator_descr;
- evaluator_descr = OBJECT_GUARDED_NEW(OpenSubdiv_EvaluatorDescr);
- evaluator_descr->eval_output = eval_output;
- evaluator_descr->patch_map = patch_map;
- evaluator_descr->patch_table = patch_table;
- /* TOOD(sergey): Look into whether we've got duplicated stencils arrays. */
- delete varying_stencils;
- delete vertex_stencils;
- return evaluator_descr;
-}
-
-void openSubdiv_deleteEvaluatorDescr(OpenSubdiv_EvaluatorDescr *evaluator_descr)
-{
- delete evaluator_descr->eval_output;
- delete evaluator_descr->patch_map;
- delete evaluator_descr->patch_table;
- OBJECT_GUARDED_DELETE(evaluator_descr, OpenSubdiv_EvaluatorDescr);
-}
-
-void openSubdiv_setEvaluatorCoarsePositions(
- OpenSubdiv_EvaluatorDescr *evaluator_descr,
- const float *positions,
- int start_vertex_index,
- int num_vertices)
-{
- /* TODO(sergey): Add sanity check on indices. */
- evaluator_descr->eval_output->UpdateData(positions,
- start_vertex_index,
- num_vertices);
-}
-
-void openSubdiv_setEvaluatorVaryingData(
- OpenSubdiv_EvaluatorDescr *evaluator_descr,
- const float *varying_data,
- int start_vertex_index,
- int num_vertices)
-{
- /* TODO(sergey): Add sanity check on indices. */
- evaluator_descr->eval_output->UpdateVaryingData(varying_data,
- start_vertex_index,
- num_vertices);
-}
-
-void openSubdiv_setEvaluatorCoarsePositionsFromBuffer(
- OpenSubdiv_EvaluatorDescr *evaluator_descr,
- const void *buffer,
- int start_offset,
- int stride,
- int start_vertex_index,
- int num_vertices)
-{
- const unsigned char *current_buffer = (unsigned char *)buffer;
- current_buffer += start_offset;
- /* TODO(sergey): Add sanity check on indices. */
- for (int i = 0; i < num_vertices; ++i) {
- const int current_vertex_index = start_vertex_index + i;
- evaluator_descr->eval_output->UpdateData((float *)current_buffer,
- current_vertex_index,
- 1);
- current_buffer += stride;
- }
-}
-
-void openSubdiv_refineEvaluator(OpenSubdiv_EvaluatorDescr *evaluator_descr)
-{
- evaluator_descr->eval_output->Refine();
-}
-
-void openSubdiv_evaluateLimit(OpenSubdiv_EvaluatorDescr *evaluator_descr,
- int osd_face_index,
- float face_u, float face_v,
- float P[3],
- float dPdu[3],
- float dPdv[3])
-{
- assert((face_u >= 0.0f) && (face_u <= 1.0f) && (face_v >= 0.0f) && (face_v <= 1.0f));
- const PatchTable::PatchHandle *handle =
- evaluator_descr->patch_map->FindPatch(osd_face_index, face_u, face_v);
- PatchCoord patch_coord(*handle, face_u, face_v);
- if (dPdu != NULL || dPdv != NULL) {
- evaluator_descr->eval_output->EvalPatchesWithDerivatives(patch_coord,
- P,
- dPdu,
- dPdv);
- }
- else {
- evaluator_descr->eval_output->EvalPatchCoord(patch_coord, P);
- }
-}
-
-void openSubdiv_evaluateVarying(OpenSubdiv_EvaluatorDescr *evaluator_descr,
- int osd_face_index,
- float face_u, float face_v,
- float varying[3])
-{
- assert((face_u >= 0.0f) && (face_u <= 1.0f) && (face_v >= 0.0f) && (face_v <= 1.0f));
- const PatchTable::PatchHandle *handle =
- evaluator_descr->patch_map->FindPatch(osd_face_index, face_u, face_v);
- PatchCoord patch_coord(*handle, face_u, face_v);
- evaluator_descr->eval_output->EvalPatchVarying(patch_coord, varying);
-}
diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.h b/intern/opensubdiv/opensubdiv_evaluator_capi.h
new file mode 100644
index 00000000000..07a55cfd349
--- /dev/null
+++ b/intern/opensubdiv/opensubdiv_evaluator_capi.h
@@ -0,0 +1,117 @@
+// Copyright 2013 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_EVALUATOR_CAPI_H_
+#define OPENSUBDIV_EVALUATOR_CAPI_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct OpenSubdiv_EvaluatorInternal;
+struct OpenSubdiv_TopologyRefiner;
+
+typedef struct OpenSubdiv_Evaluator {
+ // Set coarse positions from a continuous array of coordinates.
+ void (*setCoarsePositions)(struct OpenSubdiv_Evaluator* evaluator,
+ const float* positions,
+ const int start_vertex_index,
+ const int num_vertices);
+ // Set varying data from a continuous array of data.
+ void (*setVaryingData)(struct OpenSubdiv_Evaluator* evaluator,
+ const float* varying_data,
+ const int start_vertex_index, const int num_vertices);
+ // Set face varying data from a continuous array of data.
+ //
+ // TODO(sergey): Find a better name for vertex here. It is not the vertex of
+ // geometry, but a vertex of UV map.
+ void (*setFaceVaryingData)(struct OpenSubdiv_Evaluator* evaluator,
+ const float* face_varying_data,
+ const int start_vertex_index,
+ const int num_vertices);
+
+ // Set coarse vertex position from a continuous memory buffer where
+ // first coordinate starts at offset of `start_offset` and there is `stride`
+ // bytes between adjacent vertex coordinates.
+ void (*setCoarsePositionsFromBuffer)(struct OpenSubdiv_Evaluator* evaluator,
+ const void* buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices);
+ // Set varying data from a continuous memory buffer where
+ // first coordinate starts at offset of `start_offset` and there is `stride`
+ // bytes between adjacent vertex coordinates.
+ void (*setVaryingDataFromBuffer)(struct OpenSubdiv_Evaluator* evaluator,
+ const void* buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices);
+ // Set face varying data from a continuous memory buffer where
+ // first coordinate starts at offset of `start_offset` and there is `stride`
+ // bytes between adjacent vertex coordinates.
+ //
+ // TODO(sergey): Find a better name for vertex here. It is not the vertex of
+ // geometry, but a vertex of UV map.
+ void (*setFaceVaryingDataFromBuffer)(struct OpenSubdiv_Evaluator* evaluator,
+ const void* buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices);
+
+ // Refine after coarse positions update.
+ void (*refine)(struct OpenSubdiv_Evaluator* evaluator);
+
+ // Evaluate given ptex face at given bilinear coordinate.
+ // If derivatives are NULL, they will not be evaluated.
+ void (*evaluateLimit)(struct OpenSubdiv_Evaluator* evaluator,
+ const int ptex_face_index,
+ float face_u, float face_v,
+ float P[3], float dPdu[3], float dPdv[3]);
+
+ // Evaluate varying data at a given bilinear coordinate of given ptex face.
+ void (*evaluateVarying)(struct OpenSubdiv_Evaluator* evaluator,
+ const int ptex_face_index,
+ float face_u, float face_v,
+ float varying[3]);
+
+ // Evaluate face-varying data at a given bilinear coordinate of given
+ // ptex face.
+ void (*evaluateFaceVarying)(struct OpenSubdiv_Evaluator* evaluator,
+ const int ptex_face_index,
+ float face_u, float face_v,
+ float face_varying[2]);
+
+ // Internal storage for the use in this module only.
+ //
+ // This is where actual OpenSubdiv's evaluator is living.
+ struct OpenSubdiv_EvaluatorInternal* internal;
+} OpenSubdiv_Evaluator;
+
+OpenSubdiv_Evaluator* openSubdiv_createEvaluatorFromTopologyRefiner(
+ struct OpenSubdiv_TopologyRefiner* topology_refiner);
+
+void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator* evaluator);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // OPENSUBDIV_EVALUATOR_CAPI_H_
diff --git a/intern/opensubdiv/opensubdiv_gl_mesh.h b/intern/opensubdiv/opensubdiv_gl_mesh.h
deleted file mode 100644
index 1e99fc5bce4..00000000000
--- a/intern/opensubdiv/opensubdiv_gl_mesh.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2018 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Sergey Sharybin.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __OPENSUBDIV_GL_MESH_H__
-#define __OPENSUBDIV_GL_MESH_H__
-
-struct OpenSubdiv_GLMeshDescr;
-struct OpenSubdiv_TopologyRefinerDescr;
-struct OpenSubdiv_GLMeshFVarData;
-
-typedef struct OpenSubdiv_GLMesh {
- int evaluator_type;
- OpenSubdiv_GLMeshDescr *descriptor;
- OpenSubdiv_TopologyRefinerDescr *topology_refiner;
- OpenSubdiv_GLMeshFVarData *fvar_data;
-} OpenSubdiv_GLMesh;
-
-#endif /* __OPENSUBDIV_GL_MESH_H__ */
diff --git a/intern/opensubdiv/opensubdiv_gl_mesh_capi.h b/intern/opensubdiv/opensubdiv_gl_mesh_capi.h
new file mode 100644
index 00000000000..971f6b9dcd3
--- /dev/null
+++ b/intern/opensubdiv/opensubdiv_gl_mesh_capi.h
@@ -0,0 +1,92 @@
+// Copyright 2013 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_CAPI_GL_MESH_CAPI_H_
+#define OPENSUBDIV_CAPI_GL_MESH_CAPI_H_
+
+#include <stdint.h> // for bool
+
+#include "opensubdiv_capi_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct OpenSubdiv_GLMeshInternal;
+
+// Mesh which is displayable in OpenGL context.
+typedef struct OpenSubdiv_GLMesh {
+ //////////////////////////////////////////////////////////////////////////////
+ // Subdivision/topology part.
+
+ // Returns the GL index buffer containing the patch control vertices.
+ unsigned int (*getPatchIndexBuffer)(struct OpenSubdiv_GLMesh* gl_mesh);
+
+ // Bind GL buffer which contains vertices (VBO).
+ // TODO(sergey): Is this a coarse vertices?
+ void (*bindVertexBuffer)(struct OpenSubdiv_GLMesh* gl_mesh);
+
+ // Set coarse positions from a continuous array of coordinates.
+ void (*setCoarsePositions)(struct OpenSubdiv_GLMesh* gl_mesh,
+ const float* positions,
+ const int start_vertex,
+ const int num_vertices);
+ // TODO(sergey): setCoarsePositionsFromBuffer().
+
+ // Refine after coarse positions update.
+ void (*refine)(struct OpenSubdiv_GLMesh* gl_mesh);
+
+ // Synchronize after coarse positions update and refine.
+ void (*synchronize)(struct OpenSubdiv_GLMesh* gl_mesh);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Drawing part.
+
+ // Prepare mesh for display.
+ void (*prepareDraw)(struct OpenSubdiv_GLMesh* gl_mesh,
+ const bool use_osd_glsl,
+ const int active_uv_index);
+
+ // Draw given range of patches.
+ //
+ // If fill_quads is false, then patches are drawn in wireframe.
+ void (*drawPatches)(struct OpenSubdiv_GLMesh *gl_mesh,
+ const bool fill_quads,
+ const int start_patch, const int num_patches);
+
+ // Internal storage for the use in this module only.
+ //
+ // Tease: This contains an actual OpenSubdiv's Mesh object.
+ struct OpenSubdiv_GLMeshInternal* internal;
+} OpenSubdiv_GLMesh;
+
+OpenSubdiv_GLMesh* openSubdiv_createOsdGLMeshFromTopologyRefiner(
+ struct OpenSubdiv_TopologyRefiner* topology_refiner,
+ eOpenSubdivEvaluator evaluator_type);
+
+void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh);
+
+// Global resources needed for GL mesh drawing.
+bool openSubdiv_initGLMeshDrawingResources(void);
+void openSubdiv_deinitGLMeshDrawingResources(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // OPENSUBDIV_CAPI_GL_MESH_CAPI_H_
diff --git a/intern/opensubdiv/opensubdiv_intern.h b/intern/opensubdiv/opensubdiv_intern.h
deleted file mode 100644
index ccb32f9d0ac..00000000000
--- a/intern/opensubdiv/opensubdiv_intern.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2015 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Sergey Sharybin.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __OPENSUBDIV_INTERN_H__
-#define __OPENSUBDIV_INTERN_H__
-
-/* Perform full topology validation when exporting it to OpenSubdiv. */
-#ifdef NDEBUG
-# undef OPENSUBDIV_VALIDATE_TOPOLOGY
-#else
-/* TODO(sergey): Always disabled for now, the check doesn't handle
- * multiple non-manifolds from the OpenSubdiv side currently.
- */
-# undef OPENSUBDIV_VALIDATE_TOPOLOGY
-#endif
-
-/* Currently OpenSubdiv expects topology to be oriented,
- * but sometimes it's handy to disable orientation code
- * to check whether it causes some weird issues by using
- * pre-oriented model.
- */
-#define OPENSUBDIV_ORIENT_TOPOLOGY
-
-#endif /* __OPENSUBDIV_INTERN_H__ */
diff --git a/intern/opensubdiv/opensubdiv_topology_refiner_capi.h b/intern/opensubdiv/opensubdiv_topology_refiner_capi.h
new file mode 100644
index 00000000000..103ccd2c1f9
--- /dev/null
+++ b/intern/opensubdiv/opensubdiv_topology_refiner_capi.h
@@ -0,0 +1,110 @@
+// Copyright 2018 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_TOPOLOGY_REFINER_CAPI_H_
+#define OPENSUBDIV_TOPOLOGY_REFINER_CAPI_H_
+
+#include <stdint.h> // for bool
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct OpenSubdiv_Converter;
+struct OpenSubdiv_TopologyRefinerInternal;
+
+// Those settings don't really belong to OpenSubdiv's topology refiner, but
+// we are keeping track of them on our side of topology refiner. This is to
+// make it possible to ensure we are not trying to abuse same OpenSubdiv's
+// topology refiner with different subdivision levels or with different
+// adaptive settings.
+typedef struct OpenSubdiv_TopologyRefinerSettings {
+ bool is_adaptive;
+ int level;
+} OpenSubdiv_TopologyRefinerSettings;
+
+typedef struct OpenSubdiv_TopologyRefiner {
+ // Query subdivision level the refiner is created for.
+ int (*getSubdivisionLevel)(
+ const struct OpenSubdiv_TopologyRefiner* topology_refiner);
+ bool (*getIsAdaptive)(
+ const struct OpenSubdiv_TopologyRefiner* topology_refiner);
+
+ // Query basic topology information from base level.
+ int (*getNumVertices)(
+ const struct OpenSubdiv_TopologyRefiner* topology_refiner);
+ int (*getNumEdges)(
+ const struct OpenSubdiv_TopologyRefiner* topology_refiner);
+ int (*getNumFaces)(
+ const struct OpenSubdiv_TopologyRefiner* topology_refiner);
+ int (*getNumFaceVertices)(
+ const struct OpenSubdiv_TopologyRefiner* topology_refiner,
+ const int face_index);
+
+ // Ptex face corresponds to OpenSubdiv's internal "patch" and to Blender's
+ // subdivision grid. The rule commes as:
+ // - Triangle face consist of 3 ptex faces, ordered in the order of
+ // face-vertices.
+ // - Quad face consists of a single ptex face.
+ // - N-gons (similar to triangle) consists of N ptex faces, ordered same
+ // way as for triangle.
+ int (*getNumFacePtexFaces)(
+ const struct OpenSubdiv_TopologyRefiner* topology_refiner,
+ const int face_index);
+ int (*getNumPtexFaces)(
+ const struct OpenSubdiv_TopologyRefiner* topology_refiner);
+
+ // Initialize a per-base-face offset measured in ptex face indices.
+ //
+ // Basically, face_ptex_offset[base_face_index] is a total number of ptex
+ // faces created for bases faces [0 .. base_face_index - 1].
+ //
+ // The array must contain at least total number of ptex faces elements.
+ void (*fillFacePtexIndexOffset)(
+ const struct OpenSubdiv_TopologyRefiner* topology_refiner,
+ int* face_ptex_index_offset);
+
+ // Internal storage for the use in this module only.
+ //
+ // Tease: Contains actual OpenSubdiv's refiner and (optionally) some other
+ // data and state needed for an internbal use.
+ struct OpenSubdiv_TopologyRefinerInternal* internal;
+} OpenSubdiv_TopologyRefiner;
+
+OpenSubdiv_TopologyRefiner* openSubdiv_createTopologyRefinerFromConverter(
+ struct OpenSubdiv_Converter* converter,
+ const OpenSubdiv_TopologyRefinerSettings* settings);
+
+void openSubdiv_deleteTopologyRefiner(
+ OpenSubdiv_TopologyRefiner* topology_refiner);
+
+// Compare given topology refiner with converter. Returns truth if topology
+// refiner matches given converter, false otherwise.
+//
+// This allows users to construct converter (which is supposed to be cheap)
+// and compare with existing refiner before going into more computationally
+// complicated parts of subdivision process.
+bool openSubdiv_topologyRefinerCompareWithConverter(
+ const OpenSubdiv_TopologyRefiner* topology_refiner,
+ const OpenSubdiv_Converter* converter);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // OPENSUBDIV_TOPOLOGY_REFINER_CAPI_H_
diff --git a/intern/opensubdiv/opensubdiv_utils_capi.cc b/intern/opensubdiv/opensubdiv_utils_capi.cc
deleted file mode 100644
index 72e3751e6b3..00000000000
--- a/intern/opensubdiv/opensubdiv_utils_capi.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2013 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Sergey Sharybin.
- * Brecht van Lommel
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "opensubdiv_capi.h"
-
-#include <cstring>
-#include <GL/glew.h>
-
-#ifdef _MSC_VER
-# include "iso646.h"
-#endif
-
-#ifdef OPENSUBDIV_HAS_OPENCL
-# include "opensubdiv_device_context_opencl.h"
-#endif /* OPENSUBDIV_HAS_OPENCL */
-
-#ifdef OPENSUBDIV_HAS_CUDA
-# include "opensubdiv_device_context_cuda.h"
-#endif /* OPENSUBDIV_HAS_CUDA */
-
-int openSubdiv_getAvailableEvaluators(void)
-{
- int flags = OPENSUBDIV_EVALUATOR_CPU;
-
-#ifdef OPENSUBDIV_HAS_OPENMP
- flags |= OPENSUBDIV_EVALUATOR_OPENMP;
-#endif /* OPENSUBDIV_HAS_OPENMP */
-
-#ifdef OPENSUBDIV_HAS_OPENCL
- if (CLDeviceContext::HAS_CL_VERSION_1_1()) {
- flags |= OPENSUBDIV_EVALUATOR_OPENCL;
- }
-#endif /* OPENSUBDIV_HAS_OPENCL */
-
-#ifdef OPENSUBDIV_HAS_CUDA
- if (CudaDeviceContext::HAS_CUDA_VERSION_4_0()) {
- flags |= OPENSUBDIV_EVALUATOR_CUDA;
- }
-#endif /* OPENSUBDIV_HAS_OPENCL */
-
-#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
- if (GLEW_VERSION_4_1) {
- flags |= OPENSUBDIV_EVALUATOR_GLSL_TRANSFORM_FEEDBACK;
- }
-#endif /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */
-
-#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
- if (GLEW_VERSION_4_3 || GLEW_ARB_compute_shader) {
- flags |= OPENSUBDIV_EVALUATOR_GLSL_COMPUTE;
- }
-#endif /* OPENSUBDIV_HAS_GLSL_COMPUTE */
-
- return flags;
-}
-
-void openSubdiv_init(void)
-{
- /* Ensure all OpenGL strings are cached. */
- (void)openSubdiv_getAvailableEvaluators();
-}
-
-void openSubdiv_cleanup(void)
-{
- openSubdiv_osdGLDisplayDeinit();
-}
diff --git a/intern/opensubdiv/gpu_shader_opensubdiv_fragment.glsl b/intern/opensubdiv/shader/gpu_shader_opensubdiv_fragment.glsl
index 1e36d549360..1e36d549360 100644
--- a/intern/opensubdiv/gpu_shader_opensubdiv_fragment.glsl
+++ b/intern/opensubdiv/shader/gpu_shader_opensubdiv_fragment.glsl
diff --git a/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl b/intern/opensubdiv/shader/gpu_shader_opensubdiv_geometry.glsl
index b16a5cca733..b16a5cca733 100644
--- a/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl
+++ b/intern/opensubdiv/shader/gpu_shader_opensubdiv_geometry.glsl
diff --git a/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl b/intern/opensubdiv/shader/gpu_shader_opensubdiv_vertex.glsl
index 6fcf5ad20cd..6fcf5ad20cd 100644
--- a/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl
+++ b/intern/opensubdiv/shader/gpu_shader_opensubdiv_vertex.glsl
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index 81b1afa3621..dd5a87a445d 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -40,6 +40,8 @@
#ifdef WITH_OPENSUBDIV
# include "opensubdiv_capi.h"
# include "opensubdiv_converter_capi.h"
+# include "opensubdiv_evaluator_capi.h"
+# include "opensubdiv_topology_refiner_capi.h"
#endif
#include "GPU_glew.h"
@@ -329,7 +331,7 @@ void ccgSubSurf_free(CCGSubSurf *ss)
CCGAllocatorHDL allocator = ss->allocator;
#ifdef WITH_OPENSUBDIV
if (ss->osd_evaluator != NULL) {
- openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator);
+ openSubdiv_deleteEvaluator(ss->osd_evaluator);
}
if (ss->osd_mesh != NULL) {
ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
@@ -341,7 +343,7 @@ void ccgSubSurf_free(CCGSubSurf *ss)
MEM_freeN(ss->osd_coarse_coords);
}
if (ss->osd_topology_refiner != NULL) {
- openSubdiv_deleteTopologyRefinerDescr(ss->osd_topology_refiner);
+ openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
}
#endif
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
index 9df1c9021ef..29e327d8973 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
@@ -236,7 +236,7 @@ struct CCGSubSurf {
* Refiner is created from the modifier stack and used later from the main
* thread to construct GL mesh to avoid threaded access to GL.
*/
- struct OpenSubdiv_TopologyRefinerDescr *osd_topology_refiner; /* Only used at synchronization stage. */
+ struct OpenSubdiv_TopologyRefiner *osd_topology_refiner; /* Only used at synchronization stage. */
/* Denotes whether osd_mesh is invalid now due to topology changes and needs
* to be reconstructed.
*
@@ -249,7 +249,7 @@ struct CCGSubSurf {
/* ** CPU backend. ** */
/* Limit evaluator, used to evaluate CCG. */
- struct OpenSubdiv_EvaluatorDescr *osd_evaluator;
+ struct OpenSubdiv_Evaluator *osd_evaluator;
/* Next PTex face index, used while CCG synchronization
* to fill in PTex index of CCGFace.
*/
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
index 46204898709..98a17ad8009 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
@@ -42,6 +42,9 @@
#include "opensubdiv_capi.h"
#include "opensubdiv_converter_capi.h"
+#include "opensubdiv_evaluator_capi.h"
+#include "opensubdiv_gl_mesh_capi.h"
+#include "opensubdiv_topology_refiner_capi.h"
#include "GPU_glew.h"
#include "GPU_extensions.h"
@@ -131,7 +134,6 @@ static bool compare_ccg_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
{
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner;
OpenSubdiv_Converter converter;
bool result;
if (ss->osd_mesh == NULL && ss->osd_topology_refiner == NULL) {
@@ -140,15 +142,10 @@ static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
/* TODO(sergey): De-duplicate with topology counter at the bottom of
* the file.
*/
- if (ss->osd_topology_refiner != NULL) {
- topology_refiner = ss->osd_topology_refiner;
- }
- else {
- topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
- }
ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
- result = openSubdiv_topologyRefnerCompareConverter(topology_refiner,
- &converter);
+ result = openSubdiv_topologyRefinerCompareWithConverter(
+ ss->osd_topology_refiner,
+ &converter);
ccgSubSurf_converter_free(&converter);
return result;
}
@@ -159,22 +156,13 @@ static bool opensubdiv_is_topology_changed(CCGSubSurf *ss, DerivedMesh *dm)
return true;
}
if (ss->osd_topology_refiner != NULL) {
- int levels = openSubdiv_topologyRefinerGetSubdivLevel(
+ const int levels = ss->osd_topology_refiner->getSubdivisionLevel(
ss->osd_topology_refiner);
BLI_assert(ss->osd_mesh_invalid == true);
if (levels != ss->subdivLevels) {
return true;
}
}
- if (ss->osd_mesh != NULL && ss->osd_mesh_invalid == false) {
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner =
- openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
- int levels = openSubdiv_topologyRefinerGetSubdivLevel(topology_refiner);
- BLI_assert(ss->osd_topology_refiner == NULL);
- if (levels != ss->subdivLevels) {
- return true;
- }
- }
if (ss->skip_grids == false) {
return compare_ccg_derivedmesh_topology(ss, dm) == false;
}
@@ -194,13 +182,13 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm)
/* Reset GPU part. */
ss->osd_mesh_invalid = true;
if (ss->osd_topology_refiner != NULL) {
- openSubdiv_deleteTopologyRefinerDescr(ss->osd_topology_refiner);
+ openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
ss->osd_topology_refiner = NULL;
}
/* Reset CPU side. */
if (ss->osd_evaluator != NULL) {
- openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator);
+ openSubdiv_deleteEvaluator(ss->osd_evaluator);
ss->osd_evaluator = NULL;
}
}
@@ -209,10 +197,10 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm)
static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss)
{
BLI_assert(ss->meshIFC.numLayers == 3);
- openSubdiv_osdGLMeshUpdateVertexBuffer(ss->osd_mesh,
- (float *) ss->osd_coarse_coords,
- 0,
- ss->osd_num_coarse_coords);
+ ss->osd_mesh->setCoarsePositions(ss->osd_mesh,
+ (float *) ss->osd_coarse_coords,
+ 0,
+ ss->osd_num_coarse_coords);
}
bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
@@ -259,9 +247,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner(
ss->osd_topology_refiner,
- compute_type,
- ss->subdivLevels);
- ss->osd_topology_refiner = NULL;
+ compute_type);
if (UNLIKELY(ss->osd_mesh == NULL)) {
/* Most likely compute device is not available. */
@@ -269,13 +255,12 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
}
ccgSubSurf__updateGLMeshCoords(ss);
- openSubdiv_osdGLMeshRefine(ss->osd_mesh);
- openSubdiv_osdGLMeshSynchronize(ss->osd_mesh);
+ ss->osd_mesh->refine(ss->osd_mesh);
+ ss->osd_mesh->synchronize(ss->osd_mesh);
ss->osd_coarse_coords_invalid = false;
glBindVertexArray(ss->osd_vao);
- glBindBuffer(GL_ARRAY_BUFFER,
- openSubdiv_getOsdGLMeshVertexBuffer(ss->osd_mesh));
+ ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
@@ -289,12 +274,12 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
}
else if (ss->osd_coarse_coords_invalid) {
ccgSubSurf__updateGLMeshCoords(ss);
- openSubdiv_osdGLMeshRefine(ss->osd_mesh);
- openSubdiv_osdGLMeshSynchronize(ss->osd_mesh);
+ ss->osd_mesh->refine(ss->osd_mesh);
+ ss->osd_mesh->synchronize(ss->osd_mesh);
ss->osd_coarse_coords_invalid = false;
}
- openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl, active_uv_index);
+ ss->osd_mesh->prepareDraw(ss->osd_mesh, use_osd_glsl, active_uv_index);
return true;
}
@@ -305,12 +290,12 @@ void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads,
if (LIKELY(ss->osd_mesh != NULL)) {
glBindVertexArray(ss->osd_vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
- openSubdiv_getOsdGLMeshPatchIndexBuffer(ss->osd_mesh));
+ ss->osd_mesh->getPatchIndexBuffer(ss->osd_mesh));
- openSubdiv_osdGLMeshBindVertexBuffer(ss->osd_mesh);
+ ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
glBindVertexArray(ss->osd_vao);
- openSubdiv_osdGLMeshDisplay(ss->osd_mesh, fill_quads,
- start_partition, num_partitions);
+ ss->osd_mesh->drawPatches(ss->osd_mesh, fill_quads,
+ start_partition, num_partitions);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@@ -319,33 +304,21 @@ void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads,
int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss)
{
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner;
if (ss->osd_topology_refiner != NULL) {
- topology_refiner = ss->osd_topology_refiner;
- }
- else if (ss->osd_mesh != NULL) {
- topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
- }
- else {
- return 0;
+ return ss->osd_topology_refiner->getNumFaces(
+ ss->osd_topology_refiner);
}
- return openSubdiv_topologyRefinerGetNumFaces(topology_refiner);
+ return 0;
}
/* Get number of vertices in base faces in a particular GL mesh. */
int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face)
{
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner;
if (ss->osd_topology_refiner != NULL) {
- topology_refiner = ss->osd_topology_refiner;
- }
- else if (ss->osd_mesh != NULL) {
- topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
- }
- else {
- return 0;
+ return ss->osd_topology_refiner->getNumFaceVertices(
+ ss->osd_topology_refiner, face);
}
- return openSubdiv_topologyRefinerGetNumFaceVerts(topology_refiner, face);
+ return 0;
}
void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids)
@@ -453,17 +426,21 @@ void ccgSubSurf_evaluatorFVarUV(CCGSubSurf *ss,
static bool opensubdiv_createEvaluator(CCGSubSurf *ss)
{
OpenSubdiv_Converter converter;
- OpenSubdiv_TopologyRefinerDescr *topology_refiner;
+ OpenSubdiv_TopologyRefiner *topology_refiner;
if (ss->fMap->numEntries == 0) {
/* OpenSubdiv doesn't support meshes without faces. */
return false;
}
ccgSubSurf_converter_setup_from_ccg(ss, &converter);
- topology_refiner = openSubdiv_createTopologyRefinerDescr(&converter);
+ OpenSubdiv_TopologyRefinerSettings settings;
+ settings.level = ss->subdivLevels;
+ settings.is_adaptive = false;
+ topology_refiner =
+ openSubdiv_createTopologyRefinerFromConverter(
+ &converter, &settings);
ccgSubSurf_converter_free(&converter);
ss->osd_evaluator =
- openSubdiv_createEvaluatorDescr(topology_refiner,
- ss->subdivLevels);
+ openSubdiv_createEvaluatorFromTopologyRefiner(topology_refiner);
if (ss->osd_evaluator == NULL) {
BLI_assert(!"OpenSubdiv initialization failed, should not happen.");
return false;
@@ -519,11 +496,11 @@ static void opensubdiv_updateEvaluatorCoarsePositions(CCGSubSurf *ss)
}
}
- openSubdiv_setEvaluatorCoarsePositions(ss->osd_evaluator,
- (float *)positions,
- 0,
- num_basis_verts);
- openSubdiv_refineEvaluator(ss->osd_evaluator);
+ ss->osd_evaluator->setCoarsePositions(ss->osd_evaluator,
+ (float *)positions,
+ 0,
+ num_basis_verts);
+ ss->osd_evaluator->refine(ss->osd_evaluator);
MEM_freeN(positions);
}
@@ -558,11 +535,12 @@ static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss,
ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v);
/* TODO(sergey): Need proper port. */
- openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index,
- face_u, face_v,
- P,
- do_normals ? dPdu : NULL,
- do_normals ? dPdv : NULL);
+ ss->osd_evaluator->evaluateLimit(
+ ss->osd_evaluator, osd_face_index,
+ face_u, face_v,
+ P,
+ do_normals ? dPdu : NULL,
+ do_normals ? dPdv : NULL);
OSD_LOG("face=%d, corner=%d, grid_u=%f, grid_v=%f, face_u=%f, face_v=%f, P=(%f, %f, %f)\n",
osd_face_index, S, grid_u, grid_v, face_u, face_v, P[0], P[1], P[2]);
@@ -636,7 +614,11 @@ static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss,
* let's just re-evaluate for simplicity.
*/
/* TODO(sergey): Need proper port. */
- openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index, u, v, P, dPdu, dPdv);
+ ss->osd_evaluator->evaluateLimit(
+ ss->osd_evaluator,
+ osd_face_index,
+ u, v,
+ P, dPdu, dPdv);
VertDataCopy(co, P, ss);
if (do_normals) {
cross_v3_v3v3(no, dPdu, dPdv);
@@ -700,7 +682,11 @@ static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss,
float P[3], dPdu[3], dPdv[3];
/* TODO(sergey): Need proper port. */
- openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index + S, u, v, P, dPdu, dPdv);
+ ss->osd_evaluator->evaluateLimit(
+ ss->osd_evaluator,
+ osd_face_index + S,
+ u, v,
+ P, dPdu, dPdv);
OSD_LOG("face=%d, corner=%d, u=%f, v=%f, P=(%f, %f, %f)\n",
osd_face_index + S, S, u, v, P[0], P[1], P[2]);
@@ -838,7 +824,12 @@ void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, DerivedMesh *dm)
OpenSubdiv_Converter converter;
ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
/* TODO(sergey): Remove possibly previously allocated refiner. */
- ss->osd_topology_refiner = openSubdiv_createTopologyRefinerDescr(&converter);
+ OpenSubdiv_TopologyRefinerSettings settings;
+ settings.level = ss->subdivLevels;
+ settings.is_adaptive = false;
+ ss->osd_topology_refiner =
+ openSubdiv_createTopologyRefinerFromConverter(
+ &converter, &settings);
ccgSubSurf_converter_free(&converter);
}
}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
index 8c1ba0c3782..219d77a6c52 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
@@ -432,35 +432,35 @@ void ccgSubSurf_converter_setup_from_derivedmesh(
{
ConvDMStorage *user_data;
- converter->get_scheme_type = conv_dm_get_type;
+ converter->getSchemeType = conv_dm_get_type;
- converter->get_fvar_linear_interpolation =
+ converter->getFVarLinearInterpolation =
conv_dm_get_fvar_linear_interpolation;
- converter->get_num_faces = conv_dm_get_num_faces;
- converter->get_num_edges = conv_dm_get_num_edges;
- converter->get_num_verts = conv_dm_get_num_verts;
+ converter->getNumFaces = conv_dm_get_num_faces;
+ converter->getNumEdges = conv_dm_get_num_edges;
+ converter->getNumVertices = conv_dm_get_num_verts;
- converter->get_num_face_verts = conv_dm_get_num_face_verts;
- converter->get_face_verts = conv_dm_get_face_verts;
- converter->get_face_edges = conv_dm_get_face_edges;
+ converter->getNumFaceVertices = conv_dm_get_num_face_verts;
+ converter->getFaceVertices = conv_dm_get_face_verts;
+ converter->getFaceEdges = conv_dm_get_face_edges;
- converter->get_edge_verts = conv_dm_get_edge_verts;
- converter->get_num_edge_faces = conv_dm_get_num_edge_faces;
- converter->get_edge_faces = conv_dm_get_edge_faces;
- converter->get_edge_sharpness = conv_dm_get_edge_sharpness;
+ converter->getEdgeVertices = conv_dm_get_edge_verts;
+ converter->getNumEdgeFaces = conv_dm_get_num_edge_faces;
+ converter->getEdgeFaces = conv_dm_get_edge_faces;
+ converter->getEdgeSharpness = conv_dm_get_edge_sharpness;
- converter->get_num_vert_edges = conv_dm_get_num_vert_edges;
- converter->get_vert_edges = conv_dm_get_vert_edges;
- converter->get_num_vert_faces = conv_dm_get_num_vert_faces;
- converter->get_vert_faces = conv_dm_get_vert_faces;
+ converter->getNumVertexEdges = conv_dm_get_num_vert_edges;
+ converter->getVertexEdges = conv_dm_get_vert_edges;
+ converter->getNumVertexFaces = conv_dm_get_num_vert_faces;
+ converter->getVertexFaces = conv_dm_get_vert_faces;
- converter->get_num_uv_layers = conv_dm_get_num_uv_layers;
- converter->precalc_uv_layer = conv_dm_precalc_uv_layer;
- converter->finish_uv_layer = conv_dm_finish_uv_layer;
- converter->get_num_uvs = conv_dm_get_num_uvs;
- converter->get_uvs = conv_dm_get_uvs;
- converter->get_face_corner_uv_index = conv_dm_get_face_corner_uv_index;
+ converter->getNumUVLayers = conv_dm_get_num_uv_layers;
+ converter->precalcUVLayer = conv_dm_precalc_uv_layer;
+ converter->finishUVLayer = conv_dm_finish_uv_layer;
+ converter->getNumUVCoordinates = conv_dm_get_num_uvs;
+ converter->getUVCoordinates = conv_dm_get_uvs;
+ converter->getFaceCornerUVIndex = conv_dm_get_face_corner_uv_index;
user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__);
user_data->ss = ss;
@@ -476,7 +476,7 @@ void ccgSubSurf_converter_setup_from_derivedmesh(
user_data->uvs = NULL;
user_data->face_uvs = NULL;
- converter->free_user_data = conv_dm_free_user_data;
+ converter->freeUserData = conv_dm_free_user_data;
converter->user_data = user_data;
#ifdef USE_MESH_ELEMENT_MAPPING
@@ -717,45 +717,45 @@ static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED(
void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss,
OpenSubdiv_Converter *converter)
{
- converter->get_scheme_type = conv_ccg_get_bilinear_type;
+ converter->getSchemeType = conv_ccg_get_bilinear_type;
- converter->get_fvar_linear_interpolation =
+ converter->getFVarLinearInterpolation =
conv_ccg_get_fvar_linear_interpolation;
- converter->get_num_faces = conv_ccg_get_num_faces;
- converter->get_num_edges = conv_ccg_get_num_edges;
- converter->get_num_verts = conv_ccg_get_num_verts;
+ converter->getNumFaces = conv_ccg_get_num_faces;
+ converter->getNumEdges = conv_ccg_get_num_edges;
+ converter->getNumVertices = conv_ccg_get_num_verts;
- converter->get_num_face_verts = conv_ccg_get_num_face_verts;
- converter->get_face_verts = conv_ccg_get_face_verts;
- converter->get_face_edges = conv_ccg_get_face_edges;
+ converter->getNumFaceVertices = conv_ccg_get_num_face_verts;
+ converter->getFaceVertices = conv_ccg_get_face_verts;
+ converter->getFaceEdges = conv_ccg_get_face_edges;
- converter->get_edge_verts = conv_ccg_get_edge_verts;
- converter->get_num_edge_faces = conv_ccg_get_num_edge_faces;
- converter->get_edge_faces = conv_ccg_get_edge_faces;
- converter->get_edge_sharpness = conv_ccg_get_edge_sharpness;
+ converter->getEdgeVertices = conv_ccg_get_edge_verts;
+ converter->getNumEdgeFaces = conv_ccg_get_num_edge_faces;
+ converter->getEdgeFaces = conv_ccg_get_edge_faces;
+ converter->getEdgeSharpness = conv_ccg_get_edge_sharpness;
- converter->get_num_vert_edges = conv_ccg_get_num_vert_edges;
- converter->get_vert_edges = conv_ccg_get_vert_edges;
- converter->get_num_vert_faces = conv_ccg_get_num_vert_faces;
- converter->get_vert_faces = conv_ccg_get_vert_faces;
+ converter->getNumVertexEdges = conv_ccg_get_num_vert_edges;
+ converter->getVertexEdges = conv_ccg_get_vert_edges;
+ converter->getNumVertexFaces = conv_ccg_get_num_vert_faces;
+ converter->getVertexFaces = conv_ccg_get_vert_faces;
- converter->get_num_uv_layers = conv_ccg_get_num_uv_layers;
- converter->precalc_uv_layer = conv_ccg_precalc_uv_layer;
- converter->finish_uv_layer = conv_ccg_finish_uv_layer;
- converter->get_num_uvs = conv_ccg_get_num_uvs;
- converter->get_uvs = conv_ccg_get_uvs;
- converter->get_face_corner_uv_index = conv_ccg_get_face_corner_uv_index;
+ converter->getNumUVLayers = conv_ccg_get_num_uv_layers;
+ converter->precalcUVLayer = conv_ccg_precalc_uv_layer;
+ converter->finishUVLayer = conv_ccg_finish_uv_layer;
+ converter->getNumUVCoordinates = conv_ccg_get_num_uvs;
+ converter->getUVCoordinates = conv_ccg_get_uvs;
+ converter->getFaceCornerUVIndex = conv_ccg_get_face_corner_uv_index;
- converter->free_user_data = NULL;
+ converter->freeUserData = NULL;
converter->user_data = ss;
}
void ccgSubSurf_converter_free(
struct OpenSubdiv_Converter *converter)
{
- if (converter->free_user_data) {
- converter->free_user_data(converter);
+ if (converter->freeUserData) {
+ converter->freeUserData(converter);
}
}