Cycles: Code cleanup, spaces around keywords
[blender-staging.git] / intern / cycles / subd / subd_mesh.cpp
1 /*
2  * Original code in the public domain -- castanyo@yahoo.es
3  * 
4  * Modifications copyright (c) 2011, Blender Foundation.
5  * All rights reserved.
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  * * Redistributions of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <stdio.h>
30
31 #include "subd_mesh.h"
32 #include "subd_patch.h"
33 #include "subd_split.h"
34
35 #include "util_debug.h"
36 #include "util_foreach.h"
37
38 #ifdef WITH_OPENSUBDIV
39
40 #include <osd/vertex.h>
41 #include <osd/mesh.h>
42 #include <osd/cpuComputeController.h>
43 #include <osd/cpuVertexBuffer.h>
44 #include <osd/cpuEvalLimitController.h>
45 #include <osd/evalLimitContext.h>
46
47 CCL_NAMESPACE_BEGIN
48
49 /* typedefs */
50 typedef OpenSubdiv::OsdVertex OsdVertex;
51 typedef OpenSubdiv::FarMesh<OsdVertex> OsdFarMesh;
52 typedef OpenSubdiv::FarMeshFactory<OsdVertex> OsdFarMeshFactory;
53 typedef OpenSubdiv::HbrCatmarkSubdivision<OsdVertex> OsdHbrCatmarkSubdivision;
54 typedef OpenSubdiv::HbrFace<OsdVertex> OsdHbrFace;
55 typedef OpenSubdiv::HbrHalfedge<OsdVertex> OsdHbrHalfEdge;
56 typedef OpenSubdiv::HbrMesh<OsdVertex> OsdHbrMesh;
57 typedef OpenSubdiv::HbrVertex<OsdVertex> OsdHbrVertex;
58 typedef OpenSubdiv::OsdCpuComputeContext OsdCpuComputeContext;
59 typedef OpenSubdiv::OsdCpuComputeController OsdCpuComputeController;
60 typedef OpenSubdiv::OsdCpuEvalLimitContext OsdCpuEvalLimitContext;
61 typedef OpenSubdiv::OsdCpuEvalLimitController OsdCpuEvalLimitController;
62 typedef OpenSubdiv::OsdCpuVertexBuffer OsdCpuVertexBuffer;
63 typedef OpenSubdiv::OsdEvalCoords OsdEvalCoords;
64 typedef OpenSubdiv::OsdVertexBufferDescriptor OsdVertexBufferDescriptor;
65
66 /* OpenSubdiv Patch */
67
68 class OpenSubdPatch : public Patch {
69 public:
70         int face_id;
71
72         OpenSubdPatch(OsdFarMesh *farmesh, OsdCpuVertexBuffer *vbuf_base)
73         {
74                 face_id = 0;
75
76                 /* create buffers for evaluation */
77                 vbuf_P = OsdCpuVertexBuffer::Create(3, 1);
78                 vbuf_dPdu = OsdCpuVertexBuffer::Create(3, 1);
79                 vbuf_dPdv = OsdCpuVertexBuffer::Create(3, 1);
80
81                 P = vbuf_P->BindCpuBuffer();
82                 dPdu = vbuf_dPdu->BindCpuBuffer();
83                 dPdv = vbuf_dPdv->BindCpuBuffer();
84
85                 /* setup evaluation context */
86                 OsdVertexBufferDescriptor in_desc(0, 3, 3), out_desc(0, 3, 3); /* offset, length, stride */
87
88                 evalctx = OsdCpuEvalLimitContext::Create(farmesh, false);
89                 evalctx->GetVertexData().Bind(in_desc, vbuf_base, out_desc, vbuf_P, vbuf_dPdu, vbuf_dPdv);
90         }
91
92         ~OpenSubdPatch()
93         {
94                 evalctx->GetVertexData().Unbind();
95
96                 delete evalctx;
97                 delete vbuf_P;
98                 delete vbuf_dPdu;
99                 delete vbuf_dPdv;
100         }
101
102         void eval(float3 *P_, float3 *dPdu_, float3 *dPdv_, float u, float v)
103         {
104                 OsdEvalCoords coords;
105                 coords.u = u;
106                 coords.v = v;
107                 coords.face = face_id;
108
109                 evalctrl.EvalLimitSample<OsdCpuVertexBuffer,OsdCpuVertexBuffer>(coords, evalctx, 0);
110
111                 *P_ = make_float3(P[0], P[1], P[2]);
112                 if(dPdu_) *dPdu_ = make_float3(dPdv[0], dPdv[1], dPdv[2]);
113                 if(dPdv_) *dPdv_ = make_float3(dPdu[0], dPdu[1], dPdu[2]);
114
115                 /* optimize: skip evaluating derivatives when not needed */
116                 /* todo: swapped derivatives, different winding convention? */
117         }
118
119         BoundBox bound()
120         {
121                 /* not implemented */
122                 BoundBox bbox = BoundBox::empty;
123                 return bbox;
124         }
125
126         int ptex_face_id()
127         {
128                 return face_id;
129         }
130
131 protected:
132         OsdCpuEvalLimitController evalctrl;
133         OsdCpuEvalLimitContext *evalctx;
134         OsdCpuVertexBuffer *vbuf_P;
135         OsdCpuVertexBuffer *vbuf_dPdu;
136         OsdCpuVertexBuffer *vbuf_dPdv;
137         float *P;
138         float *dPdu;
139         float *dPdv;
140 };
141
142 /* OpenSubdiv Mesh */
143
144 OpenSubdMesh::OpenSubdMesh()
145 {
146         /* create osd mesh */
147         static OsdHbrCatmarkSubdivision catmark;
148         OsdHbrMesh *hbrmesh = new OsdHbrMesh(&catmark);
149
150         /* initialize class */
151         num_verts = 0;
152         num_ptex_faces = 0;
153         _hbrmesh = (void*)hbrmesh;
154 }
155
156 OpenSubdMesh::~OpenSubdMesh()
157 {
158         OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
159
160         if(hbrmesh)
161                 delete hbrmesh;
162 }
163
164 void OpenSubdMesh::add_vert(const float3& co)
165 {
166         OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
167
168         OsdVertex v;
169         positions.push_back(co.x);
170         positions.push_back(co.y);
171         positions.push_back(co.z);
172         hbrmesh->NewVertex(num_verts++, v);
173 }
174
175 void OpenSubdMesh::add_face(int v0, int v1, int v2)
176 {
177         int index[3] = {v0, v1, v2};
178         return add_face(index, 3);
179 }
180
181 void OpenSubdMesh::add_face(int v0, int v1, int v2, int v3)
182 {
183         int index[4] = {v0, v1, v2, v3};
184         add_face(index, 4);
185 }
186
187 void OpenSubdMesh::add_face(int *index, int num)
188 {
189         OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
190
191 #ifndef NDEBUG
192         /* sanity checks */
193         for(int j = 0; j < num; j++) {
194                 OsdHbrVertex *origin = hbrmesh->GetVertex(index[j]);
195                 OsdHbrVertex *destination = hbrmesh->GetVertex(index[(j+1)%num]);
196                 OsdHbrHalfEdge *opposite = destination->GetEdge(origin);
197
198                 if(origin==NULL || destination==NULL)
199                         assert("An edge was specified that connected a nonexistent vertex\n");
200
201                 if(origin == destination)
202                         assert("An edge was specified that connected a vertex to itself\n");
203
204                 if(opposite && opposite->GetOpposite())
205                         assert("A non-manifold edge incident to more than 2 faces was found\n");
206
207                 if(origin->GetEdge(destination))
208                         assert("An edge connecting two vertices was specified more than once."
209                                  "It's likely that an incident face was flipped\n");
210         }
211 #endif
212
213         OsdHbrFace *face = hbrmesh->NewFace(num, index, 0);
214
215         /* this is required for limit eval patch table? */
216         face->SetPtexIndex(num_ptex_faces);
217
218         if(num == 4)
219                 num_ptex_faces++;
220         else
221                 num_ptex_faces += num;
222 }
223
224 bool OpenSubdMesh::finish()
225 {
226         OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
227
228         /* finish hbr mesh construction */
229         hbrmesh->SetInterpolateBoundaryMethod(OsdHbrMesh::k_InterpolateBoundaryEdgeOnly);
230         hbrmesh->Finish();
231
232         return true;
233 }
234
235 void OpenSubdMesh::tessellate(DiagSplit *split)
236 {
237         if(num_ptex_faces == 0)
238                 return;
239
240         const int level = 3;
241         const bool requirefvar = false;
242
243         /* convert HRB to FAR mesh */
244         OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
245
246         OsdFarMeshFactory meshFactory(hbrmesh, level, true);
247         OsdFarMesh *farmesh = meshFactory.Create(requirefvar);
248         int num_hbr_verts = hbrmesh->GetNumVertices();
249
250         delete hbrmesh;
251         hbrmesh = NULL;
252         _hbrmesh = NULL;
253
254         /* refine HBR mesh with vertex coordinates */
255         OsdCpuComputeController *compute_controller = new OsdCpuComputeController();
256         OsdCpuComputeContext *compute_context = OsdCpuComputeContext::Create(farmesh);
257
258         OsdCpuVertexBuffer *vbuf_base = OsdCpuVertexBuffer::Create(3, num_hbr_verts);
259         vbuf_base->UpdateData(&positions[0], 0, num_verts);
260
261         compute_controller->Refine(compute_context, farmesh->GetKernelBatches(), vbuf_base);
262         compute_controller->Synchronize();
263
264         /* split & dice patches */
265         OpenSubdPatch patch(farmesh, vbuf_base);
266
267         for(int f = 0; f < num_ptex_faces; f++) {
268                 patch.face_id = f;
269                 split->split_quad(&patch);
270         }
271
272         /* clean up */
273         delete farmesh;
274         delete compute_controller;
275         delete compute_context;
276         delete vbuf_base;
277 }
278
279 CCL_NAMESPACE_END
280
281 #else /* WITH_OPENSUBDIV */
282
283 CCL_NAMESPACE_BEGIN
284
285 /* Subd Vertex */
286
287 class SubdVert
288 {
289 public:
290         int id;
291         float3 co;
292         
293         SubdVert(int id_)
294         {
295                 id = id_;
296                 co = make_float3(0.0f, 0.0f, 0.0f);
297         }
298 };
299
300 /* Subd Face */
301
302 class SubdFace
303 {
304 public:
305         int id;
306         int numverts;
307         int verts[4];
308
309         SubdFace(int id_)
310         {
311                 id = id_;
312                 numverts = 0;
313         }
314 };
315
316 /* Subd Mesh */
317
318 SubdMesh::SubdMesh()
319 {
320 }
321
322 SubdMesh::~SubdMesh()
323 {
324         foreach(SubdVert *vertex, verts)
325                 delete vertex;
326         foreach(SubdFace *face, faces)
327                 delete face;
328
329         verts.clear();
330         faces.clear();
331 }
332
333 SubdVert *SubdMesh::add_vert(const float3& co)
334 {
335         SubdVert *v = new SubdVert(verts.size());
336         v->co = co;
337         verts.push_back(v);
338
339         return v;
340 }
341
342 SubdFace *SubdMesh::add_face(int v0, int v1, int v2)
343 {
344         int index[3] = {v0, v1, v2};
345         return add_face(index, 3);
346 }
347
348 SubdFace *SubdMesh::add_face(int v0, int v1, int v2, int v3)
349 {
350         int index[4] = {v0, v1, v2, v3};
351         return add_face(index, 4);
352 }
353
354 SubdFace *SubdMesh::add_face(int *index, int num)
355 {
356         /* skip ngons */
357         if(num < 3 || num > 4)
358                 return NULL;
359
360         SubdFace *f = new SubdFace(faces.size());
361
362         for(int i = 0; i < num; i++)
363                 f->verts[i] = index[i];
364
365         f->numverts = num;
366         faces.push_back(f);
367
368         return f;
369 }
370
371 bool SubdMesh::finish()
372 {
373         return true;
374 }
375
376 void SubdMesh::tessellate(DiagSplit *split)
377 {
378         int num_faces = faces.size();
379                         
380         for(int f = 0; f < num_faces; f++) {
381                 SubdFace *face = faces[f];
382                 Patch *patch;
383                 float3 *hull;
384
385                 if(face->numverts == 3) {
386                         LinearTrianglePatch *lpatch = new LinearTrianglePatch();
387                         hull = lpatch->hull;
388                         patch = lpatch;
389                 }
390                 else if(face->numverts == 4) {
391                         LinearQuadPatch *lpatch = new LinearQuadPatch();
392                         hull = lpatch->hull;
393                         patch = lpatch;
394                 }
395                 else {
396                         assert(0); /* n-gons should have been split already */
397                         continue;
398                 }
399
400                 for(int i = 0; i < face->numverts; i++)
401                         hull[i] = verts[face->verts[i]]->co;
402
403                 if(face->numverts == 4)
404                         swap(hull[2], hull[3]);
405
406                 if(patch->is_triangle())
407                         split->split_triangle(patch);
408                 else
409                         split->split_quad(patch);
410
411                 delete patch;
412         }
413 }
414
415 CCL_NAMESPACE_END
416
417 #endif /* WITH_OPENSUBDIV */
418