OpenSubdiv: Better approximation of vertex normals
[blender.git] / intern / opensubdiv / opensubdiv_capi.cc
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2013 Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Sergey Sharybin.
22  *                 Brecht van Lommel
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include "opensubdiv_capi.h"
28
29 #ifdef _MSC_VER
30 #  include "iso646.h"
31 #endif
32
33 #include <GL/glew.h>
34
35 #include <opensubdiv/osd/glMesh.h>
36
37 /* CPU Backend */
38 #include <opensubdiv/osd/cpuGLVertexBuffer.h>
39 #include <opensubdiv/osd/cpuEvaluator.h>
40
41 #ifdef OPENSUBDIV_HAS_OPENMP
42 #  include <opensubdiv/osd/ompEvaluator.h>
43 #endif  /* OPENSUBDIV_HAS_OPENMP */
44
45 #ifdef OPENSUBDIV_HAS_OPENCL
46 #  include <opensubdiv/osd/clGLVertexBuffer.h>
47 #  include <opensubdiv/osd/clEvaluator.h>
48 #  include "opensubdiv_device_context_opencl.h"
49 #endif  /* OPENSUBDIV_HAS_OPENCL */
50
51 #ifdef OPENSUBDIV_HAS_CUDA
52 #  include <opensubdiv/osd/cudaGLVertexBuffer.h>
53 #  include <opensubdiv/osd/cudaEvaluator.h>
54 #  include "opensubdiv_device_context_cuda.h"
55 #endif  /* OPENSUBDIV_HAS_CUDA */
56
57 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
58 #  include <opensubdiv/osd/glXFBEvaluator.h>
59 #  include <opensubdiv/osd/glVertexBuffer.h>
60 #endif  /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */
61
62 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
63 #  include <opensubdiv/osd/glComputeEvaluator.h>
64 #  include <opensubdiv/osd/glVertexBuffer.h>
65 #endif  /* OPENSUBDIV_HAS_GLSL_COMPUTE */
66
67 #include <opensubdiv/osd/glPatchTable.h>
68 #include <opensubdiv/far/stencilTable.h>
69
70 #include "opensubdiv_intern.h"
71 #include "opensubdiv_partitioned.h"
72
73 #include "MEM_guardedalloc.h"
74
75 /* **************** Types declaration **************** */
76
77 using OpenSubdiv::Osd::GLMeshInterface;
78 using OpenSubdiv::Osd::Mesh;
79 using OpenSubdiv::Osd::MeshBitset;
80 using OpenSubdiv::Far::StencilTable;
81 using OpenSubdiv::Osd::GLPatchTable;
82
83 using OpenSubdiv::Osd::PartitionedMesh;
84
85 /* CPU backend */
86 using OpenSubdiv::Osd::CpuGLVertexBuffer;
87 using OpenSubdiv::Osd::CpuEvaluator;
88 typedef PartitionedMesh<CpuGLVertexBuffer,
89                         StencilTable,
90                         CpuEvaluator,
91                         GLPatchTable> OsdCpuMesh;
92
93 #ifdef OPENSUBDIV_HAS_OPENMP
94 using OpenSubdiv::Osd::OmpEvaluator;
95 typedef PartitionedMesh<CpuGLVertexBuffer,
96                         StencilTable,
97                         OmpEvaluator,
98                         GLPatchTable> OsdOmpMesh;
99 #endif  /* OPENSUBDIV_HAS_OPENMP */
100
101 #ifdef OPENSUBDIV_HAS_OPENCL
102 using OpenSubdiv::Osd::CLEvaluator;
103 using OpenSubdiv::Osd::CLGLVertexBuffer;
104 using OpenSubdiv::Osd::CLStencilTable;
105 /* TODO(sergey): Use CLDeviceCOntext similar to OSD examples? */
106 typedef PartitionedMesh<CLGLVertexBuffer,
107                         CLStencilTable,
108                         CLEvaluator,
109                         GLPatchTable,
110                         CLDeviceContext> OsdCLMesh;
111 static CLDeviceContext g_clDeviceContext;
112 #endif  /* OPENSUBDIV_HAS_OPENCL */
113
114 #ifdef OPENSUBDIV_HAS_CUDA
115 using OpenSubdiv::Osd::CudaEvaluator;
116 using OpenSubdiv::Osd::CudaGLVertexBuffer;
117 using OpenSubdiv::Osd::CudaStencilTable;
118 typedef PartitionedMesh<CudaGLVertexBuffer,
119                         CudaStencilTable,
120                         CudaEvaluator,
121                         GLPatchTable> OsdCudaMesh;
122 static CudaDeviceContext g_cudaDeviceContext;
123 #endif  /* OPENSUBDIV_HAS_CUDA */
124
125 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
126 using OpenSubdiv::Osd::GLXFBEvaluator;
127 using OpenSubdiv::Osd::GLStencilTableTBO;
128 using OpenSubdiv::Osd::GLVertexBuffer;
129 typedef PartitionedMesh<GLVertexBuffer,
130                         GLStencilTableTBO,
131                         GLXFBEvaluator,
132                         GLPatchTable> OsdGLSLTransformFeedbackMesh;
133 #endif  /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */
134
135 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
136 using OpenSubdiv::Osd::GLComputeEvaluator;
137 using OpenSubdiv::Osd::GLStencilTableSSBO;
138 using OpenSubdiv::Osd::GLVertexBuffer;
139 typedef PartitionedMesh<GLVertexBuffer,
140                         GLStencilTableSSBO,
141                         GLComputeEvaluator,
142                         GLPatchTable> OsdGLSLComputeMesh;
143 #endif
144
145 struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
146         OpenSubdiv_TopologyRefinerDescr *topology_refiner,
147         int evaluator_type,
148         int level,
149         int /*subdivide_uvs*/)
150 {
151         using OpenSubdiv::Far::TopologyRefiner;
152
153         MeshBitset bits;
154         /* TODO(sergey): Adaptive subdivisions are not currently
155          * possible because of the lack of tessellation shader.
156          */
157         bits.set(OpenSubdiv::Osd::MeshAdaptive, 0);
158         bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, 0);
159         bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, 1);
160         bits.set(OpenSubdiv::Osd::MeshFVarData, 1);
161         bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, 1);
162         // bits.set(Osd::MeshEndCapGregoryBasis, 1);
163         // bits.set(Osd::MeshEndCapLegacyGregory, 1);
164
165         const int num_vertex_elements = 3;
166         const int num_varying_elements = 3;
167
168         GLMeshInterface *mesh = NULL;
169         TopologyRefiner *refiner = (TopologyRefiner*)topology_refiner;
170
171         switch(evaluator_type) {
172 #define CHECK_EVALUATOR_TYPE(type, class) \
173                 case OPENSUBDIV_EVALUATOR_ ## type: \
174                         mesh = new class(refiner, \
175                                          num_vertex_elements, \
176                                          num_varying_elements, \
177                                          level, \
178                                          bits); \
179                         break;
180
181                 CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh)
182
183 #ifdef OPENSUBDIV_HAS_OPENMP
184                 CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh)
185 #endif
186
187 #ifdef OPENSUBDIV_HAS_OPENCL
188                 CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh)
189 #endif
190
191 #ifdef OPENSUBDIV_HAS_CUDA
192                 CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh)
193 #endif
194
195 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
196                 CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK,
197                                      OsdGLSLTransformFeedbackMesh)
198 #endif
199
200 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
201                 CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh)
202 #endif
203
204 #undef CHECK_EVALUATOR_TYPE
205         }
206
207         if (mesh == NULL) {
208                 return NULL;
209         }
210
211         OpenSubdiv_GLMesh *gl_mesh =
212                 (OpenSubdiv_GLMesh *) OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh);
213         gl_mesh->evaluator_type = evaluator_type;
214         gl_mesh->descriptor = (OpenSubdiv_GLMeshDescr *) mesh;
215         gl_mesh->topology_refiner = (OpenSubdiv_TopologyRefinerDescr*)refiner;
216
217         return gl_mesh;
218 }
219
220 void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh)
221 {
222         switch (gl_mesh->evaluator_type) {
223 #define CHECK_EVALUATOR_TYPE(type, class) \
224                 case OPENSUBDIV_EVALUATOR_ ## type: \
225                         delete (class *) gl_mesh->descriptor; \
226                         break;
227
228                 CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh)
229
230 #ifdef OPENSUBDIV_HAS_OPENMP
231                 CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh)
232 #endif
233
234 #ifdef OPENSUBDIV_HAS_OPENCL
235                 CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh)
236 #endif
237
238 #ifdef OPENSUBDIV_HAS_CUDA
239                 CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh)
240 #endif
241
242 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
243                 CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK,
244                                      OsdGLSLTransformFeedbackMesh)
245 #endif
246
247 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
248                 CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh)
249 #endif
250
251 #undef CHECK_EVALUATOR_TYPE
252         }
253
254         OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh);
255 }
256
257 unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer(struct OpenSubdiv_GLMesh *gl_mesh)
258 {
259         return ((GLMeshInterface *)gl_mesh->descriptor)->GetPatchTable()->GetPatchIndexBuffer();
260 }
261
262 unsigned int openSubdiv_getOsdGLMeshVertexBuffer(struct OpenSubdiv_GLMesh *gl_mesh)
263 {
264         return ((GLMeshInterface *)gl_mesh->descriptor)->BindVertexBuffer();
265 }
266
267 void openSubdiv_osdGLMeshUpdateVertexBuffer(struct OpenSubdiv_GLMesh *gl_mesh,
268                                             const float *vertex_data,
269                                             int start_vertex,
270                                             int num_verts)
271 {
272         ((GLMeshInterface *)gl_mesh->descriptor)->UpdateVertexBuffer(vertex_data,
273                                                                      start_vertex,
274                                                                      num_verts);
275 }
276
277 void openSubdiv_osdGLMeshRefine(struct OpenSubdiv_GLMesh *gl_mesh)
278 {
279         ((GLMeshInterface *)gl_mesh->descriptor)->Refine();
280 }
281
282 void openSubdiv_osdGLMeshSynchronize(struct OpenSubdiv_GLMesh *gl_mesh)
283 {
284         ((GLMeshInterface *)gl_mesh->descriptor)->Synchronize();
285 }
286
287 void openSubdiv_osdGLMeshBindVertexBuffer(OpenSubdiv_GLMesh *gl_mesh)
288 {
289         ((GLMeshInterface *)gl_mesh->descriptor)->BindVertexBuffer();
290 }
291
292 const struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_getGLMeshTopologyRefiner(
293         OpenSubdiv_GLMesh *gl_mesh)
294 {
295         return gl_mesh->topology_refiner;
296 }
297
298 int openSubdiv_supportGPUDisplay(void)
299 {
300         return GL_EXT_geometry_shader4 &&
301                GL_ARB_gpu_shader5 &&
302                glProgramParameteriEXT;
303 }