ClangFormat: apply to source, most of intern
[blender.git] / intern / opensubdiv / internal / opensubdiv_gl_mesh.cc
1 // Copyright 2013 Blender Foundation. All rights reserved.
2 //
3 // This program is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU General Public License
5 // as published by the Free Software Foundation; either version 2
6 // of the License, or (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software Foundation,
15 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
17 #include "opensubdiv_gl_mesh_capi.h"
18
19 #ifdef _MSC_VER
20 #  include <iso646.h>
21 #endif
22
23 #include <opensubdiv/far/stencilTable.h>
24 #include <opensubdiv/osd/glMesh.h>
25 #include <opensubdiv/osd/glPatchTable.h>
26
27 using OpenSubdiv::Far::StencilTable;
28 using OpenSubdiv::Osd::GLMeshInterface;
29 using OpenSubdiv::Osd::GLPatchTable;
30 using OpenSubdiv::Osd::Mesh;
31 using OpenSubdiv::Osd::MeshBitset;
32
33 // CPU backend.
34 #include <opensubdiv/osd/cpuEvaluator.h>
35 #include <opensubdiv/osd/cpuGLVertexBuffer.h>
36 using OpenSubdiv::Osd::CpuEvaluator;
37 using OpenSubdiv::Osd::CpuGLVertexBuffer;
38 typedef Mesh<CpuGLVertexBuffer, StencilTable, CpuEvaluator, GLPatchTable> OsdCpuMesh;
39 // OpenMP backend.
40 #ifdef OPENSUBDIV_HAS_OPENMP
41 #  include <opensubdiv/osd/ompEvaluator.h>
42 using OpenSubdiv::Osd::OmpEvaluator;
43 typedef Mesh<CpuGLVertexBuffer, StencilTable, OmpEvaluator, GLPatchTable> OsdOmpMesh;
44 #endif
45 // OpenCL backend.
46 #ifdef OPENSUBDIV_HAS_OPENCL
47 #  include <opensubdiv/osd/clEvaluator.h>
48 #  include <opensubdiv/osd/clGLVertexBuffer.h>
49 #  include "opensubdiv_device_context_opencl.h"
50 using OpenSubdiv::Osd::CLEvaluator;
51 using OpenSubdiv::Osd::CLGLVertexBuffer;
52 using OpenSubdiv::Osd::CLStencilTable;
53 /* TODO(sergey): Use CLDeviceContext similar to OSD examples? */
54 typedef Mesh<CLGLVertexBuffer, CLStencilTable, CLEvaluator, GLPatchTable, CLDeviceContext>
55     OsdCLMesh;
56 static CLDeviceContext g_cl_device_context;
57 #endif
58 // CUDA backend.
59 #ifdef OPENSUBDIV_HAS_CUDA
60 #  include <opensubdiv/osd/cudaEvaluator.h>
61 #  include <opensubdiv/osd/cudaGLVertexBuffer.h>
62 #  include "opensubdiv_device_context_cuda.h"
63 using OpenSubdiv::Osd::CudaEvaluator;
64 using OpenSubdiv::Osd::CudaGLVertexBuffer;
65 using OpenSubdiv::Osd::CudaStencilTable;
66 typedef Mesh<CudaGLVertexBuffer, CudaStencilTable, CudaEvaluator, GLPatchTable> OsdCudaMesh;
67 static CudaDeviceContext g_cuda_device_context;
68 #endif
69 // Transform feedback backend.
70 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
71 #  include <opensubdiv/osd/glVertexBuffer.h>
72 #  include <opensubdiv/osd/glXFBEvaluator.h>
73 using OpenSubdiv::Osd::GLStencilTableTBO;
74 using OpenSubdiv::Osd::GLVertexBuffer;
75 using OpenSubdiv::Osd::GLXFBEvaluator;
76 typedef Mesh<GLVertexBuffer, GLStencilTableTBO, GLXFBEvaluator, GLPatchTable>
77     OsdGLSLTransformFeedbackMesh;
78 #endif
79 // GLSL compute backend.
80 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
81 #  include <opensubdiv/osd/glComputeEvaluator.h>
82 #  include <opensubdiv/osd/glVertexBuffer.h>
83 using OpenSubdiv::Osd::GLComputeEvaluator;
84 using OpenSubdiv::Osd::GLStencilTableSSBO;
85 using OpenSubdiv::Osd::GLVertexBuffer;
86 typedef Mesh<GLVertexBuffer, GLStencilTableSSBO, GLComputeEvaluator, GLPatchTable>
87     OsdGLSLComputeMesh;
88 #endif
89
90 #include "MEM_guardedalloc.h"
91
92 #include "opensubdiv_topology_refiner_capi.h"
93 #include "internal/opensubdiv_gl_mesh_draw.h"
94 #include "internal/opensubdiv_gl_mesh_fvar.h"
95 #include "internal/opensubdiv_gl_mesh_internal.h"
96 #include "internal/opensubdiv_topology_refiner_internal.h"
97 #include "internal/opensubdiv_util.h"
98
99 using opensubdiv_capi::vector;
100
101 namespace {
102
103 GLMeshInterface *createGLMeshInterface(OpenSubdiv::Far::TopologyRefiner *topology_refiner,
104                                        const MeshBitset &bits,
105                                        const int num_vertex_elements,
106                                        const int num_varying_elements,
107                                        const int level,
108                                        eOpenSubdivEvaluator evaluator_type)
109 {
110   GLMeshInterface *mesh = NULL;
111   switch (evaluator_type) {
112 #define CHECK_EVALUATOR_TYPE(type, class) \
113   case OPENSUBDIV_EVALUATOR_##type: \
114     mesh = new class(topology_refiner, num_vertex_elements, num_varying_elements, level, bits); \
115     break;
116
117 #define CHECK_EVALUATOR_TYPE_STUB(type) \
118   case OPENSUBDIV_EVALUATOR_##type: \
119     mesh = NULL; \
120     break;
121
122     CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh)
123 #ifdef OPENSUBDIV_HAS_OPENMP
124     CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh)
125 #else
126     CHECK_EVALUATOR_TYPE_STUB(OPENMP)
127 #endif
128 #ifdef OPENSUBDIV_HAS_OPENCL
129     CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh)
130 #else
131     CHECK_EVALUATOR_TYPE_STUB(OPENCL)
132 #endif
133 #ifdef OPENSUBDIV_HAS_CUDA
134     CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh)
135 #else
136     CHECK_EVALUATOR_TYPE_STUB(CUDA)
137 #endif
138 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
139     CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK, OsdGLSLTransformFeedbackMesh)
140 #else
141     CHECK_EVALUATOR_TYPE_STUB(GLSL_TRANSFORM_FEEDBACK)
142 #endif
143 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
144     CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh)
145 #else
146     CHECK_EVALUATOR_TYPE_STUB(GLSL_COMPUTE)
147 #endif
148
149 #undef CHECK_EVALUATOR_TYPE
150 #undef CHECK_EVALUATOR_TYPE_STUB
151   }
152   return mesh;
153 }
154
155 ////////////////////////////////////////////////////////////////////////////////
156 // GLMesh structure "methods".
157
158 opensubdiv_capi::GLMeshFVarData *createFVarData(OpenSubdiv::Far::TopologyRefiner *topology_refiner,
159                                                 GLMeshInterface *mesh,
160                                                 const float *fvar_src_buffer)
161 {
162   using opensubdiv_capi::GLMeshFVarData;
163   GLMeshFVarData *fvar_data = new GLMeshFVarData();
164   fvar_data->create(topology_refiner, mesh->GetFarPatchTable(), 2, fvar_src_buffer);
165   return fvar_data;
166 }
167
168 unsigned int getPatchIndexBuffer(OpenSubdiv_GLMesh *gl_mesh)
169 {
170   return gl_mesh->internal->mesh_interface->GetPatchTable()->GetPatchIndexBuffer();
171 }
172
173 void bindVertexBuffer(OpenSubdiv_GLMesh *gl_mesh)
174 {
175   gl_mesh->internal->mesh_interface->BindVertexBuffer();
176 }
177
178 void setCoarsePositions(OpenSubdiv_GLMesh *gl_mesh,
179                         const float *positions,
180                         const int start_vertex,
181                         const int num_vertices)
182 {
183   gl_mesh->internal->mesh_interface->UpdateVertexBuffer(positions, start_vertex, num_vertices);
184 }
185
186 void refine(OpenSubdiv_GLMesh *gl_mesh)
187 {
188   gl_mesh->internal->mesh_interface->Refine();
189 }
190
191 void synchronize(struct OpenSubdiv_GLMesh *gl_mesh)
192 {
193   gl_mesh->internal->mesh_interface->Synchronize();
194 }
195
196 void assignFunctionPointers(OpenSubdiv_GLMesh *gl_mesh)
197 {
198   gl_mesh->getPatchIndexBuffer = getPatchIndexBuffer;
199   gl_mesh->bindVertexBuffer = bindVertexBuffer;
200   gl_mesh->setCoarsePositions = setCoarsePositions;
201   gl_mesh->refine = refine;
202   gl_mesh->synchronize = synchronize;
203
204   gl_mesh->prepareDraw = opensubdiv_capi::GLMeshDisplayPrepare;
205   gl_mesh->drawPatches = opensubdiv_capi::GLMeshDisplayDrawPatches;
206 }
207
208 }  // namespace
209
210 struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
211     OpenSubdiv_TopologyRefiner *topology_refiner, eOpenSubdivEvaluator evaluator_type)
212 {
213   using OpenSubdiv::Far::TopologyRefiner;
214   TopologyRefiner *osd_topology_refiner = topology_refiner->internal->osd_topology_refiner;
215   // TODO(sergey): Query this from refiner.
216   const bool is_adaptive = false;
217   MeshBitset bits;
218   bits.set(OpenSubdiv::Osd::MeshAdaptive, is_adaptive);
219   bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, 0);
220   bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, 1);
221   bits.set(OpenSubdiv::Osd::MeshFVarData, 1);
222   bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, 1);
223   const int num_vertex_elements = 3;
224   const int num_varying_elements = 3;
225   GLMeshInterface *mesh = createGLMeshInterface(osd_topology_refiner,
226                                                 bits,
227                                                 num_vertex_elements,
228                                                 num_varying_elements,
229                                                 osd_topology_refiner->GetMaxLevel(),
230                                                 evaluator_type);
231   if (mesh == NULL) {
232     return NULL;
233   }
234   OpenSubdiv_GLMesh *gl_mesh = OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh);
235   assignFunctionPointers(gl_mesh);
236   gl_mesh->internal = new OpenSubdiv_GLMeshInternal();
237   gl_mesh->internal->evaluator_type = evaluator_type;
238   gl_mesh->internal->mesh_interface = mesh;
239   // Face-varying support.
240   // TODO(sergey): This part needs to be re-done.
241   if (osd_topology_refiner->GetNumFVarChannels() > 0) {
242     // TODO(sergey): This is a temporary stub to get things compiled. Need
243     // to store base level UVs somewhere else.
244     vector<float> uvs;
245     vector<float> fvar_data_buffer;
246     opensubdiv_capi::interpolateFVarData(*osd_topology_refiner, uvs, &fvar_data_buffer);
247     gl_mesh->internal->fvar_data = createFVarData(
248         osd_topology_refiner, mesh, &fvar_data_buffer[0]);
249   }
250   else {
251     gl_mesh->internal->fvar_data = NULL;
252   }
253   return gl_mesh;
254 }
255
256 void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh)
257 {
258   delete gl_mesh->internal;
259   OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh);
260 }