added 3dengfx into the repo, probably not the correct version for this
[summerhack] / src / 3dengfx / src / 3dengfx / ggen.cpp
1 /*
2 This file is part of the 3dengfx, 3d visualization system.
3
4 Copyright (c) 2004, 2005, 2006 John Tsiombikas <nuclear@siggraph.org>
5
6 3dengfx is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 3dengfx is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with 3dengfx; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 /* geometry generation
22  * 
23  * author: John Tsiombikas 2004
24  * modified: 
25  *              Mihalis Georgoulopoulos 2004, 2005
26  *              John Tsiombikas 2005
27  */
28
29 #include <float.h>
30 #include "3dengfx_config.h"
31 #include "gfx/curves.hpp"
32 #include "ggen.hpp"
33
34 #define GGEN_SOURCE
35 #include "teapot.h"
36
37 /* create_cube - (JT)
38  * creates a subdivided cube
39  */
40 void create_cube(TriMesh *mesh, scalar_t size, int subdiv) {
41         TriMesh tmp;
42         Matrix4x4 mat;
43
44         Vector3 face_vec[] = {
45                 Vector3(0, 0, -1),
46                 Vector3(1, 0, 0),
47                 Vector3(0, 0, 1),
48                 Vector3(-1, 0, 0),
49                 Vector3(0, 1, 0),
50                 Vector3(0, -1, 0)
51         };
52
53         for(int i=0; i<6; i++) {
54                 create_plane(i ? &tmp : mesh, face_vec[i], Vector2(size, size), subdiv);
55                 mat.set_translation(face_vec[i] * (size / 2.0));
56
57                 if(i) {
58                         tmp.apply_xform(mat);
59                         join_tri_mesh(mesh, mesh, &tmp);
60                 } else {
61                         mesh->apply_xform(mat);
62                 }
63         }
64 }
65  
66 /* CreatePlane - (JT)
67  * creates a planar mesh of arbitrary subdivision
68  */
69 void create_plane(TriMesh *mesh, const Vector3 &normal, const Vector2 &size, int subdiv) {
70         unsigned long vcount = (subdiv + 2) * (subdiv + 2);
71         unsigned long tcount = (subdiv + 1) * (subdiv + 1) * 2;
72         int quad_num = tcount / 2;
73         int quads_row = subdiv + 1;             // quads per row
74         int vrow = subdiv + 2;          // vertices per row
75         int vcol = vrow;
76
77     Vertex *varray = new Vertex[vcount];
78         Triangle *tarray = new Triangle[tcount];
79
80         for(int j=0; j<vcol; j++) {
81                 for(int i=0; i<vrow; i++) {
82
83                         scalar_t u = (scalar_t)i/(scalar_t)quads_row;
84                         scalar_t v = (scalar_t)j/(scalar_t)quads_row;
85                         varray[j * vrow + i] = Vertex(Vector3(u - 0.5f, 1.0f - v - 0.5f, 0), u, 1.0 - v, Color(1.0f));
86                         varray[j * vrow + i].pos.x *= size.x;
87                         varray[j * vrow + i].pos.y *= size.y;
88                 }
89         }
90
91         // first seperate the quads and then triangulate
92         Quad *quads = new Quad[quad_num];
93
94         for(int i=0; i<quad_num; i++) {
95                 quads[i].vertices[0] = i + i / quads_row;
96                 quads[i].vertices[1] = quads[i].vertices[0] + 1;
97                 quads[i].vertices[2] = quads[i].vertices[0] + vrow;
98                 quads[i].vertices[3] = quads[i].vertices[1] + vrow;
99         }
100
101         for(int i=0; i<quad_num; i++) {
102                 tarray[i * 2] = Triangle(quads[i].vertices[0], quads[i].vertices[1], quads[i].vertices[3]);
103                 tarray[i * 2 + 1] = Triangle(quads[i].vertices[0], quads[i].vertices[3], quads[i].vertices[2]);
104         }
105
106         for(unsigned long i=0; i<vcount; i++) {
107                 varray[i].normal = Vector3(0, 0, -1);
108         }
109
110         // reorient the plane to match the specification
111         Basis b;
112         Vector3 n = normal.normalized();
113         b.k = -n;
114         
115         if(fabs(dot_product(n, Vector3(1, 0, 0))) < 1.0 - small_number) {
116                 b.i = Vector3(1, 0, 0);
117                 b.j = cross_product(b.k, b.i);
118                 b.i = cross_product(b.j, b.k);
119         } else {
120                 b.j = Vector3(0, 1, 0);
121                 b.i = cross_product(b.j, b.k);
122                 b.j = cross_product(b.k, b.i);
123         }
124         
125         Matrix3x3 rot = b.create_rotation_matrix();
126
127         for(unsigned long i=0; i<vcount; i++) {
128                 varray[i].pos.transform(rot);
129                 varray[i].normal.transform(rot);
130         }
131
132         mesh->set_data(varray, vcount, tarray, tcount);
133
134         delete [] quads;
135         delete [] varray;
136         delete [] tarray;
137 }
138
139 /* CreateCylinder - (JT)
140  * creates a cylinder by extruding a circle along the y axis, with optional
141  * caps at each end.
142  */
143 void create_cylinder(TriMesh *mesh, scalar_t rad, scalar_t len, bool caps, int udiv, int vdiv) {
144         if(udiv < 3) udiv = 3;
145         Vector3 *circle = new Vector3[udiv + 1];
146
147         // generate the circle
148         Vector3 cgen(0.0, -len / 2.0, rad);
149         
150         for(int i=0; i<udiv; i++) {
151                 Matrix3x3 mat;
152                 mat.set_rotation(Vector3(0.0, two_pi * (scalar_t)i / (scalar_t)udiv, 0.0));
153                 circle[i] = cgen.transformed(mat);
154         }
155         circle[udiv] = cgen;
156
157         // extrude along y
158         int slices = vdiv + 2;
159         int vcount = (udiv + 1) * slices + (caps ? 2 * (udiv + 2) : 0);
160         Vertex *verts = new Vertex[vcount];
161         scalar_t yoffs = len / (vdiv + 1);
162
163         Vertex *vptr = verts;
164         for(int i=0; i<slices; i++) {
165                 for(int j=0; j<=udiv; j++) {
166                         vptr->pos = circle[j];
167                         vptr->pos.y += yoffs * i;
168                         vptr->normal = circle[j];
169                         vptr->normal.y = 0.0;
170                         vptr->normal /= rad;
171                         scalar_t u = (scalar_t)j / (scalar_t)udiv;
172                         scalar_t v = (scalar_t)i / (scalar_t)(vdiv + 1);
173                         vptr->tex[0] = vptr->tex[1] = TexCoord(u, v);
174                         vptr++;
175                 }
176         }
177
178         if(caps) {
179                 Vertex *cap1 = vptr;
180                 Vertex *cap2 = vptr + udiv + 2;
181                 
182                 for(int i=0; i<=udiv; i++) {
183                         circle[i].y = -len/2.0;
184                         cap1->pos = circle[i];
185                         cap1->normal = Vector3(0.0, -1.0, 0.0);
186                         //cap1->tex[0] = vptr->tex[1] = TexCoord((scalar_t)i / (scalar_t)udiv, 0.0);
187                         cap1->tex[0].u = cap1->tex[1].u = (cap1->pos.x / rad) * 0.5 + 0.5;
188                         cap1->tex[0].v = cap1->tex[1].v = (cap1->pos.z / rad) * 0.5 + 0.5;
189                         
190                         *cap2 = *cap1;
191                         cap2->pos.y = len/2.0;
192                         cap2->normal.y *= -1.0;
193                         //cap2->tex[0].v = cap2->tex[1].v = 1.0;
194
195                         cap1++;
196                         cap2++;
197                 }
198
199                 *cap1 = Vertex(Vector3(0.0, -len/2.0, 0.0), 0.5, 0.5);
200                 cap1->normal = Vector3(0.0, -1.0, 0.0);
201
202                 *cap2 = *cap1;
203                 cap2->pos.y = len/2.0;
204                 cap2->normal.y *= -1.0;
205                 //cap2->tex[0].v = cap2->tex[1].v = 1.0;
206         }
207         delete [] circle;
208
209         // triangulate
210         int tcount = 2 * udiv * (slices - 1) + (caps ? udiv * 2 : 0);
211         Triangle *triangles = new Triangle[tcount];
212         Triangle *tptr = triangles;
213         int v = 0;
214         for(int i=0; i<slices-1; i++) {
215                 for(int j=0; j<udiv; j++) {
216                         *tptr++ = Triangle(v + udiv + 1, v + 1, v + udiv + 2);
217                         *tptr++ = Triangle(v + udiv + 1, v, v + 1);
218                         v++;
219                 }
220                 v++;
221         }
222
223         if(caps) {
224                 v += udiv + 1;
225                 int v2 = v + udiv + 2;
226                 Triangle *tcap2 = tptr + udiv;
227                 for(int i=0; i<udiv; i++) {
228                         *tptr++ = Triangle(v + udiv + 1, v + i + 1, v + i);
229                         *tcap2++ = Triangle(v2 + udiv + 1, v2 + i, v2 + i + 1);
230                 }               
231         }
232         
233         mesh->set_data(verts, vcount, triangles, tcount);
234
235         delete [] verts;
236         delete [] triangles;
237 }
238
239 /* CreateSphere - (MG)
240  * creates a sphere as a solid of revolution
241  */
242 void create_sphere(TriMesh *mesh, scalar_t radius, int subdiv) {
243         // Solid of revolution. A slice of pi rads is rotated
244         // for 2pi rads. Subdiv in this revolution should be
245         // double than subdiv of the slice, because the angle
246         // is double.
247
248         unsigned long edges_pi  = 2 * subdiv;
249         unsigned long edges_2pi = 4 * subdiv;
250         
251         unsigned long vcount_pi  = edges_pi  + 1;
252         unsigned long vcount_2pi = edges_2pi + 1;
253
254         unsigned long vcount = vcount_pi * vcount_2pi;
255         
256         unsigned long quad_count = edges_pi * edges_2pi;
257         unsigned long tcount = quad_count * 2;
258         
259         Vertex *varray = new Vertex[vcount];
260         Triangle *tarray = new Triangle[tcount];
261
262         for(unsigned long j = 0; j < vcount_pi; j++) {
263                 for(unsigned long i = 0; i < vcount_2pi; i++) {
264
265                         Vector3 up_vec(0,1,0);
266
267                         scalar_t rotx,roty;
268                         rotx = -(pi * j) / (vcount_pi - 1);
269                         roty = -(two_pi * i) / (vcount_2pi - 1);
270                         
271                         Matrix4x4 rot_mat;
272                         rot_mat.set_rotation(Vector3(rotx, 0, 0));
273                         up_vec.transform(rot_mat);
274                         rot_mat.set_rotation(Vector3(0, roty, 0));
275                         up_vec.transform(rot_mat);
276
277                         scalar_t u = (scalar_t)i / (scalar_t)(vcount_2pi - 1);
278                         scalar_t v = 1.0 - (scalar_t)j / (scalar_t)(vcount_pi - 1);
279                         varray[j * vcount_2pi + i] = Vertex(up_vec * radius, u, v, Color(1.0f));
280                         varray[j * vcount_2pi + i].normal = up_vec; 
281                 }
282         }
283
284         // first seperate the quads and then triangulate
285         Quad *quads = new Quad[quad_count];
286
287         for(unsigned long i=0; i<quad_count; i++) {
288
289                 unsigned long hor_edge,vert_edge;
290                 hor_edge  = i % edges_2pi;
291                 vert_edge = i / edges_2pi;
292                 
293                 quads[i].vertices[0] = hor_edge + vert_edge * vcount_2pi;
294                 quads[i].vertices[1] = quads[i].vertices[0] + 1;
295                 quads[i].vertices[2] = quads[i].vertices[0] + vcount_2pi;
296                 quads[i].vertices[3] = quads[i].vertices[1] + vcount_2pi;
297         }
298
299         for(unsigned long i=0; i<quad_count; i++) {
300                 tarray[i * 2] = Triangle(quads[i].vertices[0], quads[i].vertices[1], quads[i].vertices[3]);
301                 tarray[i * 2 + 1] = Triangle(quads[i].vertices[0], quads[i].vertices[3], quads[i].vertices[2]);
302         }
303
304         mesh->set_data(varray, vcount, tarray, tcount);
305
306         delete [] quads;
307         delete [] varray;
308         delete [] tarray;
309 }
310
311 /* CreateTorus - (MG)
312  * Creates a toroid mesh
313  */
314 void create_torus(TriMesh *mesh, scalar_t circle_rad, scalar_t revolv_rad, int subdiv) {
315         unsigned long edges_2pi  = 4 * subdiv;
316         unsigned long vcount_2pi = edges_2pi + 1;
317
318         unsigned long vcount = vcount_2pi * vcount_2pi;
319         unsigned long qcount = edges_2pi * edges_2pi;
320         unsigned long tcount = qcount * 2;
321
322         // alloc mamory
323         Vertex   *varray = new Vertex[vcount];
324         Quad     *qarray = new Quad[qcount];
325         Triangle *tarray = new Triangle[tcount];
326         Vertex   *circle = new Vertex[vcount_2pi];
327         
328         // first create a circle
329         // rotation of this circle will produce the torus
330         for (unsigned long i = 0; i < vcount_2pi; i++)
331         {
332                 scalar_t t = (scalar_t)i / (scalar_t)(vcount_2pi - 1);
333                 
334                 Vector3 up_vec = Vector3(0, 1, 0);
335                 Matrix4x4 rot_mat;
336                 rot_mat.set_rotation(Vector3(0, 0, two_pi * t));
337                 up_vec.transform(rot_mat);
338
339                 Vector3 pos_vec = up_vec * circle_rad;
340                 pos_vec += Vector3(revolv_rad, 0, 0);
341
342                 circle[i] = Vertex(pos_vec, 0, t, Color(1.0f));
343                 circle[i].normal = up_vec;
344         }
345
346         // vertex loop
347         for (unsigned long j = 0; j < vcount_2pi; j++)
348         {
349                 for (unsigned long i = 0; i < vcount_2pi; i++)
350                 {
351                         scalar_t t = (scalar_t)i / (scalar_t)(vcount_2pi - 1);
352                         
353                         Vector3 pos,nor;
354                         pos = circle[j].pos;
355                         nor = circle[j].normal;
356
357                         Matrix4x4 rot_mat;
358                         rot_mat.set_rotation(Vector3(0, two_pi * t, 0));
359                         pos.transform(rot_mat);
360                         nor.transform(rot_mat);
361
362                         unsigned long index = i + vcount_2pi * j;
363
364                         varray[index] = Vertex(pos, t, 1.0 - circle[j].tex[0].v, Color(1.0f));
365                         varray[index].normal = nor;
366                 }
367         } // End vertex loop
368
369         
370         for(unsigned long i=0; i<qcount; i++) {
371
372                 unsigned long hor_edge,vert_edge;
373                 hor_edge  = i % edges_2pi;
374                 vert_edge = i / edges_2pi;
375                 
376                 qarray[i].vertices[0] = hor_edge + vert_edge * vcount_2pi;
377                 qarray[i].vertices[1] = qarray[i].vertices[0] + 1;
378                 qarray[i].vertices[2] = qarray[i].vertices[0] + vcount_2pi;
379                 qarray[i].vertices[3] = qarray[i].vertices[1] + vcount_2pi;
380         }
381         
382         for(unsigned long i=0; i<qcount; i++) {
383                 tarray[i * 2] = Triangle(qarray[i].vertices[0], qarray[i].vertices[1], qarray[i].vertices[3]);
384                 tarray[i * 2 + 1] = Triangle(qarray[i].vertices[0], qarray[i].vertices[3], qarray[i].vertices[2]);
385         }
386
387         mesh->set_data(varray, vcount, tarray, tcount);
388         
389         // cleanup
390         delete [] varray;
391         delete [] qarray;
392         delete [] tarray;
393         delete [] circle;
394 }
395
396
397 /* create_revolution - (JT)
398  * Creates a surface of revolution by rotating a curve around the Y axis.
399  */
400 void create_revolution(TriMesh *mesh, const Curve &curve, int udiv, int vdiv) {
401         if(udiv < 3) udiv = 3;
402         if(vdiv < 1) vdiv = 1;
403
404         int slices = udiv;
405         int stacks = vdiv + 1;
406
407         // create the slice that will be revolved to create the mesh
408         Vector3 *slice = new Vector3[stacks];
409         Vector3 *slice_normal = new Vector3[stacks];
410         
411         for(int i=0; i<stacks; i++) {
412                 scalar_t t = (scalar_t)i / (scalar_t)vdiv;
413                 slice[i] = curve(t);
414
415                 // calculate normal
416                 Vector3 bitangent = (curve(t + 0.0001) - curve(t - 0.0001)).normalized();
417                 Vector3 tp1 = slice[i].rotated(Vector3(0.0, DEG_TO_RAD(3), 0.0));
418                 Vector3 tp2 = slice[i].rotated(Vector3(0.0, -DEG_TO_RAD(3), 0.0));
419                 Vector3 tangent = (tp1 - tp2).normalized();
420
421                 slice_normal[i] = cross_product(tangent, bitangent);
422         }
423         
424         int vcount = stacks * slices;
425         int quad_count = udiv * vdiv;
426         int tcount = quad_count * 2;
427         
428         Vertex *varray = new Vertex[vcount];
429         Triangle *tarray = new Triangle[tcount];
430
431         Vertex *vptr = varray;
432         Triangle *tptr = tarray;
433         
434         for(int i=0; i<slices; i++) {
435                 Matrix4x4 rot;
436                 rot.set_rotation(Vector3(0.0, two_pi * (scalar_t)i / (scalar_t)udiv, 0.0));
437                 
438                 for(int j=0; j<stacks; j++) {
439                         // create the vertex
440                         vptr->pos = slice[j].transformed(rot);
441                         vptr->tex[0].u = vptr->tex[1].u = (scalar_t)i / (scalar_t)udiv;
442                         vptr->tex[0].v = vptr->tex[1].v = (scalar_t)j / (scalar_t)vdiv;
443                         vptr->normal = slice_normal[j].transformed(rot);
444                         vptr++;
445
446                         if(j < vdiv) {
447                                 // create the quad
448                                 Quad q;
449                                 q.vertices[0] = j + (i % slices) * stacks;
450                                 q.vertices[1] = j + ((i + 1) % slices) * stacks;
451                                 q.vertices[2] = (j + 1) + ((i + 1) % slices) * stacks;
452                                 q.vertices[3] = (j + 1) + (i % slices) * stacks;
453
454                                 // triangulate
455                                 tptr->vertices[0] = q.vertices[0];
456                                 tptr->vertices[1] = q.vertices[1];
457                                 tptr->vertices[2] = q.vertices[2];
458                                 tptr++;
459                                 tptr->vertices[0] = q.vertices[0];
460                                 tptr->vertices[1] = q.vertices[2];
461                                 tptr->vertices[2] = q.vertices[3];
462                                 tptr++;
463                         }
464                 }
465         }
466
467         mesh->set_data(varray, vcount, tarray, tcount);
468         delete [] varray;
469         delete [] tarray;
470         delete [] slice;
471         delete [] slice_normal;
472 }
473
474 /* create_revolution - helper function - (JT)
475  * accepts an array of data points, fits a spline through them and passes the rest
476  * to the real create_revolution defined above.
477  */
478 void create_revolution(TriMesh *mesh, const Vector3 *data, int count, int udiv, int vdiv) {
479         CatmullRomSplineCurve spline;
480         for(int i=0; i<count; i++) {
481                 spline.add_control_point(data[i]);
482         }
483         spline.set_arc_parametrization(true);
484
485         create_revolution(mesh, spline, udiv, vdiv);
486 }
487
488 /* create_extrusion - (JT)
489  * Takes a shape and extrudes it along a path.
490  */
491 void create_extrusion(TriMesh *mesh, const Curve &shape, const Curve &path, int udiv, int vdiv, scalar_t start_scale, scalar_t end_scale) {
492         if(udiv < 3) udiv = 3;
493         Vector3 *shape_pt = new Vector3[udiv + 1];
494
495         for(int i=0; i<udiv; i++) {
496                 shape_pt[i] = shape((scalar_t)i / (scalar_t)udiv);
497         }
498         shape_pt[udiv] = shape_pt[0];
499
500         // extrude along the spline
501         int slices = vdiv + 2;
502         int vcount = (udiv + 1) * slices;
503         Vertex *verts = new Vertex[vcount];
504         scalar_t dt = 1.0 / (vdiv + 1);
505
506         Vertex *vptr = verts;
507         for(int i=0; i<slices; i++) {
508                 for(int j=0; j<=udiv; j++) {
509                         // XXX FIX THIS
510                         vptr->pos = shape_pt[j];
511                         vptr->pos.y += dt * i;
512                         scalar_t u = (scalar_t)j / (scalar_t)udiv;
513                         scalar_t v = (scalar_t)i / (scalar_t)(vdiv + 1);
514                         vptr->tex[0] = vptr->tex[1] = TexCoord(u, v);
515                         vptr++;
516                 }
517         }
518
519         delete [] shape_pt;
520
521         // triangulate
522         int tcount = 2 * udiv * (slices - 1);
523         Triangle *triangles = new Triangle[tcount];
524         Triangle *tptr = triangles;
525         int v = 0;
526         for(int i=0; i<slices-1; i++) {
527                 for(int j=0; j<udiv; j++) {
528                         *tptr++ = Triangle(v + udiv + 1, v + 1, v + udiv + 2);
529                         *tptr++ = Triangle(v + udiv + 1, v, v + 1);
530                         v++;
531                 }
532                 v++;
533         }
534
535         mesh->set_data(verts, vcount, triangles, tcount);
536         mesh->calculate_normals();
537
538         delete [] verts;
539         delete [] triangles;
540 }
541
542 /* CreateBezierPatch - (MG)
543  * overloaded function that gets a vector3 array
544  * and makes a single Bezier patch
545  */
546 void create_bezier_patch(TriMesh *mesh, const Vector3 *cp, int subdiv)
547 {
548
549         // make 8 BezierSpline's
550         BezierSpline u[4], v[4];
551
552         u[0].add_control_point(cp[0]);
553         u[0].add_control_point(cp[1]);
554         u[0].add_control_point(cp[2]);  
555         u[0].add_control_point(cp[3]);
556         
557         u[1].add_control_point(cp[4]);
558         u[1].add_control_point(cp[5]);
559         u[1].add_control_point(cp[6]);  
560         u[1].add_control_point(cp[7]);
561         
562         u[2].add_control_point(cp[8]);
563         u[2].add_control_point(cp[9]);
564         u[2].add_control_point(cp[10]); 
565         u[2].add_control_point(cp[11]);
566         
567         u[3].add_control_point(cp[12]);
568         u[3].add_control_point(cp[13]);
569         u[3].add_control_point(cp[14]); 
570         u[3].add_control_point(cp[15]);
571
572         v[0].add_control_point(cp[0]);
573         v[0].add_control_point(cp[4]);
574         v[0].add_control_point(cp[8]);  
575         v[0].add_control_point(cp[12]);
576         
577         v[1].add_control_point(cp[1]);
578         v[1].add_control_point(cp[5]);
579         v[1].add_control_point(cp[9]);  
580         v[1].add_control_point(cp[13]);
581         
582         v[2].add_control_point(cp[2]);
583         v[2].add_control_point(cp[6]);
584         v[2].add_control_point(cp[10]); 
585         v[2].add_control_point(cp[14]);
586
587         v[3].add_control_point(cp[3]);
588         v[3].add_control_point(cp[7]);
589         v[3].add_control_point(cp[11]); 
590         v[3].add_control_point(cp[15]);
591
592         unsigned long edges = subdiv * 2;
593         unsigned long vrow = edges + 1;
594         unsigned long qcount = edges * edges;
595         unsigned long vcount = vrow * vrow;
596         unsigned long tcount = qcount * 2;
597
598         // allocate memory
599         Vertex *varray = new Vertex[vcount];
600         Quad *qarray = new Quad[qcount];
601         Triangle *tarray = new Triangle[tcount];
602
603         // Vertex loop
604         for (unsigned long j=0; j<vrow; j++)
605         {
606                 scalar_t tv = (scalar_t)j / (scalar_t)(vrow - 1);
607                 BezierSpline uc;
608                 uc.add_control_point(v[0](tv));
609                 uc.add_control_point(v[1](tv));
610                 uc.add_control_point(v[2](tv));
611                 uc.add_control_point(v[3](tv));
612                 
613                 for (unsigned long i=0; i<vrow; i++)
614                 {
615                         scalar_t tu = (scalar_t)i / (scalar_t)(vrow - 1);
616                         BezierSpline vc;
617                         vc.add_control_point(u[0](tu));
618                         vc.add_control_point(u[1](tu));
619                         vc.add_control_point(u[2](tu));
620                         vc.add_control_point(u[3](tu));
621
622                         // get the position
623                         Vector3 pos = uc(tu);
624
625                         // get normal
626                         Vector3 tan_u,tan_v;
627                         tan_u = uc.get_tangent(tu);
628                         tan_v = vc.get_tangent(tv);
629                         Vector3 normal;
630                         normal = cross_product(tan_u, tan_v);
631                         normal.normalize();
632
633                         // store vertex
634                         varray[i + j * vrow] = Vertex(pos, tu, 1.0 - tv, Color(1.0f));
635                         varray[i + j * vrow].normal = normal;
636                 }
637         } // end vertex loop
638
639         
640         // first seperate the quads and then triangulate
641         for(unsigned long i=0; i<qcount; i++) {
642                 qarray[i].vertices[0] = i + i / edges;
643                 qarray[i].vertices[1] = qarray[i].vertices[0] + 1;
644                 qarray[i].vertices[2] = qarray[i].vertices[0] + vrow;
645                 qarray[i].vertices[3] = qarray[i].vertices[1] + vrow;
646         }
647
648         for(unsigned long i=0; i<qcount; i++) {
649                 tarray[i * 2] = Triangle(qarray[i].vertices[0], qarray[i].vertices[1], qarray[i].vertices[3]);
650                 tarray[i * 2 + 1] = Triangle(qarray[i].vertices[0], qarray[i].vertices[3], qarray[i].vertices[2]);
651         }
652
653         mesh->set_data(varray, vcount, tarray, tcount);
654         
655         // cleanup
656         delete [] varray;
657         delete [] qarray;
658         delete [] tarray;
659 }
660
661 /* CreateBezierPatch - (MG)
662  * creates a bezier patch (!)
663  * if the control curves contain more than one 
664  * segments, multiple patches will be included
665  * in the output TriMesh
666  */
667 void create_bezier_patch(TriMesh *mesh, const BezierSpline &u0, const BezierSpline &u1, const BezierSpline &u2, const BezierSpline &u3, int subdiv)
668 {
669         // get minimum number of segments
670         unsigned long min_seg , tmp;
671         min_seg = u0.get_segment_count();
672         tmp = u1.get_segment_count(); if (min_seg > tmp) min_seg = tmp;
673         tmp = u2.get_segment_count(); if (min_seg > tmp) min_seg = tmp;
674         tmp = u3.get_segment_count(); if (min_seg > tmp) min_seg = tmp;
675
676         TriMesh tmp_mesh;
677         Vector3 *cp = new Vector3[16];
678         for (unsigned long i=0; i<min_seg; i++)
679         {
680                 // fill control point array
681                 cp[0] = u0.get_control_point(4 * i + 0);
682                 cp[1] = u0.get_control_point(4 * i + 1);
683                 cp[2] = u0.get_control_point(4 * i + 2);
684                 cp[3] = u0.get_control_point(4 * i + 3);
685
686                 cp[4] = u1.get_control_point(4 * i + 0);
687                 cp[5] = u1.get_control_point(4 * i + 1);
688                 cp[6] = u1.get_control_point(4 * i + 2);
689                 cp[7] = u1.get_control_point(4 * i + 3);
690                 
691                 cp[8] = u2.get_control_point(4 * i + 0);
692                 cp[9] = u2.get_control_point(4 * i + 1);
693                 cp[10] = u2.get_control_point(4 * i + 2);
694                 cp[11] = u2.get_control_point(4 * i + 3);
695                         
696                 cp[12] = u3.get_control_point(4 * i + 0);
697                 cp[13] = u3.get_control_point(4 * i + 1);
698                 cp[14] = u3.get_control_point(4 * i + 2);
699                 cp[15] = u3.get_control_point(4 * i + 3);
700
701                 // Make a single patch and put all patches together     
702                 create_bezier_patch(&tmp_mesh, cp, subdiv);
703
704                 join_tri_mesh(mesh, mesh, &tmp_mesh);
705         }
706
707         // cleanup
708         delete [] cp;
709 }
710
711 /* CreateBezierMesh - (MG)
712  * tesselates a whole mesh of bezier patches.
713  * usefull when some patches share vertices
714  * TODO : Make a bezier patch class , like Triangle
715  * and Quad. Store indices
716  */
717 void create_bezier_mesh(TriMesh *mesh, const Vector3 *cp, unsigned int *patches, int patch_count, int subdiv)
718 {
719         TriMesh tmp_mesh;
720         Vector3 control_pts[16];
721         for(int i=0; i<patch_count; i++)
722         {
723                 for(int j=0; j<16; j++)
724                 {
725                         control_pts[j] = cp[ patches[16 * i + j] ];
726                 }
727
728                 create_bezier_patch(&tmp_mesh, control_pts, subdiv);
729
730                 join_tri_mesh(mesh, mesh, &tmp_mesh);
731         }
732 }
733
734 /* CreateTeapot - (MG)
735  * Creates a teapot TriMesh, using the original
736  * data file from Newell
737  */
738 void create_teapot(TriMesh *mesh, scalar_t size, int subdiv)
739 {
740         unsigned int *patches = new unsigned int[teapot_num_patches * 16];
741         
742         // fix indices to start from zero
743         for(int i=0; i<teapot_num_patches * 16; i++)
744         {
745                 patches[i] = teapot_patches[i] - 1;
746         }
747
748                 
749         // rearrange patches to clockwise order
750         for(int p=0; p<teapot_num_patches; p++)
751         {
752                 unsigned int new_order[16];
753                 for(int j=0; j<4; j++)
754                 {
755                         for(int i=0; i<4; i++)
756                         {
757                                 new_order[j * 4 + (3 - i)] = patches[p * 16 + j * 4 + i];
758                         }
759                 }
760
761                 for(int k=0; k<16; k++)
762                 {
763                         patches[16 * p + k] = new_order[k];
764                 }
765         }
766
767         // rearrange vertices to correct axes
768         Vector3 *vertices = new Vector3[teapot_num_vertices];
769         for(int i = 0; i < teapot_num_vertices; i++)
770         {
771                 vertices[i].x = teapot_vertices[i * 3 + 0] * size;
772                 vertices[i].z = teapot_vertices[i * 3 + 1] * size;
773                 vertices[i].y = teapot_vertices[i * 3 + 2] * size;
774         }
775         
776         create_bezier_mesh(mesh, vertices, patches, teapot_num_patches, subdiv);
777
778         mesh->calculate_normals();
779
780         // cleanup
781         delete [] patches;
782         delete [] vertices;
783 }
784
785
786 // fractal stuff ...
787
788 /* create_landscape (JT)
789  * Creates a fractal landscape... (TODO: add algorithm description or something)
790  */
791 void create_landscape(TriMesh *mesh, const Vector2 &size, int mesh_detail, scalar_t max_height, int iter, scalar_t roughness, int seed) {
792         create_plane(mesh, Vector3(0, 1, 0), size, mesh_detail);
793         roughness *= 0.25;
794
795         if(seed == GGEN_RANDOM_SEED) {
796                 srand(time(0));
797         } else if(seed != GGEN_NO_RESEED) {
798                 srand(seed);
799         }
800
801         scalar_t offs = max_height / (scalar_t)iter;
802
803         unsigned long vcount = mesh->get_vertex_array()->get_count();
804         Vertex *varray = mesh->get_mod_vertex_array()->get_mod_data();
805
806         for(int i=0; i<iter; i++) {
807                 // pick a partitioning line (2d)
808                 Vector2 pt1(frand(size.x) - size.x / 2.0, frand(size.y) - size.y / 2.0);
809                 Vector2 pt2(frand(size.x) - size.x / 2.0, frand(size.y) - size.y / 2.0);
810
811                 // find its normal
812                 Vector2 normal(pt2.y - pt1.y, pt1.x - pt2.x);
813
814                 // classify all points wrt. this line and raise them accordingly.
815                 for(unsigned long j=0; j<vcount; j++) {
816                         Vector3 *vpos = &varray[j].pos;
817                         Vector2 vpos2d(vpos->x, vpos->z);
818                         
819                         scalar_t dist = dist_line(pt1, pt2, vpos2d);
820                         
821                         /* this was considered but it was producing extremely smooth
822                          * results, which looked unnatural.
823                          */
824                         /* 
825                         if(dot_product(normal, vpos2d - pt1) < 0.0) {
826                                 dist = -dist;
827                         }
828                         scalar_t sigmoid = (tanh(dist * size.x * size.y * roughness) + 1.0) * 0.5;
829                         vpos->y += offs * sigmoid;
830                         */
831
832                         if(dot_product(normal, vpos2d - pt1) > 0.0) {
833                                 scalar_t sigmoid = tanh(dist * size.x * size.y * roughness);
834                                 vpos->y += offs * sigmoid;
835                         }
836                 }
837         }
838
839         // normalize the landscape in the range [0, max_height)
840         scalar_t hmin = FLT_MAX, hmax = 0.0;
841         Vertex *vptr = varray;
842
843         for(unsigned long i=0; i<vcount; i++) {
844                 if(vptr->pos.y > hmax) hmax = vptr->pos.y;
845                 if(vptr->pos.y < hmin) hmin = vptr->pos.y;
846                 vptr++;
847         }
848
849         vptr = varray;
850         for(unsigned long i=0; i<vcount; i++) {
851                 vptr->pos.y = max_height * (vptr->pos.y - hmin) / (hmax - hmin);
852                 vptr++;
853         }
854
855         mesh->calculate_normals();
856 }