Fix incorrect FLT_MIN use
[blender.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         }
212 #endif
213
214         OsdHbrFace *face = hbrmesh->NewFace(num, index, 0);
215
216         /* this is required for limit eval patch table? */
217         face->SetPtexIndex(num_ptex_faces);
218
219         if(num == 4)
220                 num_ptex_faces++;
221         else
222                 num_ptex_faces += num;
223 }
224
225 bool OpenSubdMesh::finish()
226 {
227         OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
228
229         /* finish hbr mesh construction */
230         hbrmesh->SetInterpolateBoundaryMethod(OsdHbrMesh::k_InterpolateBoundaryEdgeOnly);
231         hbrmesh->Finish();
232
233         return true;
234 }
235
236 void OpenSubdMesh::tessellate(DiagSplit *split)
237 {
238         if(num_ptex_faces == 0)
239                 return;
240
241         const int level = 3;
242         const bool requirefvar = false;
243
244         /* convert HRB to FAR mesh */
245         OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
246
247         OsdFarMeshFactory meshFactory(hbrmesh, level, true);
248         OsdFarMesh *farmesh = meshFactory.Create(requirefvar);
249         int num_hbr_verts = hbrmesh->GetNumVertices();
250
251         delete hbrmesh;
252         hbrmesh = NULL;
253         _hbrmesh = NULL;
254
255         /* refine HBR mesh with vertex coordinates */
256         OsdCpuComputeController *compute_controller = new OsdCpuComputeController();
257         OsdCpuComputeContext *compute_context = OsdCpuComputeContext::Create(farmesh);
258
259         OsdCpuVertexBuffer *vbuf_base = OsdCpuVertexBuffer::Create(3, num_hbr_verts);
260         vbuf_base->UpdateData(&positions[0], 0, num_verts);
261
262         compute_controller->Refine(compute_context, farmesh->GetKernelBatches(), vbuf_base);
263         compute_controller->Synchronize();
264
265         /* split & dice patches */
266         OpenSubdPatch patch(farmesh, vbuf_base);
267
268         for(int f = 0; f < num_ptex_faces; f++) {
269                 patch.face_id = f;
270                 split->split_quad(&patch);
271         }
272
273         /* clean up */
274         delete farmesh;
275         delete compute_controller;
276         delete compute_context;
277         delete vbuf_base;
278 }
279
280 CCL_NAMESPACE_END
281
282 #else /* WITH_OPENSUBDIV */
283
284 CCL_NAMESPACE_BEGIN
285
286 /* Subd Vertex */
287
288 class SubdVert
289 {
290 public:
291         int id;
292         float3 co;
293         
294         SubdVert(int id_)
295         {
296                 id = id_;
297                 co = make_float3(0.0f, 0.0f, 0.0f);
298         }
299 };
300
301 /* Subd Face */
302
303 class SubdFace
304 {
305 public:
306         int id;
307         int numverts;
308         int verts[4];
309
310         SubdFace(int id_)
311         {
312                 id = id_;
313                 numverts = 0;
314         }
315 };
316
317 /* Subd Mesh */
318
319 SubdMesh::SubdMesh()
320 {
321 }
322
323 SubdMesh::~SubdMesh()
324 {
325         foreach(SubdVert *vertex, verts)
326                 delete vertex;
327         foreach(SubdFace *face, faces)
328                 delete face;
329
330         verts.clear();
331         faces.clear();
332 }
333
334 SubdVert *SubdMesh::add_vert(const float3& co)
335 {
336         SubdVert *v = new SubdVert(verts.size());
337         v->co = co;
338         verts.push_back(v);
339
340         return v;
341 }
342
343 SubdFace *SubdMesh::add_face(int v0, int v1, int v2)
344 {
345         int index[3] = {v0, v1, v2};
346         return add_face(index, 3);
347 }
348
349 SubdFace *SubdMesh::add_face(int v0, int v1, int v2, int v3)
350 {
351         int index[4] = {v0, v1, v2, v3};
352         return add_face(index, 4);
353 }
354
355 SubdFace *SubdMesh::add_face(int *index, int num)
356 {
357         /* skip ngons */
358         if(num < 3 || num > 4)
359                 return NULL;
360
361         SubdFace *f = new SubdFace(faces.size());
362
363         for(int i = 0; i < num; i++)
364                 f->verts[i] = index[i];
365
366         f->numverts = num;
367         faces.push_back(f);
368
369         return f;
370 }
371
372 bool SubdMesh::finish()
373 {
374         return true;
375 }
376
377 void SubdMesh::tessellate(DiagSplit *split)
378 {
379         int num_faces = faces.size();
380                         
381         for(int f = 0; f < num_faces; f++) {
382                 SubdFace *face = faces[f];
383                 Patch *patch;
384                 float3 *hull;
385
386                 if(face->numverts == 3) {
387                         LinearTrianglePatch *lpatch = new LinearTrianglePatch();
388                         hull = lpatch->hull;
389                         patch = lpatch;
390                 }
391                 else if(face->numverts == 4) {
392                         LinearQuadPatch *lpatch = new LinearQuadPatch();
393                         hull = lpatch->hull;
394                         patch = lpatch;
395                 }
396                 else {
397                         assert(0); /* n-gons should have been split already */
398                         continue;
399                 }
400
401                 for(int i = 0; i < face->numverts; i++)
402                         hull[i] = verts[face->verts[i]]->co;
403
404                 if(face->numverts == 4)
405                         swap(hull[2], hull[3]);
406
407                 if(patch->is_triangle())
408                         split->split_triangle(patch);
409                 else
410                         split->split_quad(patch);
411
412                 delete patch;
413         }
414 }
415
416 CCL_NAMESPACE_END
417
418 #endif /* WITH_OPENSUBDIV */
419