cubemapper

view src/meshgen.cc @ 5:614295b72341

minor fixes, and redundant code removal
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 30 Jul 2017 16:16:57 +0300
parents 8fc9e1d3aad2
children
line source
1 /*
2 Cubemapper - a program for converting panoramic images into cubemaps
3 Copyright (C) 2017 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <stdio.h>
19 #include "meshgen.h"
20 #include "mesh.h"
22 // -------- sphere --------
24 #define SURAD(u) ((u) * 2.0 * M_PI)
25 #define SVRAD(v) ((v) * M_PI)
27 static Vec3 sphvec(float theta, float phi)
28 {
29 return Vec3(sin(theta) * sin(phi),
30 cos(phi),
31 cos(theta) * sin(phi));
32 }
34 void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange, float vrange)
35 {
36 if(usub < 4) usub = 4;
37 if(vsub < 2) vsub = 2;
39 int uverts = usub + 1;
40 int vverts = vsub + 1;
42 int num_verts = uverts * vverts;
43 int num_quads = usub * vsub;
44 int num_tri = num_quads * 2;
46 mesh->clear();
47 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
48 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
49 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
50 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
51 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
53 float du = urange / (float)(uverts - 1);
54 float dv = vrange / (float)(vverts - 1);
56 float u = 0.0;
57 for(int i=0; i<uverts; i++) {
58 float theta = u * 2.0 * M_PI;
60 float v = 0.0;
61 for(int j=0; j<vverts; j++) {
62 float phi = v * M_PI;
64 Vec3 pos = sphvec(theta, phi);
66 *varr++ = pos * rad;
67 *narr++ = pos;
68 *tarr++ = normalize(sphvec(theta + 0.1f, (float)M_PI / 2.0f) - sphvec(theta - 0.1f, (float)M_PI / 2.0f));
69 *uvarr++ = Vec2(u * urange, v * vrange);
71 if(i < usub && j < vsub) {
72 int idx = i * vverts + j;
73 *idxarr++ = idx;
74 *idxarr++ = idx + 1;
75 *idxarr++ = idx + vverts + 1;
77 *idxarr++ = idx;
78 *idxarr++ = idx + vverts + 1;
79 *idxarr++ = idx + vverts;
80 }
82 v += dv;
83 }
84 u += du;
85 }
86 }
88 // ------ geosphere ------
89 #define PHI 1.618034
91 static Vec3 icosa_pt[] = {
92 Vec3(PHI, 1, 0),
93 Vec3(-PHI, 1, 0),
94 Vec3(PHI, -1, 0),
95 Vec3(-PHI, -1, 0),
96 Vec3(1, 0, PHI),
97 Vec3(1, 0, -PHI),
98 Vec3(-1, 0, PHI),
99 Vec3(-1, 0, -PHI),
100 Vec3(0, PHI, 1),
101 Vec3(0, -PHI, 1),
102 Vec3(0, PHI, -1),
103 Vec3(0, -PHI, -1)
104 };
105 enum { P11, P12, P13, P14, P21, P22, P23, P24, P31, P32, P33, P34 };
106 static int icosa_idx[] = {
107 P11, P31, P21,
108 P11, P22, P33,
109 P13, P21, P32,
110 P13, P34, P22,
111 P12, P23, P31,
112 P12, P33, P24,
113 P14, P32, P23,
114 P14, P24, P34,
116 P11, P33, P31,
117 P12, P31, P33,
118 P13, P32, P34,
119 P14, P34, P32,
121 P21, P13, P11,
122 P22, P11, P13,
123 P23, P12, P14,
124 P24, P14, P12,
126 P31, P23, P21,
127 P32, P21, P23,
128 P33, P22, P24,
129 P34, P24, P22
130 };
132 static void geosphere(std::vector<Vec3> *verts, const Vec3 &v1, const Vec3 &v2, const Vec3 &v3, int iter)
133 {
134 if(!iter) {
135 verts->push_back(v1);
136 verts->push_back(v2);
137 verts->push_back(v3);
138 return;
139 }
141 Vec3 v12 = normalize(v1 + v2);
142 Vec3 v23 = normalize(v2 + v3);
143 Vec3 v31 = normalize(v3 + v1);
145 geosphere(verts, v1, v12, v31, iter - 1);
146 geosphere(verts, v2, v23, v12, iter - 1);
147 geosphere(verts, v3, v31, v23, iter - 1);
148 geosphere(verts, v12, v23, v31, iter - 1);
149 }
151 void gen_geosphere(Mesh *mesh, float rad, int subdiv, bool hemi)
152 {
153 int num_tri = (sizeof icosa_idx / sizeof *icosa_idx) / 3;
155 std::vector<Vec3> verts;
156 for(int i=0; i<num_tri; i++) {
157 Vec3 v[3];
159 for(int j=0; j<3; j++) {
160 int vidx = icosa_idx[i * 3 + j];
161 v[j] = normalize(icosa_pt[vidx]);
162 }
164 if(hemi && (v[0].y < 0.0 || v[1].y < 0.0 || v[2].y < 0.0)) {
165 continue;
166 }
168 geosphere(&verts, v[0], v[1], v[2], subdiv);
169 }
171 int num_verts = (int)verts.size();
173 mesh->clear();
174 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
175 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
176 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
177 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
179 for(int i=0; i<num_verts; i++) {
180 *varr++ = verts[i] * rad;
181 *narr++ = verts[i];
183 float theta = atan2(verts[i].z, verts[i].x);
184 float phi = acos(verts[i].y);
186 *tarr++ = normalize(sphvec(theta + 0.1f, (float)M_PI / 2.0f) - sphvec(theta - 0.1f, (float)M_PI / 2.0f));
188 float u = 0.5 * theta / M_PI + 0.5;
189 float v = phi / M_PI;
190 *uvarr++ = Vec2(u, v);
191 }
192 }
194 // -------- torus -----------
195 static Vec3 torusvec(float theta, float phi, float mr, float rr)
196 {
197 theta = -theta;
199 float rx = -cos(phi) * rr + mr;
200 float ry = sin(phi) * rr;
201 float rz = 0.0;
203 float x = rx * sin(theta) + rz * cos(theta);
204 float y = ry;
205 float z = -rx * cos(theta) + rz * sin(theta);
207 return Vec3(x, y, z);
208 }
210 void gen_torus(Mesh *mesh, float mainrad, float ringrad, int usub, int vsub, float urange, float vrange)
211 {
212 if(usub < 4) usub = 4;
213 if(vsub < 2) vsub = 2;
215 int uverts = usub + 1;
216 int vverts = vsub + 1;
218 int num_verts = uverts * vverts;
219 int num_quads = usub * vsub;
220 int num_tri = num_quads * 2;
222 mesh->clear();
223 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
224 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
225 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
226 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
227 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
229 float du = urange / (float)(uverts - 1);
230 float dv = vrange / (float)(vverts - 1);
232 float u = 0.0;
233 for(int i=0; i<uverts; i++) {
234 float theta = u * 2.0 * M_PI;
236 float v = 0.0;
237 for(int j=0; j<vverts; j++) {
238 float phi = v * 2.0 * M_PI;
240 Vec3 pos = torusvec(theta, phi, mainrad, ringrad);
241 Vec3 cent = torusvec(theta, phi, mainrad, 0.0);
243 *varr++ = pos;
244 *narr++ = (pos - cent) / ringrad;
246 Vec3 pprev = torusvec(theta - 0.1f, phi, mainrad, ringrad);
247 Vec3 pnext = torusvec(theta + 0.1f, phi, mainrad, ringrad);
249 *tarr++ = normalize(pnext - pprev);
250 *uvarr++ = Vec2(u * urange, v * vrange);
252 if(i < usub && j < vsub) {
253 int idx = i * vverts + j;
254 *idxarr++ = idx;
255 *idxarr++ = idx + 1;
256 *idxarr++ = idx + vverts + 1;
258 *idxarr++ = idx;
259 *idxarr++ = idx + vverts + 1;
260 *idxarr++ = idx + vverts;
261 }
263 v += dv;
264 }
265 u += du;
266 }
267 }
270 // -------- cylinder --------
272 static Vec3 cylvec(float theta, float height)
273 {
274 return Vec3(sin(theta), height, cos(theta));
275 }
277 void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
278 {
279 if(usub < 4) usub = 4;
280 if(vsub < 1) vsub = 1;
282 int uverts = usub + 1;
283 int vverts = vsub + 1;
285 int num_body_verts = uverts * vverts;
286 int num_body_quads = usub * vsub;
287 int num_body_tri = num_body_quads * 2;
289 int capvverts = capsub ? capsub + 1 : 0;
290 int num_cap_verts = uverts * capvverts;
291 int num_cap_quads = usub * capsub;
292 int num_cap_tri = num_cap_quads * 2;
294 int num_verts = num_body_verts + num_cap_verts * 2;
295 int num_tri = num_body_tri + num_cap_tri * 2;
297 mesh->clear();
298 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
299 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
300 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
301 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
302 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
304 float du = urange / (float)(uverts - 1);
305 float dv = vrange / (float)(vverts - 1);
307 float u = 0.0;
308 for(int i=0; i<uverts; i++) {
309 float theta = SURAD(u);
311 float v = 0.0;
312 for(int j=0; j<vverts; j++) {
313 float y = (v - 0.5) * height;
314 Vec3 pos = cylvec(theta, y);
316 *varr++ = Vec3(pos.x * rad, pos.y, pos.z * rad);
317 *narr++ = Vec3(pos.x, 0.0, pos.z);
318 *tarr++ = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0));
319 *uvarr++ = Vec2(u * urange, v * vrange);
321 if(i < usub && j < vsub) {
322 int idx = i * vverts + j;
324 *idxarr++ = idx;
325 *idxarr++ = idx + vverts + 1;
326 *idxarr++ = idx + 1;
328 *idxarr++ = idx;
329 *idxarr++ = idx + vverts;
330 *idxarr++ = idx + vverts + 1;
331 }
333 v += dv;
334 }
335 u += du;
336 }
339 // now the cap!
340 if(!capsub) {
341 return;
342 }
344 dv = 1.0 / (float)(capvverts - 1);
346 u = 0.0;
347 for(int i=0; i<uverts; i++) {
348 float theta = SURAD(u);
350 float v = 0.0;
351 for(int j=0; j<capvverts; j++) {
352 float r = v * rad;
354 Vec3 pos = cylvec(theta, height / 2.0) * r;
355 pos.y = height / 2.0;
356 Vec3 tang = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0));
358 *varr++ = pos;
359 *narr++ = Vec3(0, 1, 0);
360 *tarr++ = tang;
361 *uvarr++ = Vec2(u * urange, v);
363 pos.y = -height / 2.0;
364 *varr++ = pos;
365 *narr++ = Vec3(0, -1, 0);
366 *tarr++ = -tang;
367 *uvarr++ = Vec2(u * urange, v);
369 if(i < usub && j < capsub) {
370 unsigned int idx = num_body_verts + (i * capvverts + j) * 2;
372 unsigned int vidx[4] = {
373 idx,
374 idx + capvverts * 2,
375 idx + (capvverts + 1) * 2,
376 idx + 2
377 };
379 *idxarr++ = vidx[0];
380 *idxarr++ = vidx[2];
381 *idxarr++ = vidx[1];
382 *idxarr++ = vidx[0];
383 *idxarr++ = vidx[3];
384 *idxarr++ = vidx[2];
386 *idxarr++ = vidx[0] + 1;
387 *idxarr++ = vidx[1] + 1;
388 *idxarr++ = vidx[2] + 1;
389 *idxarr++ = vidx[0] + 1;
390 *idxarr++ = vidx[2] + 1;
391 *idxarr++ = vidx[3] + 1;
392 }
394 v += dv;
395 }
396 u += du;
397 }
398 }
400 // -------- cone --------
402 static Vec3 conevec(float theta, float y, float height)
403 {
404 float scale = 1.0 - y / height;
405 return Vec3(sin(theta) * scale, y, cos(theta) * scale);
406 }
408 void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
409 {
410 if(usub < 4) usub = 4;
411 if(vsub < 1) vsub = 1;
413 int uverts = usub + 1;
414 int vverts = vsub + 1;
416 int num_body_verts = uverts * vverts;
417 int num_body_quads = usub * vsub;
418 int num_body_tri = num_body_quads * 2;
420 int capvverts = capsub ? capsub + 1 : 0;
421 int num_cap_verts = uverts * capvverts;
422 int num_cap_quads = usub * capsub;
423 int num_cap_tri = num_cap_quads * 2;
425 int num_verts = num_body_verts + num_cap_verts;
426 int num_tri = num_body_tri + num_cap_tri;
428 mesh->clear();
429 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
430 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
431 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
432 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
433 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
435 float du = urange / (float)(uverts - 1);
436 float dv = vrange / (float)(vverts - 1);
438 float u = 0.0;
439 for(int i=0; i<uverts; i++) {
440 float theta = SURAD(u);
442 float v = 0.0;
443 for(int j=0; j<vverts; j++) {
444 float y = v * height;
445 Vec3 pos = conevec(theta, y, height);
447 Vec3 tang = normalize(conevec(theta + 0.1, 0.0, height) - conevec(theta - 0.1, 0.0, height));
448 Vec3 bitang = normalize(conevec(theta, y + 0.1, height) - pos);
450 *varr++ = Vec3(pos.x * rad, pos.y, pos.z * rad);
451 *narr++ = cross(tang, bitang);
452 *tarr++ = tang;
453 *uvarr++ = Vec2(u * urange, v * vrange);
455 if(i < usub && j < vsub) {
456 int idx = i * vverts + j;
458 *idxarr++ = idx;
459 *idxarr++ = idx + vverts + 1;
460 *idxarr++ = idx + 1;
462 *idxarr++ = idx;
463 *idxarr++ = idx + vverts;
464 *idxarr++ = idx + vverts + 1;
465 }
467 v += dv;
468 }
469 u += du;
470 }
473 // now the bottom cap!
474 if(!capsub) {
475 return;
476 }
478 dv = 1.0 / (float)(capvverts - 1);
480 u = 0.0;
481 for(int i=0; i<uverts; i++) {
482 float theta = SURAD(u);
484 float v = 0.0;
485 for(int j=0; j<capvverts; j++) {
486 float r = v * rad;
488 Vec3 pos = conevec(theta, 0.0, height) * r;
489 Vec3 tang = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0));
491 *varr++ = pos;
492 *narr++ = Vec3(0, -1, 0);
493 *tarr++ = tang;
494 *uvarr++ = Vec2(u * urange, v);
496 if(i < usub && j < capsub) {
497 unsigned int idx = num_body_verts + i * capvverts + j;
499 unsigned int vidx[4] = {
500 idx,
501 idx + capvverts,
502 idx + (capvverts + 1),
503 idx + 1
504 };
506 *idxarr++ = vidx[0];
507 *idxarr++ = vidx[1];
508 *idxarr++ = vidx[2];
509 *idxarr++ = vidx[0];
510 *idxarr++ = vidx[2];
511 *idxarr++ = vidx[3];
512 }
514 v += dv;
515 }
516 u += du;
517 }
518 }
521 // -------- plane --------
523 void gen_plane(Mesh *mesh, float width, float height, int usub, int vsub)
524 {
525 gen_heightmap(mesh, width, height, usub, vsub, 0);
526 }
529 // ----- heightmap ------
531 void gen_heightmap(Mesh *mesh, float width, float height, int usub, int vsub, float (*hf)(float, float, void*), void *hfdata)
532 {
533 if(usub < 1) usub = 1;
534 if(vsub < 1) vsub = 1;
536 mesh->clear();
538 int uverts = usub + 1;
539 int vverts = vsub + 1;
540 int num_verts = uverts * vverts;
542 int num_quads = usub * vsub;
543 int num_tri = num_quads * 2;
545 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
546 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
547 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
548 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
549 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
551 float du = 1.0 / (float)usub;
552 float dv = 1.0 / (float)vsub;
554 float u = 0.0;
555 for(int i=0; i<uverts; i++) {
556 float v = 0.0;
557 for(int j=0; j<vverts; j++) {
558 float x = (u - 0.5) * width;
559 float y = (v - 0.5) * height;
560 float z = hf ? hf(u, v, hfdata) : 0.0;
562 Vec3 normal = Vec3(0, 0, 1);
563 if(hf) {
564 float u1z = hf(u + du, v, hfdata);
565 float v1z = hf(u, v + dv, hfdata);
567 Vec3 tang = Vec3(du * width, 0, u1z - z);
568 Vec3 bitan = Vec3(0, dv * height, v1z - z);
569 normal = normalize(cross(tang, bitan));
570 }
572 *varr++ = Vec3(x, y, z);
573 *narr++ = normal;
574 *tarr++ = Vec3(1, 0, 0);
575 *uvarr++ = Vec2(u, v);
577 if(i < usub && j < vsub) {
578 int idx = i * vverts + j;
580 *idxarr++ = idx;
581 *idxarr++ = idx + vverts + 1;
582 *idxarr++ = idx + 1;
584 *idxarr++ = idx;
585 *idxarr++ = idx + vverts;
586 *idxarr++ = idx + vverts + 1;
587 }
589 v += dv;
590 }
591 u += du;
592 }
593 }
595 // ----- box ------
596 void gen_box(Mesh *mesh, float xsz, float ysz, float zsz, int usub, int vsub)
597 {
598 static const float face_angles[][2] = {
599 {0, 0},
600 {M_PI / 2.0, 0},
601 {M_PI, 0},
602 {3.0 * M_PI / 2.0, 0},
603 {0, M_PI / 2.0},
604 {0, -M_PI / 2.0}
605 };
607 if(usub < 1) usub = 1;
608 if(vsub < 1) vsub = 1;
610 mesh->clear();
612 for(int i=0; i<6; i++) {
613 Mat4 xform, dir_xform;
614 Mesh m;
616 gen_plane(&m, 1, 1, usub, vsub);
617 xform.rotate(Vec3(face_angles[i][1], face_angles[i][0], 0));
618 dir_xform = xform;
619 xform.translate(Vec3(0, 0, 0.5));
620 m.apply_xform(xform, dir_xform);
622 mesh->append(m);
623 }
625 Mat4 scale;
626 scale.scaling(xsz, ysz, zsz);
627 mesh->apply_xform(scale, Mat4::identity);
628 }
630 /*
631 void gen_box(Mesh *mesh, float xsz, float ysz, float zsz)
632 {
633 mesh->clear();
635 const int num_faces = 6;
636 int num_verts = num_faces * 4;
637 int num_tri = num_faces * 2;
639 float x = xsz / 2.0;
640 float y = ysz / 2.0;
641 float z = zsz / 2.0;
643 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
644 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
645 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
646 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
647 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
649 static const Vec2 uv[] = { Vec2(0, 0), Vec2(1, 0), Vec2(1, 1), Vec2(0, 1) };
651 // front
652 for(int i=0; i<4; i++) {
653 *narr++ = Vec3(0, 0, 1);
654 *tarr++ = Vec3(1, 0, 0);
655 *uvarr++ = uv[i];
656 }
657 *varr++ = Vec3(-x, -y, z);
658 *varr++ = Vec3(x, -y, z);
659 *varr++ = Vec3(x, y, z);
660 *varr++ = Vec3(-x, y, z);
661 // right
662 for(int i=0; i<4; i++) {
663 *narr++ = Vec3(1, 0, 0);
664 *tarr++ = Vec3(0, 0, -1);
665 *uvarr++ = uv[i];
666 }
667 *varr++ = Vec3(x, -y, z);
668 *varr++ = Vec3(x, -y, -z);
669 *varr++ = Vec3(x, y, -z);
670 *varr++ = Vec3(x, y, z);
671 // back
672 for(int i=0; i<4; i++) {
673 *narr++ = Vec3(0, 0, -1);
674 *tarr++ = Vec3(-1, 0, 0);
675 *uvarr++ = uv[i];
676 }
677 *varr++ = Vec3(x, -y, -z);
678 *varr++ = Vec3(-x, -y, -z);
679 *varr++ = Vec3(-x, y, -z);
680 *varr++ = Vec3(x, y, -z);
681 // left
682 for(int i=0; i<4; i++) {
683 *narr++ = Vec3(-1, 0, 0);
684 *tarr++ = Vec3(0, 0, 1);
685 *uvarr++ = uv[i];
686 }
687 *varr++ = Vec3(-x, -y, -z);
688 *varr++ = Vec3(-x, -y, z);
689 *varr++ = Vec3(-x, y, z);
690 *varr++ = Vec3(-x, y, -z);
691 // top
692 for(int i=0; i<4; i++) {
693 *narr++ = Vec3(0, 1, 0);
694 *tarr++ = Vec3(1, 0, 0);
695 *uvarr++ = uv[i];
696 }
697 *varr++ = Vec3(-x, y, z);
698 *varr++ = Vec3(x, y, z);
699 *varr++ = Vec3(x, y, -z);
700 *varr++ = Vec3(-x, y, -z);
701 // bottom
702 for(int i=0; i<4; i++) {
703 *narr++ = Vec3(0, -1, 0);
704 *tarr++ = Vec3(1, 0, 0);
705 *uvarr++ = uv[i];
706 }
707 *varr++ = Vec3(-x, -y, -z);
708 *varr++ = Vec3(x, -y, -z);
709 *varr++ = Vec3(x, -y, z);
710 *varr++ = Vec3(-x, -y, z);
712 // index array
713 static const int faceidx[] = {0, 1, 2, 0, 2, 3};
714 for(int i=0; i<num_faces; i++) {
715 for(int j=0; j<6; j++) {
716 *idxarr++ = faceidx[j] + i * 4;
717 }
718 }
719 }
720 */
722 static inline Vec3 rev_vert(float u, float v, Vec2 (*rf)(float, float, void*), void *cls)
723 {
724 Vec2 pos = rf(u, v, cls);
726 float angle = u * 2.0 * M_PI;
727 float x = pos.x * cos(angle);
728 float y = pos.y;
729 float z = pos.x * sin(angle);
731 return Vec3(x, y, z);
732 }
734 // ------ surface of revolution -------
735 void gen_revol(Mesh *mesh, int usub, int vsub, Vec2 (*rfunc)(float, float, void*), void *cls)
736 {
737 gen_revol(mesh, usub, vsub, rfunc, 0, cls);
738 }
740 void gen_revol(Mesh *mesh, int usub, int vsub, Vec2 (*rfunc)(float, float, void*),
741 Vec2 (*nfunc)(float, float, void*), void *cls)
742 {
743 if(!rfunc) return;
744 if(usub < 3) usub = 3;
745 if(vsub < 1) vsub = 1;
747 mesh->clear();
749 int uverts = usub + 1;
750 int vverts = vsub + 1;
751 int num_verts = uverts * vverts;
753 int num_quads = usub * vsub;
754 int num_tri = num_quads * 2;
756 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
757 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
758 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
759 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
760 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
762 float du = 1.0 / (float)(uverts - 1);
763 float dv = 1.0 / (float)(vverts - 1);
765 float u = 0.0;
766 for(int i=0; i<uverts; i++) {
767 float v = 0.0;
768 for(int j=0; j<vverts; j++) {
769 Vec3 pos = rev_vert(u, v, rfunc, cls);
771 Vec3 nextu = rev_vert(fmod(u + du, 1.0), v, rfunc, cls);
772 Vec3 tang = nextu - pos;
773 if(length_sq(tang) < 1e-6) {
774 float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25;
775 nextu = rev_vert(fmod(u + du, 1.0), new_v, rfunc, cls);
776 tang = nextu - pos;
777 }
779 Vec3 normal;
780 if(nfunc) {
781 normal = rev_vert(u, v, nfunc, cls);
782 } else {
783 Vec3 nextv = rev_vert(u, v + dv, rfunc, cls);
784 Vec3 bitan = nextv - pos;
785 if(length_sq(bitan) < 1e-6) {
786 nextv = rev_vert(u, v - dv, rfunc, cls);
787 bitan = pos - nextv;
788 }
790 normal = cross(tang, bitan);
791 }
793 *varr++ = pos;
794 *narr++ = normalize(normal);
795 *tarr++ = normalize(tang);
796 *uvarr++ = Vec2(u, v);
798 if(i < usub && j < vsub) {
799 int idx = i * vverts + j;
801 *idxarr++ = idx;
802 *idxarr++ = idx + vverts + 1;
803 *idxarr++ = idx + 1;
805 *idxarr++ = idx;
806 *idxarr++ = idx + vverts;
807 *idxarr++ = idx + vverts + 1;
808 }
810 v += dv;
811 }
812 u += du;
813 }
814 }
817 static inline Vec3 sweep_vert(float u, float v, float height, Vec2 (*sf)(float, float, void*), void *cls)
818 {
819 Vec2 pos = sf(u, v, cls);
821 float x = pos.x;
822 float y = v * height;
823 float z = pos.y;
825 return Vec3(x, y, z);
826 }
828 // ---- sweep shape along a path ----
829 void gen_sweep(Mesh *mesh, float height, int usub, int vsub, Vec2 (*sfunc)(float, float, void*), void *cls)
830 {
831 if(!sfunc) return;
832 if(usub < 3) usub = 3;
833 if(vsub < 1) vsub = 1;
835 mesh->clear();
837 int uverts = usub + 1;
838 int vverts = vsub + 1;
839 int num_verts = uverts * vverts;
841 int num_quads = usub * vsub;
842 int num_tri = num_quads * 2;
844 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
845 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
846 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
847 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
848 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
850 float du = 1.0 / (float)(uverts - 1);
851 float dv = 1.0 / (float)(vverts - 1);
853 float u = 0.0;
854 for(int i=0; i<uverts; i++) {
855 float v = 0.0;
856 for(int j=0; j<vverts; j++) {
857 Vec3 pos = sweep_vert(u, v, height, sfunc, cls);
859 Vec3 nextu = sweep_vert(fmod(u + du, 1.0), v, height, sfunc, cls);
860 Vec3 tang = nextu - pos;
861 if(length_sq(tang) < 1e-6) {
862 float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25;
863 nextu = sweep_vert(fmod(u + du, 1.0), new_v, height, sfunc, cls);
864 tang = nextu - pos;
865 }
867 Vec3 normal;
868 Vec3 nextv = sweep_vert(u, v + dv, height, sfunc, cls);
869 Vec3 bitan = nextv - pos;
870 if(length_sq(bitan) < 1e-6) {
871 nextv = sweep_vert(u, v - dv, height, sfunc, cls);
872 bitan = pos - nextv;
873 }
875 normal = cross(tang, bitan);
877 *varr++ = pos;
878 *narr++ = normalize(normal);
879 *tarr++ = normalize(tang);
880 *uvarr++ = Vec2(u, v);
882 if(i < usub && j < vsub) {
883 int idx = i * vverts + j;
885 *idxarr++ = idx;
886 *idxarr++ = idx + vverts + 1;
887 *idxarr++ = idx + 1;
889 *idxarr++ = idx;
890 *idxarr++ = idx + vverts;
891 *idxarr++ = idx + vverts + 1;
892 }
894 v += dv;
895 }
896 u += du;
897 }
898 }