OpenSubdiv: Initial work to support UV maps in textured OSD viewport
[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 <stdlib.h>
34 #include <GL/glew.h>
35
36 #include <opensubdiv/osd/glMesh.h>
37
38 /* CPU Backend */
39 #include <opensubdiv/osd/cpuGLVertexBuffer.h>
40 #include <opensubdiv/osd/cpuEvaluator.h>
41
42 #ifdef OPENSUBDIV_HAS_OPENMP
43 #  include <opensubdiv/osd/ompEvaluator.h>
44 #endif  /* OPENSUBDIV_HAS_OPENMP */
45
46 #ifdef OPENSUBDIV_HAS_OPENCL
47 #  include <opensubdiv/osd/clGLVertexBuffer.h>
48 #  include <opensubdiv/osd/clEvaluator.h>
49 #  include "opensubdiv_device_context_opencl.h"
50 #endif  /* OPENSUBDIV_HAS_OPENCL */
51
52 #ifdef OPENSUBDIV_HAS_CUDA
53 #  include <opensubdiv/osd/cudaGLVertexBuffer.h>
54 #  include <opensubdiv/osd/cudaEvaluator.h>
55 #  include "opensubdiv_device_context_cuda.h"
56 #endif  /* OPENSUBDIV_HAS_CUDA */
57
58 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
59 #  include <opensubdiv/osd/glXFBEvaluator.h>
60 #  include <opensubdiv/osd/glVertexBuffer.h>
61 #endif  /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */
62
63 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
64 #  include <opensubdiv/osd/glComputeEvaluator.h>
65 #  include <opensubdiv/osd/glVertexBuffer.h>
66 #endif  /* OPENSUBDIV_HAS_GLSL_COMPUTE */
67
68 #include <opensubdiv/osd/glPatchTable.h>
69 #include <opensubdiv/far/stencilTable.h>
70 #include <opensubdiv/far/primvarRefiner.h>
71
72 #include "opensubdiv_intern.h"
73 #include "opensubdiv_topology_refiner.h"
74
75 #include "MEM_guardedalloc.h"
76
77 /* **************** Types declaration **************** */
78
79 using OpenSubdiv::Osd::GLMeshInterface;
80 using OpenSubdiv::Osd::Mesh;
81 using OpenSubdiv::Osd::MeshBitset;
82 using OpenSubdiv::Far::StencilTable;
83 using OpenSubdiv::Osd::GLPatchTable;
84
85 using OpenSubdiv::Osd::Mesh;
86
87 /* CPU backend */
88 using OpenSubdiv::Osd::CpuGLVertexBuffer;
89 using OpenSubdiv::Osd::CpuEvaluator;
90 typedef Mesh<CpuGLVertexBuffer,
91              StencilTable,
92              CpuEvaluator,
93              GLPatchTable> OsdCpuMesh;
94
95 #ifdef OPENSUBDIV_HAS_OPENMP
96 using OpenSubdiv::Osd::OmpEvaluator;
97 typedef Mesh<CpuGLVertexBuffer,
98              StencilTable,
99              OmpEvaluator,
100              GLPatchTable> OsdOmpMesh;
101 #endif  /* OPENSUBDIV_HAS_OPENMP */
102
103 #ifdef OPENSUBDIV_HAS_OPENCL
104 using OpenSubdiv::Osd::CLEvaluator;
105 using OpenSubdiv::Osd::CLGLVertexBuffer;
106 using OpenSubdiv::Osd::CLStencilTable;
107 /* TODO(sergey): Use CLDeviceCOntext similar to OSD examples? */
108 typedef Mesh<CLGLVertexBuffer,
109              CLStencilTable,
110              CLEvaluator,
111              GLPatchTable,
112              CLDeviceContext> OsdCLMesh;
113 static CLDeviceContext g_clDeviceContext;
114 #endif  /* OPENSUBDIV_HAS_OPENCL */
115
116 #ifdef OPENSUBDIV_HAS_CUDA
117 using OpenSubdiv::Osd::CudaEvaluator;
118 using OpenSubdiv::Osd::CudaGLVertexBuffer;
119 using OpenSubdiv::Osd::CudaStencilTable;
120 typedef Mesh<CudaGLVertexBuffer,
121              CudaStencilTable,
122              CudaEvaluator,
123              GLPatchTable> OsdCudaMesh;
124 static CudaDeviceContext g_cudaDeviceContext;
125 #endif  /* OPENSUBDIV_HAS_CUDA */
126
127 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
128 using OpenSubdiv::Osd::GLXFBEvaluator;
129 using OpenSubdiv::Osd::GLStencilTableTBO;
130 using OpenSubdiv::Osd::GLVertexBuffer;
131 typedef Mesh<GLVertexBuffer,
132              GLStencilTableTBO,
133              GLXFBEvaluator,
134              GLPatchTable> OsdGLSLTransformFeedbackMesh;
135 #endif  /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */
136
137 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
138 using OpenSubdiv::Osd::GLComputeEvaluator;
139 using OpenSubdiv::Osd::GLStencilTableSSBO;
140 using OpenSubdiv::Osd::GLVertexBuffer;
141 typedef Mesh<GLVertexBuffer,
142              GLStencilTableSSBO,
143              GLComputeEvaluator,
144              GLPatchTable> OsdGLSLComputeMesh;
145 #endif
146
147 namespace {
148
149 struct FVarVertex {
150         float u, v;
151         void Clear() {
152                 u = v = 0.0f;
153         }
154         void AddWithWeight(FVarVertex const & src, float weight) {
155                 u += weight * src.u;
156                 v += weight * src.v;
157         }
158 };
159
160 static void interpolate_fvar_data(OpenSubdiv::Far::TopologyRefiner& refiner,
161                                   const std::vector<float> uvs,
162                                   std::vector<float> &fvar_data) {
163         /* TODO(sergey): Support all FVar channels. */
164         const int channel = 0;
165         /* TODO(sergey): Make it somehow more generic way. */
166         const int fvar_width = 2;
167
168         int max_level = refiner.GetMaxLevel(),
169             num_values_max = refiner.GetLevel(max_level).GetNumFVarValues(channel),
170             num_values_total = refiner.GetNumFVarValuesTotal(channel);
171         if (num_values_total <= 0) {
172                 return;
173         }
174         OpenSubdiv::Far::PrimvarRefiner primvarRefiner(refiner);
175         if (refiner.IsUniform()) {
176                 /* For uniform we only keep the highest level of refinement. */
177                 fvar_data.resize(num_values_max * fvar_width);
178                 std::vector<FVarVertex> buffer(num_values_total - num_values_max);
179                 FVarVertex *src = &buffer[0];
180                 memcpy(src, &uvs[0], uvs.size() * sizeof(float));
181                 /* Defer the last level to treat separately with its alternate
182                  * destination.
183                  */
184                 for (int level = 1; level < max_level; ++level) {
185                         FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);
186                         primvarRefiner.InterpolateFaceVarying(level, src, dst, channel);
187                         src = dst;
188                 }
189                 FVarVertex *dst = reinterpret_cast<FVarVertex *>(&fvar_data[0]);
190                 primvarRefiner.InterpolateFaceVarying(max_level, src, dst, channel);
191         } else {
192                 /* For adaptive we keep all levels. */
193                 fvar_data.resize(num_values_total * fvar_width);
194                 FVarVertex *src = reinterpret_cast<FVarVertex *>(&fvar_data[0]);
195                 memcpy(src, &uvs[0], uvs.size() * sizeof(float));
196                 for (int level = 1; level <= max_level; ++level) {
197                         FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);
198                         primvarRefiner.InterpolateFaceVarying(level, src, dst, channel);
199                         src = dst;
200         }
201     }
202 }
203
204 }  // namespace
205
206 struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
207         OpenSubdiv_TopologyRefinerDescr *topology_refiner,
208         int evaluator_type,
209         int level)
210 {
211         using OpenSubdiv::Far::TopologyRefiner;
212
213         MeshBitset bits;
214         /* TODO(sergey): Adaptive subdivisions are not currently
215          * possible because of the lack of tessellation shader.
216          */
217         bits.set(OpenSubdiv::Osd::MeshAdaptive, 0);
218         bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, 0);
219         bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, 1);
220         bits.set(OpenSubdiv::Osd::MeshFVarData, 1);
221         bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, 1);
222
223         const int num_vertex_elements = 3;
224         const int num_varying_elements = 3;
225
226         GLMeshInterface *mesh = NULL;
227         TopologyRefiner *refiner = topology_refiner->osd_refiner;
228
229         switch(evaluator_type) {
230 #define CHECK_EVALUATOR_TYPE(type, class) \
231                 case OPENSUBDIV_EVALUATOR_ ## type: \
232                         mesh = new class(refiner, \
233                                          num_vertex_elements, \
234                                          num_varying_elements, \
235                                          level, \
236                                          bits); \
237                         break;
238
239                 CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh)
240
241 #ifdef OPENSUBDIV_HAS_OPENMP
242                 CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh)
243 #endif
244
245 #ifdef OPENSUBDIV_HAS_OPENCL
246                 CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh)
247 #endif
248
249 #ifdef OPENSUBDIV_HAS_CUDA
250                 CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh)
251 #endif
252
253 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
254                 CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK,
255                                      OsdGLSLTransformFeedbackMesh)
256 #endif
257
258 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
259                 CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh)
260 #endif
261
262 #undef CHECK_EVALUATOR_TYPE
263         }
264
265         if (mesh == NULL) {
266                 return NULL;
267         }
268
269         OpenSubdiv_GLMesh *gl_mesh =
270                 (OpenSubdiv_GLMesh *) OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh);
271         gl_mesh->evaluator_type = evaluator_type;
272         gl_mesh->descriptor = (OpenSubdiv_GLMeshDescr *) mesh;
273         gl_mesh->topology_refiner = topology_refiner;
274
275         if (refiner->GetNumFVarChannels() > 0) {
276                 std::vector<float> fvar_data;
277                 interpolate_fvar_data(*refiner, topology_refiner->uvs, fvar_data);
278                 openSubdiv_osdGLAllocFVar(gl_mesh, &fvar_data[0]);
279         }
280         else {
281                 gl_mesh->fvar_data = NULL;
282         }
283
284         return gl_mesh;
285 }
286
287 void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh)
288 {
289         openSubdiv_osdGLDestroyFVar(gl_mesh);
290         switch (gl_mesh->evaluator_type) {
291 #define CHECK_EVALUATOR_TYPE(type, class) \
292                 case OPENSUBDIV_EVALUATOR_ ## type: \
293                         delete (class *) gl_mesh->descriptor; \
294                         break;
295
296                 CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh)
297
298 #ifdef OPENSUBDIV_HAS_OPENMP
299                 CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh)
300 #endif
301
302 #ifdef OPENSUBDIV_HAS_OPENCL
303                 CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh)
304 #endif
305
306 #ifdef OPENSUBDIV_HAS_CUDA
307                 CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh)
308 #endif
309
310 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
311                 CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK,
312                                      OsdGLSLTransformFeedbackMesh)
313 #endif
314
315 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
316                 CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh)
317 #endif
318
319 #undef CHECK_EVALUATOR_TYPE
320         }
321
322         /* NOTE: OSD refiner was owned by gl_mesh, no need to free it here. */
323         OBJECT_GUARDED_DELETE(gl_mesh->topology_refiner, OpenSubdiv_TopologyRefinerDescr);
324         OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh);
325 }
326
327 unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer(struct OpenSubdiv_GLMesh *gl_mesh)
328 {
329         return ((GLMeshInterface *)gl_mesh->descriptor)->GetPatchTable()->GetPatchIndexBuffer();
330 }
331
332 unsigned int openSubdiv_getOsdGLMeshVertexBuffer(struct OpenSubdiv_GLMesh *gl_mesh)
333 {
334         return ((GLMeshInterface *)gl_mesh->descriptor)->BindVertexBuffer();
335 }
336
337 void openSubdiv_osdGLMeshUpdateVertexBuffer(struct OpenSubdiv_GLMesh *gl_mesh,
338                                             const float *vertex_data,
339                                             int start_vertex,
340                                             int num_verts)
341 {
342         ((GLMeshInterface *)gl_mesh->descriptor)->UpdateVertexBuffer(vertex_data,
343                                                                      start_vertex,
344                                                                      num_verts);
345 }
346
347 void openSubdiv_osdGLMeshRefine(struct OpenSubdiv_GLMesh *gl_mesh)
348 {
349         ((GLMeshInterface *)gl_mesh->descriptor)->Refine();
350 }
351
352 void openSubdiv_osdGLMeshSynchronize(struct OpenSubdiv_GLMesh *gl_mesh)
353 {
354         ((GLMeshInterface *)gl_mesh->descriptor)->Synchronize();
355 }
356
357 void openSubdiv_osdGLMeshBindVertexBuffer(OpenSubdiv_GLMesh *gl_mesh)
358 {
359         ((GLMeshInterface *)gl_mesh->descriptor)->BindVertexBuffer();
360 }
361
362 const struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_getGLMeshTopologyRefiner(
363         OpenSubdiv_GLMesh *gl_mesh)
364 {
365         return gl_mesh->topology_refiner;
366 }
367
368 int openSubdiv_supportGPUDisplay(void)
369 {
370         // TODO: simplify extension check once Blender adopts GL 3.2
371         return openSubdiv_gpu_legacy_support() &&
372                (GLEW_VERSION_3_2 ||
373                (GLEW_VERSION_3_1 && GLEW_EXT_geometry_shader4) ||
374                (GLEW_VERSION_3_0 && GLEW_EXT_geometry_shader4 && GLEW_ARB_uniform_buffer_object && (GLEW_ARB_texture_buffer_object || GLEW_EXT_texture_buffer_object)));
375         /* also ARB_explicit_attrib_location? */
376 }