Wise&mystical  1.0
Project about Europe
Loading...
Searching...
No Matches
par_shapes.h
Go to the documentation of this file.
1// SHAPES :: https://github.com/prideout/par
2// Simple C library for creation and manipulation of triangle meshes.
3//
4// The API is divided into three sections:
5//
6// - Generators. Create parametric surfaces, platonic solids, etc.
7// - Queries. Ask a mesh for its axis-aligned bounding box, etc.
8// - Transforms. Rotate a mesh, merge it with another, add normals, etc.
9//
10// In addition to the comment block above each function declaration, the API
11// has informal documentation here:
12//
13// https://prideout.net/shapes
14//
15// For our purposes, a "mesh" is a list of points and a list of triangles; the
16// former is a flattened list of three-tuples (32-bit floats) and the latter is
17// also a flattened list of three-tuples (16-bit uints). Triangles are always
18// oriented such that their front face winds counter-clockwise.
19//
20// Optionally, meshes can contain 3D normals (one per vertex), and 2D texture
21// coordinates (one per vertex). That's it! If you need something fancier,
22// look elsewhere.
23//
24// Distributed under the MIT License, see bottom of file.
25
26#ifndef PAR_SHAPES_H
27#define PAR_SHAPES_H
28
29#ifdef __cplusplus
30extern "C" {
31#endif
32
33#include <stdint.h>
34// Ray (@raysan5): Commented to avoid conflict with raylib bool
35/*
36#if !defined(_MSC_VER)
37# include <stdbool.h>
38#else // MSVC
39# if _MSC_VER >= 1800
40# include <stdbool.h>
41# else // stdbool.h missing prior to MSVC++ 12.0 (VS2013)
42# define bool int
43# define true 1
44# define false 0
45# endif
46#endif
47*/
48
49#ifndef PAR_SHAPES_T
50#define PAR_SHAPES_T uint16_t
51#endif
52
53typedef struct par_shapes_mesh_s {
54 float* points; // Flat list of 3-tuples (X Y Z X Y Z...)
55 int npoints; // Number of points
56 PAR_SHAPES_T* triangles; // Flat list of 3-tuples (I J K I J K...)
57 int ntriangles; // Number of triangles
58 float* normals; // Optional list of 3-tuples (X Y Z X Y Z...)
59 float* tcoords; // Optional list of 2-tuples (U V U V U V...)
61
63
64// Generators ------------------------------------------------------------------
65
66// Instance a cylinder that sits on the Z=0 plane using the given tessellation
67// levels across the UV domain. Think of "slices" like a number of pizza
68// slices, and "stacks" like a number of stacked rings. Height and radius are
69// both 1.0, but they can easily be changed with par_shapes_scale.
71
72// Cone is similar to cylinder but the radius diminishes to zero as Z increases.
73// Again, height and radius are 1.0, but can be changed with par_shapes_scale.
74par_shapes_mesh* par_shapes_create_cone(int slices, int stacks);
75
76// Create a disk of radius 1.0 with texture coordinates and normals by squashing
77// a cone flat on the Z=0 plane.
79
80// Create a donut that sits on the Z=0 plane with the specified inner radius.
81// The outer radius can be controlled with par_shapes_scale.
82par_shapes_mesh* par_shapes_create_torus(int slices, int stacks, float radius);
83
84// Create a sphere with texture coordinates and small triangles near the poles.
86
87// Approximate a sphere with a subdivided icosahedron, which produces a nice
88// distribution of triangles, but no texture coordinates. Each subdivision
89// level scales the number of triangles by four, so use a very low number.
91
92// More parametric surfaces.
95 float radius);
98
99// Create a parametric surface from a callback function that consumes a 2D
100// point in [0,1] and produces a 3D point.
101typedef void (*par_shapes_fn)(float const*, float*, void*);
103 int stacks, void* userdata);
104
105// Generate points for a 20-sided polyhedron that fits in the unit sphere.
106// Texture coordinates and normals are not generated.
108
109// Generate points for a 12-sided polyhedron that fits in the unit sphere.
110// Again, texture coordinates and normals are not generated.
112
113// More platonic solids.
117
118// Generate an orientable disk shape in 3-space. Does not include normals or
119// texture coordinates.
120par_shapes_mesh* par_shapes_create_disk(float radius, int slices,
121 float const* center, float const* normal);
122
123// Create an empty shape. Useful for building scenes with merge_and_free.
125
126// Generate a rock shape that sits on the Y=0 plane, and sinks into it a bit.
127// This includes smooth normals but no texture coordinates. Each subdivision
128// level scales the number of triangles by four, so use a very low number.
129par_shapes_mesh* par_shapes_create_rock(int seed, int nsubdivisions);
130
131// Create trees or vegetation by executing a recursive turtle graphics program.
132// The program is a list of command-argument pairs. See the unit test for
133// an example. Texture coordinates and normals are not generated.
134par_shapes_mesh* par_shapes_create_lsystem(char const* program, int slices,
135 int maxdepth);
136
137// Queries ---------------------------------------------------------------------
138
139// Dump out a text file conforming to the venerable OBJ format.
140void par_shapes_export(par_shapes_mesh const*, char const* objfile);
141
142// Take a pointer to 6 floats and set them to min xyz, max xyz.
143void par_shapes_compute_aabb(par_shapes_mesh const* mesh, float* aabb);
144
145// Make a deep copy of a mesh. To make a brand new copy, pass null to "target".
146// To avoid memory churn, pass an existing mesh to "target".
148 par_shapes_mesh* target);
149
150// Transformations -------------------------------------------------------------
151
153void par_shapes_translate(par_shapes_mesh*, float x, float y, float z);
154void par_shapes_rotate(par_shapes_mesh*, float radians, float const* axis);
155void par_shapes_scale(par_shapes_mesh*, float x, float y, float z);
157
158// Reverse the winding of a run of faces. Useful when drawing the inside of
159// a Cornell Box. Pass 0 for nfaces to reverse every face in the mesh.
160void par_shapes_invert(par_shapes_mesh*, int startface, int nfaces);
161
162// Remove all triangles whose area is less than minarea.
164
165// Dereference the entire index buffer and replace the point list.
166// This creates an inefficient structure, but is useful for drawing facets.
167// If create_indices is true, a trivial "0 1 2 3..." index buffer is generated.
168void par_shapes_unweld(par_shapes_mesh* mesh, bool create_indices);
169
170// Merge colocated verts, build a new index buffer, and return the
171// optimized mesh. Epsilon is the maximum distance to consider when
172// welding vertices. The mapping argument can be null, or a pointer to
173// npoints integers, which gets filled with the mapping from old vertex
174// indices to new indices.
176 PAR_SHAPES_T* mapping);
177
178// Compute smooth normals by averaging adjacent facet normals.
180
181// Global Config ---------------------------------------------------------------
182
185
186// Advanced --------------------------------------------------------------------
187
190 int slices);
191
192#ifndef PAR_PI
193#define PAR_PI (3.14159265359)
194#define PAR_MIN(a, b) (a > b ? b : a)
195#define PAR_MAX(a, b) (a > b ? a : b)
196#define PAR_CLAMP(v, lo, hi) PAR_MAX(lo, PAR_MIN(hi, v))
197#define PAR_SWAP(T, A, B) { T tmp = B; B = A; A = tmp; }
198#define PAR_SQR(a) ((a) * (a))
199#endif
200
201#ifndef PAR_MALLOC
202#define PAR_MALLOC(T, N) ((T*) malloc(N * sizeof(T)))
203#define PAR_CALLOC(T, N) ((T*) calloc(N * sizeof(T), 1))
204#define PAR_REALLOC(T, BUF, N) ((T*) realloc(BUF, sizeof(T) * (N)))
205#define PAR_FREE(BUF) free(BUF)
206#endif
207
208#ifdef __cplusplus
209}
210#endif
211
212// -----------------------------------------------------------------------------
213// END PUBLIC API
214// -----------------------------------------------------------------------------
215
216#ifdef PAR_SHAPES_IMPLEMENTATION
217#include <stdlib.h>
218#include <stdio.h>
219#include <assert.h>
220#include <float.h>
221#include <string.h>
222#include <math.h>
223#include <errno.h>
224
225static float par_shapes__epsilon_welded_normals = 0.001;
226static float par_shapes__epsilon_degenerate_sphere = 0.0001;
227
228static void par_shapes__sphere(float const* uv, float* xyz, void*);
229static void par_shapes__hemisphere(float const* uv, float* xyz, void*);
230static void par_shapes__plane(float const* uv, float* xyz, void*);
231static void par_shapes__klein(float const* uv, float* xyz, void*);
232static void par_shapes__cylinder(float const* uv, float* xyz, void*);
233static void par_shapes__cone(float const* uv, float* xyz, void*);
234static void par_shapes__torus(float const* uv, float* xyz, void*);
235static void par_shapes__trefoil(float const* uv, float* xyz, void*);
236
237struct osn_context;
238static int par__simplex_noise(int64_t seed, struct osn_context** ctx);
239static void par__simplex_noise_free(struct osn_context* ctx);
240static double par__simplex_noise2(struct osn_context* ctx, double x, double y);
241
242static void par_shapes__copy3(float* result, float const* a)
243{
244 result[0] = a[0];
245 result[1] = a[1];
246 result[2] = a[2];
247}
248
249static float par_shapes__dot3(float const* a, float const* b)
250{
251 return b[0] * a[0] + b[1] * a[1] + b[2] * a[2];
252}
253
254static void par_shapes__transform3(float* p, float const* x, float const* y,
255 float const* z)
256{
257 float px = par_shapes__dot3(p, x);
258 float py = par_shapes__dot3(p, y);
259 float pz = par_shapes__dot3(p, z);
260 p[0] = px;
261 p[1] = py;
262 p[2] = pz;
263}
264
265static void par_shapes__cross3(float* result, float const* a, float const* b)
266{
267 float x = (a[1] * b[2]) - (a[2] * b[1]);
268 float y = (a[2] * b[0]) - (a[0] * b[2]);
269 float z = (a[0] * b[1]) - (a[1] * b[0]);
270 result[0] = x;
271 result[1] = y;
272 result[2] = z;
273}
274
275static void par_shapes__mix3(float* d, float const* a, float const* b, float t)
276{
277 float x = b[0] * t + a[0] * (1 - t);
278 float y = b[1] * t + a[1] * (1 - t);
279 float z = b[2] * t + a[2] * (1 - t);
280 d[0] = x;
281 d[1] = y;
282 d[2] = z;
283}
284
285static void par_shapes__scale3(float* result, float a)
286{
287 result[0] *= a;
288 result[1] *= a;
289 result[2] *= a;
290}
291
292static void par_shapes__normalize3(float* v)
293{
294 float lsqr = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
295 if (lsqr > 0) {
296 par_shapes__scale3(v, 1.0f / lsqr);
297 }
298}
299
300static void par_shapes__subtract3(float* result, float const* a)
301{
302 result[0] -= a[0];
303 result[1] -= a[1];
304 result[2] -= a[2];
305}
306
307static void par_shapes__add3(float* result, float const* a)
308{
309 result[0] += a[0];
310 result[1] += a[1];
311 result[2] += a[2];
312}
313
314static float par_shapes__sqrdist3(float const* a, float const* b)
315{
316 float dx = a[0] - b[0];
317 float dy = a[1] - b[1];
318 float dz = a[2] - b[2];
319 return dx * dx + dy * dy + dz * dz;
320}
321
323{
324 const float epsilon = par_shapes__epsilon_welded_normals;
325 m->normals = PAR_MALLOC(float, m->npoints * 3);
327 par_shapes_mesh* welded = par_shapes_weld(m, epsilon, weldmap);
329 float* pdst = m->normals;
330 for (int i = 0; i < m->npoints; i++, pdst += 3) {
331 int d = weldmap[i];
332 float const* pnormal = welded->normals + d * 3;
333 pdst[0] = pnormal[0];
334 pdst[1] = pnormal[1];
335 pdst[2] = pnormal[2];
336 }
337 PAR_FREE(weldmap);
338 par_shapes_free_mesh(welded);
339}
340
341par_shapes_mesh* par_shapes_create_cylinder(int slices, int stacks)
342{
343 if (slices < 3 || stacks < 1) {
344 return 0;
345 }
346 return par_shapes_create_parametric(par_shapes__cylinder, slices,
347 stacks, 0);
348}
349
350par_shapes_mesh* par_shapes_create_cone(int slices, int stacks)
351{
352 if (slices < 3 || stacks < 1) {
353 return 0;
354 }
355 return par_shapes_create_parametric(par_shapes__cone, slices,
356 stacks, 0);
357}
358
360{
361 par_shapes_mesh* m = par_shapes_create_cone(slices, stacks);
362 if (m) {
363 par_shapes_scale(m, 1.0f, 1.0f, 0.0f);
364 }
365 return m;
366}
367
369{
370 if (slices < 3 || stacks < 3) {
371 return 0;
372 }
373 par_shapes_mesh* m = par_shapes_create_parametric(par_shapes__sphere,
374 slices, stacks, 0);
375 par_shapes_remove_degenerate(m, par_shapes__epsilon_degenerate_sphere);
376 return m;
377}
378
379par_shapes_mesh* par_shapes_create_hemisphere(int slices, int stacks)
380{
381 if (slices < 3 || stacks < 3) {
382 return 0;
383 }
384 par_shapes_mesh* m = par_shapes_create_parametric(par_shapes__hemisphere,
385 slices, stacks, 0);
386 par_shapes_remove_degenerate(m, par_shapes__epsilon_degenerate_sphere);
387 return m;
388}
389
390par_shapes_mesh* par_shapes_create_torus(int slices, int stacks, float radius)
391{
392 if (slices < 3 || stacks < 3) {
393 return 0;
394 }
395 assert(radius <= 1.0 && "Use smaller radius to avoid self-intersection.");
396 assert(radius >= 0.1 && "Use larger radius to avoid self-intersection.");
397 void* userdata = (void*) &radius;
398 return par_shapes_create_parametric(par_shapes__torus, slices,
399 stacks, userdata);
400}
401
402par_shapes_mesh* par_shapes_create_klein_bottle(int slices, int stacks)
403{
404 if (slices < 3 || stacks < 3) {
405 return 0;
406 }
408 par_shapes__klein, slices, stacks, 0);
409 int face = 0;
410 for (int stack = 0; stack < stacks; stack++) {
411 for (int slice = 0; slice < slices; slice++, face += 2) {
412 if (stack < 27 * stacks / 32) {
413 par_shapes_invert(mesh, face, 2);
414 }
415 }
416 }
418 return mesh;
419}
420
421par_shapes_mesh* par_shapes_create_trefoil_knot(int slices, int stacks,
422 float radius)
423{
424 if (slices < 3 || stacks < 3) {
425 return 0;
426 }
427 assert(radius <= 3.0 && "Use smaller radius to avoid self-intersection.");
428 assert(radius >= 0.5 && "Use larger radius to avoid self-intersection.");
429 void* userdata = (void*) &radius;
430 return par_shapes_create_parametric(par_shapes__trefoil, slices,
431 stacks, userdata);
432}
433
434par_shapes_mesh* par_shapes_create_plane(int slices, int stacks)
435{
436 if (slices < 1 || stacks < 1) {
437 return 0;
438 }
439 return par_shapes_create_parametric(par_shapes__plane, slices,
440 stacks, 0);
441}
442
444 int slices, int stacks, void* userdata)
445{
447
448 // Generate verts.
449 mesh->npoints = (slices + 1) * (stacks + 1);
450 mesh->points = PAR_CALLOC(float, 3 * mesh->npoints);
451 float uv[2];
452 float xyz[3];
453 float* points = mesh->points;
454 for (int stack = 0; stack < stacks + 1; stack++) {
455 uv[0] = (float) stack / stacks;
456 for (int slice = 0; slice < slices + 1; slice++) {
457 uv[1] = (float) slice / slices;
458 fn(uv, xyz, userdata);
459 *points++ = xyz[0];
460 *points++ = xyz[1];
461 *points++ = xyz[2];
462 }
463 }
464
465 // Generate texture coordinates.
466 mesh->tcoords = PAR_CALLOC(float, 2 * mesh->npoints);
467 float* uvs = mesh->tcoords;
468 for (int stack = 0; stack < stacks + 1; stack++) {
469 uv[0] = (float) stack / stacks;
470 for (int slice = 0; slice < slices + 1; slice++) {
471 uv[1] = (float) slice / slices;
472 *uvs++ = uv[0];
473 *uvs++ = uv[1];
474 }
475 }
476
477 // Generate faces.
478 mesh->ntriangles = 2 * slices * stacks;
479 mesh->triangles = PAR_CALLOC(PAR_SHAPES_T, 3 * mesh->ntriangles);
480 int v = 0;
481 PAR_SHAPES_T* face = mesh->triangles;
482 for (int stack = 0; stack < stacks; stack++) {
483 for (int slice = 0; slice < slices; slice++) {
484 int next = slice + 1;
485 *face++ = v + slice + slices + 1;
486 *face++ = v + next;
487 *face++ = v + slice;
488 *face++ = v + slice + slices + 1;
489 *face++ = v + next + slices + 1;
490 *face++ = v + next;
491 }
492 v += slices + 1;
493 }
494
496 return mesh;
497}
498
500{
501 PAR_FREE(mesh->points);
502 PAR_FREE(mesh->triangles);
503 PAR_FREE(mesh->normals);
504 PAR_FREE(mesh->tcoords);
505 PAR_FREE(mesh);
506}
507
508void par_shapes_export(par_shapes_mesh const* mesh, char const* filename)
509{
510 FILE* objfile = fopen(filename, "wt");
511 float const* points = mesh->points;
512 float const* tcoords = mesh->tcoords;
513 float const* norms = mesh->normals;
514 PAR_SHAPES_T const* indices = mesh->triangles;
515 if (tcoords && norms) {
516 for (int nvert = 0; nvert < mesh->npoints; nvert++) {
517 fprintf(objfile, "v %f %f %f\n", points[0], points[1], points[2]);
518 fprintf(objfile, "vt %f %f\n", tcoords[0], tcoords[1]);
519 fprintf(objfile, "vn %f %f %f\n", norms[0], norms[1], norms[2]);
520 points += 3;
521 norms += 3;
522 tcoords += 2;
523 }
524 for (int nface = 0; nface < mesh->ntriangles; nface++) {
525 int a = 1 + *indices++;
526 int b = 1 + *indices++;
527 int c = 1 + *indices++;
528 fprintf(objfile, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",
529 a, a, a, b, b, b, c, c, c);
530 }
531 } else if (norms) {
532 for (int nvert = 0; nvert < mesh->npoints; nvert++) {
533 fprintf(objfile, "v %f %f %f\n", points[0], points[1], points[2]);
534 fprintf(objfile, "vn %f %f %f\n", norms[0], norms[1], norms[2]);
535 points += 3;
536 norms += 3;
537 }
538 for (int nface = 0; nface < mesh->ntriangles; nface++) {
539 int a = 1 + *indices++;
540 int b = 1 + *indices++;
541 int c = 1 + *indices++;
542 fprintf(objfile, "f %d//%d %d//%d %d//%d\n", a, a, b, b, c, c);
543 }
544 } else if (tcoords) {
545 for (int nvert = 0; nvert < mesh->npoints; nvert++) {
546 fprintf(objfile, "v %f %f %f\n", points[0], points[1], points[2]);
547 fprintf(objfile, "vt %f %f\n", tcoords[0], tcoords[1]);
548 points += 3;
549 tcoords += 2;
550 }
551 for (int nface = 0; nface < mesh->ntriangles; nface++) {
552 int a = 1 + *indices++;
553 int b = 1 + *indices++;
554 int c = 1 + *indices++;
555 fprintf(objfile, "f %d/%d %d/%d %d/%d\n", a, a, b, b, c, c);
556 }
557 } else {
558 for (int nvert = 0; nvert < mesh->npoints; nvert++) {
559 fprintf(objfile, "v %f %f %f\n", points[0], points[1], points[2]);
560 points += 3;
561 }
562 for (int nface = 0; nface < mesh->ntriangles; nface++) {
563 int a = 1 + *indices++;
564 int b = 1 + *indices++;
565 int c = 1 + *indices++;
566 fprintf(objfile, "f %d %d %d\n", a, b, c);
567 }
568 }
569 fclose(objfile);
570}
571
572static void par_shapes__sphere(float const* uv, float* xyz, void* userdata)
573{
574 float phi = uv[0] * PAR_PI;
575 float theta = uv[1] * 2 * PAR_PI;
576 xyz[0] = cosf(theta) * sinf(phi);
577 xyz[1] = sinf(theta) * sinf(phi);
578 xyz[2] = cosf(phi);
579}
580
581static void par_shapes__hemisphere(float const* uv, float* xyz, void* userdata)
582{
583 float phi = uv[0] * PAR_PI;
584 float theta = uv[1] * PAR_PI;
585 xyz[0] = cosf(theta) * sinf(phi);
586 xyz[1] = sinf(theta) * sinf(phi);
587 xyz[2] = cosf(phi);
588}
589
590static void par_shapes__plane(float const* uv, float* xyz, void* userdata)
591{
592 xyz[0] = uv[0];
593 xyz[1] = uv[1];
594 xyz[2] = 0;
595}
596
597static void par_shapes__klein(float const* uv, float* xyz, void* userdata)
598{
599 float u = uv[0] * PAR_PI;
600 float v = uv[1] * 2 * PAR_PI;
601 u = u * 2;
602 if (u < PAR_PI) {
603 xyz[0] = 3 * cosf(u) * (1 + sinf(u)) + (2 * (1 - cosf(u) / 2)) *
604 cosf(u) * cosf(v);
605 xyz[2] = -8 * sinf(u) - 2 * (1 - cosf(u) / 2) * sinf(u) * cosf(v);
606 } else {
607 xyz[0] = 3 * cosf(u) * (1 + sinf(u)) + (2 * (1 - cosf(u) / 2)) *
608 cosf(v + PAR_PI);
609 xyz[2] = -8 * sinf(u);
610 }
611 xyz[1] = -2 * (1 - cosf(u) / 2) * sinf(v);
612}
613
614static void par_shapes__cylinder(float const* uv, float* xyz, void* userdata)
615{
616 float theta = uv[1] * 2 * PAR_PI;
617 xyz[0] = sinf(theta);
618 xyz[1] = cosf(theta);
619 xyz[2] = uv[0];
620}
621
622static void par_shapes__cone(float const* uv, float* xyz, void* userdata)
623{
624 float r = 1.0f - uv[0];
625 float theta = uv[1] * 2 * PAR_PI;
626 xyz[0] = r * sinf(theta);
627 xyz[1] = r * cosf(theta);
628 xyz[2] = uv[0];
629}
630
631static void par_shapes__torus(float const* uv, float* xyz, void* userdata)
632{
633 float major = 1;
634 float minor = *((float*) userdata);
635 float theta = uv[0] * 2 * PAR_PI;
636 float phi = uv[1] * 2 * PAR_PI;
637 float beta = major + minor * cosf(phi);
638 xyz[0] = cosf(theta) * beta;
639 xyz[1] = sinf(theta) * beta;
640 xyz[2] = sinf(phi) * minor;
641}
642
643static void par_shapes__trefoil(float const* uv, float* xyz, void* userdata)
644{
645 float minor = *((float*) userdata);
646 const float a = 0.5f;
647 const float b = 0.3f;
648 const float c = 0.5f;
649 const float d = minor * 0.1f;
650 const float u = (1 - uv[0]) * 4 * PAR_PI;
651 const float v = uv[1] * 2 * PAR_PI;
652 const float r = a + b * cos(1.5f * u);
653 const float x = r * cos(u);
654 const float y = r * sin(u);
655 const float z = c * sin(1.5f * u);
656 float q[3];
657 q[0] =
658 -1.5f * b * sin(1.5f * u) * cos(u) - (a + b * cos(1.5f * u)) * sin(u);
659 q[1] =
660 -1.5f * b * sin(1.5f * u) * sin(u) + (a + b * cos(1.5f * u)) * cos(u);
661 q[2] = 1.5f * c * cos(1.5f * u);
662 par_shapes__normalize3(q);
663 float qvn[3] = {q[1], -q[0], 0};
664 par_shapes__normalize3(qvn);
665 float ww[3];
666 par_shapes__cross3(ww, q, qvn);
667 xyz[0] = x + d * (qvn[0] * cos(v) + ww[0] * sin(v));
668 xyz[1] = y + d * (qvn[1] * cos(v) + ww[1] * sin(v));
669 xyz[2] = z + d * ww[2] * sin(v);
670}
671
672void par_shapes_set_epsilon_welded_normals(float epsilon) {
673 par_shapes__epsilon_welded_normals = epsilon;
674}
675
677 par_shapes__epsilon_degenerate_sphere = epsilon;
678}
679
681{
682 PAR_SHAPES_T offset = dst->npoints;
683 int npoints = dst->npoints + src->npoints;
684 int vecsize = sizeof(float) * 3;
685 dst->points = PAR_REALLOC(float, dst->points, 3 * npoints);
686 memcpy(dst->points + 3 * dst->npoints, src->points, vecsize * src->npoints);
687 dst->npoints = npoints;
688 if (src->normals || dst->normals) {
689 dst->normals = PAR_REALLOC(float, dst->normals, 3 * npoints);
690 if (src->normals) {
691 memcpy(dst->normals + 3 * offset, src->normals,
692 vecsize * src->npoints);
693 }
694 }
695 if (src->tcoords || dst->tcoords) {
696 int uvsize = sizeof(float) * 2;
697 dst->tcoords = PAR_REALLOC(float, dst->tcoords, 2 * npoints);
698 if (src->tcoords) {
699 memcpy(dst->tcoords + 2 * offset, src->tcoords,
700 uvsize * src->npoints);
701 }
702 }
703 int ntriangles = dst->ntriangles + src->ntriangles;
704 dst->triangles = PAR_REALLOC(PAR_SHAPES_T, dst->triangles, 3 * ntriangles);
705 PAR_SHAPES_T* ptriangles = dst->triangles + 3 * dst->ntriangles;
706 PAR_SHAPES_T const* striangles = src->triangles;
707 for (int i = 0; i < src->ntriangles; i++) {
708 *ptriangles++ = offset + *striangles++;
709 *ptriangles++ = offset + *striangles++;
710 *ptriangles++ = offset + *striangles++;
711 }
712 dst->ntriangles = ntriangles;
713}
714
715par_shapes_mesh* par_shapes_create_disk(float radius, int slices,
716 float const* center, float const* normal)
717{
719 mesh->npoints = slices + 1;
720 mesh->points = PAR_MALLOC(float, 3 * mesh->npoints);
721 float* points = mesh->points;
722 *points++ = 0;
723 *points++ = 0;
724 *points++ = 0;
725 for (int i = 0; i < slices; i++) {
726 float theta = i * PAR_PI * 2 / slices;
727 *points++ = radius * cos(theta);
728 *points++ = radius * sin(theta);
729 *points++ = 0;
730 }
731 float nnormal[3] = {normal[0], normal[1], normal[2]};
732 par_shapes__normalize3(nnormal);
733 mesh->normals = PAR_MALLOC(float, 3 * mesh->npoints);
734 float* norms = mesh->normals;
735 for (int i = 0; i < mesh->npoints; i++) {
736 *norms++ = nnormal[0];
737 *norms++ = nnormal[1];
738 *norms++ = nnormal[2];
739 }
740 mesh->ntriangles = slices;
741 mesh->triangles = PAR_MALLOC(PAR_SHAPES_T, 3 * mesh->ntriangles);
742 PAR_SHAPES_T* triangles = mesh->triangles;
743 for (int i = 0; i < slices; i++) {
744 *triangles++ = 0;
745 *triangles++ = 1 + i;
746 *triangles++ = 1 + (i + 1) % slices;
747 }
748 float k[3] = {0, 0, -1};
749 float axis[3];
750 par_shapes__cross3(axis, nnormal, k);
751 par_shapes__normalize3(axis);
752 par_shapes_rotate(mesh, acos(nnormal[2]), axis);
753 par_shapes_translate(mesh, center[0], center[1], center[2]);
754 return mesh;
755}
756
758{
759 return PAR_CALLOC(par_shapes_mesh, 1);
760}
761
762void par_shapes_translate(par_shapes_mesh* m, float x, float y, float z)
763{
764 float* points = m->points;
765 for (int i = 0; i < m->npoints; i++) {
766 *points++ += x;
767 *points++ += y;
768 *points++ += z;
769 }
770}
771
772void par_shapes_rotate(par_shapes_mesh* mesh, float radians, float const* axis)
773{
774 float s = sinf(radians);
775 float c = cosf(radians);
776 float x = axis[0];
777 float y = axis[1];
778 float z = axis[2];
779 float xy = x * y;
780 float yz = y * z;
781 float zx = z * x;
782 float oneMinusC = 1.0f - c;
783 float col0[3] = {
784 (((x * x) * oneMinusC) + c),
785 ((xy * oneMinusC) + (z * s)), ((zx * oneMinusC) - (y * s))
786 };
787 float col1[3] = {
788 ((xy * oneMinusC) - (z * s)),
789 (((y * y) * oneMinusC) + c), ((yz * oneMinusC) + (x * s))
790 };
791 float col2[3] = {
792 ((zx * oneMinusC) + (y * s)),
793 ((yz * oneMinusC) - (x * s)), (((z * z) * oneMinusC) + c)
794 };
795 float* p = mesh->points;
796 for (int i = 0; i < mesh->npoints; i++, p += 3) {
797 float x = col0[0] * p[0] + col1[0] * p[1] + col2[0] * p[2];
798 float y = col0[1] * p[0] + col1[1] * p[1] + col2[1] * p[2];
799 float z = col0[2] * p[0] + col1[2] * p[1] + col2[2] * p[2];
800 p[0] = x;
801 p[1] = y;
802 p[2] = z;
803 }
804 float* n = mesh->normals;
805 if (n) {
806 for (int i = 0; i < mesh->npoints; i++, n += 3) {
807 float x = col0[0] * n[0] + col1[0] * n[1] + col2[0] * n[2];
808 float y = col0[1] * n[0] + col1[1] * n[1] + col2[1] * n[2];
809 float z = col0[2] * n[0] + col1[2] * n[1] + col2[2] * n[2];
810 n[0] = x;
811 n[1] = y;
812 n[2] = z;
813 }
814 }
815}
816
817void par_shapes_scale(par_shapes_mesh* m, float x, float y, float z)
818{
819 float* points = m->points;
820 for (int i = 0; i < m->npoints; i++) {
821 *points++ *= x;
822 *points++ *= y;
823 *points++ *= z;
824 }
825 float* n = m->normals;
826 if (n && !(x == y && y == z)) {
827 bool x_zero = x == 0;
828 bool y_zero = y == 0;
829 bool z_zero = z == 0;
830 if (!x_zero && !y_zero && !z_zero) {
831 x = 1.0f / x;
832 y = 1.0f / y;
833 z = 1.0f / z;
834 } else {
835 x = x_zero && !y_zero && !z_zero;
836 y = y_zero && !x_zero && !z_zero;
837 z = z_zero && !x_zero && !y_zero;
838 }
839 for (int i = 0; i < m->npoints; i++, n += 3) {
840 n[0] *= x;
841 n[1] *= y;
842 n[2] *= z;
843 par_shapes__normalize3(n);
844 }
845 }
846}
847
849{
850 par_shapes_merge(dst, src);
852}
853
854void par_shapes_compute_aabb(par_shapes_mesh const* m, float* aabb)
855{
856 float* points = m->points;
857 aabb[0] = aabb[3] = points[0];
858 aabb[1] = aabb[4] = points[1];
859 aabb[2] = aabb[5] = points[2];
860 points += 3;
861 for (int i = 1; i < m->npoints; i++, points += 3) {
862 aabb[0] = PAR_MIN(points[0], aabb[0]);
863 aabb[1] = PAR_MIN(points[1], aabb[1]);
864 aabb[2] = PAR_MIN(points[2], aabb[2]);
865 aabb[3] = PAR_MAX(points[0], aabb[3]);
866 aabb[4] = PAR_MAX(points[1], aabb[4]);
867 aabb[5] = PAR_MAX(points[2], aabb[5]);
868 }
869}
870
871void par_shapes_invert(par_shapes_mesh* m, int face, int nfaces)
872{
873 nfaces = nfaces ? nfaces : m->ntriangles;
874 PAR_SHAPES_T* tri = m->triangles + face * 3;
875 for (int i = 0; i < nfaces; i++) {
876 PAR_SWAP(PAR_SHAPES_T, tri[0], tri[2]);
877 tri += 3;
878 }
879}
880
882{
883 static float verts[] = {
884 0.000, 0.000, 1.000,
885 0.894, 0.000, 0.447,
886 0.276, 0.851, 0.447,
887 -0.724, 0.526, 0.447,
888 -0.724, -0.526, 0.447,
889 0.276, -0.851, 0.447,
890 0.724, 0.526, -0.447,
891 -0.276, 0.851, -0.447,
892 -0.894, 0.000, -0.447,
893 -0.276, -0.851, -0.447,
894 0.724, -0.526, -0.447,
895 0.000, 0.000, -1.000
896 };
897 static PAR_SHAPES_T faces[] = {
898 0,1,2,
899 0,2,3,
900 0,3,4,
901 0,4,5,
902 0,5,1,
903 7,6,11,
904 8,7,11,
905 9,8,11,
906 10,9,11,
907 6,10,11,
908 6,2,1,
909 7,3,2,
910 8,4,3,
911 9,5,4,
912 10,1,5,
913 6,7,2,
914 7,8,3,
915 8,9,4,
916 9,10,5,
917 10,6,1
918 };
920 mesh->npoints = sizeof(verts) / sizeof(verts[0]) / 3;
921 mesh->points = PAR_MALLOC(float, sizeof(verts) / 4);
922 memcpy(mesh->points, verts, sizeof(verts));
923 mesh->ntriangles = sizeof(faces) / sizeof(faces[0]) / 3;
924 mesh->triangles = PAR_MALLOC(PAR_SHAPES_T, sizeof(faces) / 2);
925 memcpy(mesh->triangles, faces, sizeof(faces));
926 return mesh;
927}
928
930{
931 static float verts[20 * 3] = {
932 0.607, 0.000, 0.795,
933 0.188, 0.577, 0.795,
934 -0.491, 0.357, 0.795,
935 -0.491, -0.357, 0.795,
936 0.188, -0.577, 0.795,
937 0.982, 0.000, 0.188,
938 0.304, 0.934, 0.188,
939 -0.795, 0.577, 0.188,
940 -0.795, -0.577, 0.188,
941 0.304, -0.934, 0.188,
942 0.795, 0.577, -0.188,
943 -0.304, 0.934, -0.188,
944 -0.982, 0.000, -0.188,
945 -0.304, -0.934, -0.188,
946 0.795, -0.577, -0.188,
947 0.491, 0.357, -0.795,
948 -0.188, 0.577, -0.795,
949 -0.607, 0.000, -0.795,
950 -0.188, -0.577, -0.795,
951 0.491, -0.357, -0.795,
952 };
953 static PAR_SHAPES_T pentagons[12 * 5] = {
954 0,1,2,3,4,
955 5,10,6,1,0,
956 6,11,7,2,1,
957 7,12,8,3,2,
958 8,13,9,4,3,
959 9,14,5,0,4,
960 15,16,11,6,10,
961 16,17,12,7,11,
962 17,18,13,8,12,
963 18,19,14,9,13,
964 19,15,10,5,14,
965 19,18,17,16,15
966 };
967 int npentagons = sizeof(pentagons) / sizeof(pentagons[0]) / 5;
969 int ncorners = sizeof(verts) / sizeof(verts[0]) / 3;
970 mesh->npoints = ncorners;
971 mesh->points = PAR_MALLOC(float, mesh->npoints * 3);
972 memcpy(mesh->points, verts, sizeof(verts));
973 PAR_SHAPES_T const* pentagon = pentagons;
974 mesh->ntriangles = npentagons * 3;
975 mesh->triangles = PAR_MALLOC(PAR_SHAPES_T, mesh->ntriangles * 3);
976 PAR_SHAPES_T* tris = mesh->triangles;
977 for (int p = 0; p < npentagons; p++, pentagon += 5) {
978 *tris++ = pentagon[0];
979 *tris++ = pentagon[1];
980 *tris++ = pentagon[2];
981 *tris++ = pentagon[0];
982 *tris++ = pentagon[2];
983 *tris++ = pentagon[3];
984 *tris++ = pentagon[0];
985 *tris++ = pentagon[3];
986 *tris++ = pentagon[4];
987 }
988 return mesh;
989}
990
992{
993 static float verts[6 * 3] = {
994 0.000, 0.000, 1.000,
995 1.000, 0.000, 0.000,
996 0.000, 1.000, 0.000,
997 -1.000, 0.000, 0.000,
998 0.000, -1.000, 0.000,
999 0.000, 0.000, -1.000
1000 };
1001 static PAR_SHAPES_T triangles[8 * 3] = {
1002 0,1,2,
1003 0,2,3,
1004 0,3,4,
1005 0,4,1,
1006 2,1,5,
1007 3,2,5,
1008 4,3,5,
1009 1,4,5,
1010 };
1011 int ntris = sizeof(triangles) / sizeof(triangles[0]) / 3;
1013 int ncorners = sizeof(verts) / sizeof(verts[0]) / 3;
1014 mesh->npoints = ncorners;
1015 mesh->points = PAR_MALLOC(float, mesh->npoints * 3);
1016 memcpy(mesh->points, verts, sizeof(verts));
1017 PAR_SHAPES_T const* triangle = triangles;
1018 mesh->ntriangles = ntris;
1019 mesh->triangles = PAR_MALLOC(PAR_SHAPES_T, mesh->ntriangles * 3);
1020 PAR_SHAPES_T* tris = mesh->triangles;
1021 for (int p = 0; p < ntris; p++) {
1022 *tris++ = *triangle++;
1023 *tris++ = *triangle++;
1024 *tris++ = *triangle++;
1025 }
1026 return mesh;
1027}
1028
1030{
1031 static float verts[4 * 3] = {
1032 0.000, 1.333, 0,
1033 0.943, 0, 0,
1034 -0.471, 0, 0.816,
1035 -0.471, 0, -0.816,
1036 };
1037 static PAR_SHAPES_T triangles[4 * 3] = {
1038 2,1,0,
1039 3,2,0,
1040 1,3,0,
1041 1,2,3,
1042 };
1043 int ntris = sizeof(triangles) / sizeof(triangles[0]) / 3;
1045 int ncorners = sizeof(verts) / sizeof(verts[0]) / 3;
1046 mesh->npoints = ncorners;
1047 mesh->points = PAR_MALLOC(float, mesh->npoints * 3);
1048 memcpy(mesh->points, verts, sizeof(verts));
1049 PAR_SHAPES_T const* triangle = triangles;
1050 mesh->ntriangles = ntris;
1051 mesh->triangles = PAR_MALLOC(PAR_SHAPES_T, mesh->ntriangles * 3);
1052 PAR_SHAPES_T* tris = mesh->triangles;
1053 for (int p = 0; p < ntris; p++) {
1054 *tris++ = *triangle++;
1055 *tris++ = *triangle++;
1056 *tris++ = *triangle++;
1057 }
1058 return mesh;
1059}
1060
1062{
1063 static float verts[8 * 3] = {
1064 0, 0, 0, // 0
1065 0, 1, 0, // 1
1066 1, 1, 0, // 2
1067 1, 0, 0, // 3
1068 0, 0, 1, // 4
1069 0, 1, 1, // 5
1070 1, 1, 1, // 6
1071 1, 0, 1, // 7
1072 };
1073 static PAR_SHAPES_T quads[6 * 4] = {
1074 7,6,5,4, // front
1075 0,1,2,3, // back
1076 6,7,3,2, // right
1077 5,6,2,1, // top
1078 4,5,1,0, // left
1079 7,4,0,3, // bottom
1080 };
1081 int nquads = sizeof(quads) / sizeof(quads[0]) / 4;
1083 int ncorners = sizeof(verts) / sizeof(verts[0]) / 3;
1084 mesh->npoints = ncorners;
1085 mesh->points = PAR_MALLOC(float, mesh->npoints * 3);
1086 memcpy(mesh->points, verts, sizeof(verts));
1087 PAR_SHAPES_T const* quad = quads;
1088 mesh->ntriangles = nquads * 2;
1089 mesh->triangles = PAR_MALLOC(PAR_SHAPES_T, mesh->ntriangles * 3);
1090 PAR_SHAPES_T* tris = mesh->triangles;
1091 for (int p = 0; p < nquads; p++, quad += 4) {
1092 *tris++ = quad[0];
1093 *tris++ = quad[1];
1094 *tris++ = quad[2];
1095 *tris++ = quad[2];
1096 *tris++ = quad[3];
1097 *tris++ = quad[0];
1098 }
1099 return mesh;
1100}
1101
1102typedef struct {
1103 char* cmd;
1104 char* arg;
1105} par_shapes__command;
1106
1107typedef struct {
1108 char const* name;
1109 int weight;
1110 int ncommands;
1111 par_shapes__command* commands;
1112} par_shapes__rule;
1113
1114typedef struct {
1115 int pc;
1116 float position[3];
1117 float scale[3];
1118 par_shapes_mesh* orientation;
1119 par_shapes__rule* rule;
1120} par_shapes__stackframe;
1121
1122static par_shapes__rule* par_shapes__pick_rule(const char* name,
1123 par_shapes__rule* rules, int nrules)
1124{
1125 par_shapes__rule* rule = 0;
1126 int total = 0;
1127 for (int i = 0; i < nrules; i++) {
1128 rule = rules + i;
1129 if (!strcmp(rule->name, name)) {
1130 total += rule->weight;
1131 }
1132 }
1133 float r = (float) rand() / RAND_MAX;
1134 float t = 0;
1135 for (int i = 0; i < nrules; i++) {
1136 rule = rules + i;
1137 if (!strcmp(rule->name, name)) {
1138 t += (float) rule->weight / total;
1139 if (t >= r) {
1140 return rule;
1141 }
1142 }
1143 }
1144 return rule;
1145}
1146
1147static par_shapes_mesh* par_shapes__create_turtle()
1148{
1149 const float xaxis[] = {1, 0, 0};
1150 const float yaxis[] = {0, 1, 0};
1151 const float zaxis[] = {0, 0, 1};
1153 turtle->npoints = 3;
1154 turtle->points = PAR_CALLOC(float, turtle->npoints * 3);
1155 par_shapes__copy3(turtle->points + 0, xaxis);
1156 par_shapes__copy3(turtle->points + 3, yaxis);
1157 par_shapes__copy3(turtle->points + 6, zaxis);
1158 return turtle;
1159}
1160
1161static par_shapes_mesh* par_shapes__apply_turtle(par_shapes_mesh* mesh,
1162 par_shapes_mesh* turtle, float const* pos, float const* scale)
1163{
1164 par_shapes_mesh* m = par_shapes_clone(mesh, 0);
1165 for (int p = 0; p < m->npoints; p++) {
1166 float* pt = m->points + p * 3;
1167 pt[0] *= scale[0];
1168 pt[1] *= scale[1];
1169 pt[2] *= scale[2];
1170 par_shapes__transform3(pt,
1171 turtle->points + 0, turtle->points + 3, turtle->points + 6);
1172 pt[0] += pos[0];
1173 pt[1] += pos[1];
1174 pt[2] += pos[2];
1175 }
1176 return m;
1177}
1178
1180 int slices)
1181{
1182 int stacks = 1;
1183 int npoints = (slices + 1) * (stacks + 1);
1184 assert(scene->npoints >= npoints && "Cannot connect to empty scene.");
1185
1186 // Create the new point list.
1187 npoints = scene->npoints + (slices + 1);
1188 float* points = PAR_MALLOC(float, npoints * 3);
1189 memcpy(points, scene->points, sizeof(float) * scene->npoints * 3);
1190 float* newpts = points + scene->npoints * 3;
1191 memcpy(newpts, cylinder->points + (slices + 1) * 3,
1192 sizeof(float) * (slices + 1) * 3);
1193 PAR_FREE(scene->points);
1194 scene->points = points;
1195
1196 // Create the new triangle list.
1197 int ntriangles = scene->ntriangles + 2 * slices * stacks;
1198 PAR_SHAPES_T* triangles = PAR_MALLOC(PAR_SHAPES_T, ntriangles * 3);
1199 memcpy(triangles, scene->triangles,
1200 sizeof(PAR_SHAPES_T) * scene->ntriangles * 3);
1201 int v = scene->npoints - (slices + 1);
1202 PAR_SHAPES_T* face = triangles + scene->ntriangles * 3;
1203 for (int stack = 0; stack < stacks; stack++) {
1204 for (int slice = 0; slice < slices; slice++) {
1205 int next = slice + 1;
1206 *face++ = v + slice + slices + 1;
1207 *face++ = v + next;
1208 *face++ = v + slice;
1209 *face++ = v + slice + slices + 1;
1210 *face++ = v + next + slices + 1;
1211 *face++ = v + next;
1212 }
1213 v += slices + 1;
1214 }
1215 PAR_FREE(scene->triangles);
1216 scene->triangles = triangles;
1217
1218 scene->npoints = npoints;
1219 scene->ntriangles = ntriangles;
1220}
1221
1222par_shapes_mesh* par_shapes_create_lsystem(char const* text, int slices,
1223 int maxdepth)
1224{
1225 char* program;
1226 program = PAR_MALLOC(char, strlen(text) + 1);
1227
1228 // The first pass counts the number of rules and commands.
1229 strcpy(program, text);
1230 char *cmd = strtok(program, " ");
1231 int nrules = 1;
1232 int ncommands = 0;
1233 while (cmd) {
1234 char *arg = strtok(0, " ");
1235 if (!arg) {
1236 puts("lsystem error: unexpected end of program.");
1237 break;
1238 }
1239 if (!strcmp(cmd, "rule")) {
1240 nrules++;
1241 } else {
1242 ncommands++;
1243 }
1244 cmd = strtok(0, " ");
1245 }
1246
1247 // Allocate space.
1248 par_shapes__rule* rules = PAR_MALLOC(par_shapes__rule, nrules);
1249 par_shapes__command* commands = PAR_MALLOC(par_shapes__command, ncommands);
1250
1251 // Initialize the entry rule.
1252 par_shapes__rule* current_rule = &rules[0];
1253 par_shapes__command* current_command = &commands[0];
1254 current_rule->name = "entry";
1255 current_rule->weight = 1;
1256 current_rule->ncommands = 0;
1257 current_rule->commands = current_command;
1258
1259 // The second pass fills in the structures.
1260 strcpy(program, text);
1261 cmd = strtok(program, " ");
1262 while (cmd) {
1263 char *arg = strtok(0, " ");
1264 if (!strcmp(cmd, "rule")) {
1265 current_rule++;
1266
1267 // Split the argument into a rule name and weight.
1268 char* dot = strchr(arg, '.');
1269 if (dot) {
1270 current_rule->weight = atoi(dot + 1);
1271 *dot = 0;
1272 } else {
1273 current_rule->weight = 1;
1274 }
1275
1276 current_rule->name = arg;
1277 current_rule->ncommands = 0;
1278 current_rule->commands = current_command;
1279 } else {
1280 current_rule->ncommands++;
1281 current_command->cmd = cmd;
1282 current_command->arg = arg;
1283 current_command++;
1284 }
1285 cmd = strtok(0, " ");
1286 }
1287
1288 // For testing purposes, dump out the parsed program.
1289 #ifdef TEST_PARSE
1290 for (int i = 0; i < nrules; i++) {
1291 par_shapes__rule rule = rules[i];
1292 printf("rule %s.%d\n", rule.name, rule.weight);
1293 for (int c = 0; c < rule.ncommands; c++) {
1294 par_shapes__command cmd = rule.commands[c];
1295 printf("\t%s %s\n", cmd.cmd, cmd.arg);
1296 }
1297 }
1298 #endif
1299
1300 // Instantiate the aggregated shape and the template shapes.
1303 par_shapes_mesh* turtle = par_shapes__create_turtle();
1304
1305 // We're not attempting to support texture coordinates and normals
1306 // with L-systems, so remove them from the template shape.
1307 PAR_FREE(tube->normals);
1308 PAR_FREE(tube->tcoords);
1309 tube->normals = 0;
1310 tube->tcoords = 0;
1311
1312 const float xaxis[] = {1, 0, 0};
1313 const float yaxis[] = {0, 1, 0};
1314 const float zaxis[] = {0, 0, 1};
1315 const float units[] = {1, 1, 1};
1316
1317 // Execute the L-system program until the stack size is 0.
1318 par_shapes__stackframe* stack =
1319 PAR_CALLOC(par_shapes__stackframe, maxdepth);
1320 int stackptr = 0;
1321 stack[0].orientation = turtle;
1322 stack[0].rule = &rules[0];
1323 par_shapes__copy3(stack[0].scale, units);
1324 while (stackptr >= 0) {
1325 par_shapes__stackframe* frame = &stack[stackptr];
1326 par_shapes__rule* rule = frame->rule;
1327 par_shapes_mesh* turtle = frame->orientation;
1328 float* position = frame->position;
1329 float* scale = frame->scale;
1330 if (frame->pc >= rule->ncommands) {
1331 par_shapes_free_mesh(turtle);
1332 stackptr--;
1333 continue;
1334 }
1335
1336 par_shapes__command* cmd = rule->commands + (frame->pc++);
1337 #ifdef DUMP_TRACE
1338 printf("%5s %5s %5s:%d %03d\n", cmd->cmd, cmd->arg, rule->name,
1339 frame->pc - 1, stackptr);
1340 #endif
1341
1342 float value;
1343 if (!strcmp(cmd->cmd, "shape")) {
1344 par_shapes_mesh* m = par_shapes__apply_turtle(tube, turtle,
1345 position, scale);
1346 if (!strcmp(cmd->arg, "connect")) {
1347 par_shapes__connect(scene, m, slices);
1348 } else {
1349 par_shapes_merge(scene, m);
1350 }
1352 } else if (!strcmp(cmd->cmd, "call") && stackptr < maxdepth - 1) {
1353 rule = par_shapes__pick_rule(cmd->arg, rules, nrules);
1354 frame = &stack[++stackptr];
1355 frame->rule = rule;
1356 frame->orientation = par_shapes_clone(turtle, 0);
1357 frame->pc = 0;
1358 par_shapes__copy3(frame->scale, scale);
1359 par_shapes__copy3(frame->position, position);
1360 continue;
1361 } else {
1362 value = atof(cmd->arg);
1363 if (!strcmp(cmd->cmd, "rx")) {
1364 par_shapes_rotate(turtle, value * PAR_PI / 180.0, xaxis);
1365 } else if (!strcmp(cmd->cmd, "ry")) {
1366 par_shapes_rotate(turtle, value * PAR_PI / 180.0, yaxis);
1367 } else if (!strcmp(cmd->cmd, "rz")) {
1368 par_shapes_rotate(turtle, value * PAR_PI / 180.0, zaxis);
1369 } else if (!strcmp(cmd->cmd, "tx")) {
1370 float vec[3] = {value, 0, 0};
1371 float t[3] = {
1372 par_shapes__dot3(turtle->points + 0, vec),
1373 par_shapes__dot3(turtle->points + 3, vec),
1374 par_shapes__dot3(turtle->points + 6, vec)
1375 };
1376 par_shapes__add3(position, t);
1377 } else if (!strcmp(cmd->cmd, "ty")) {
1378 float vec[3] = {0, value, 0};
1379 float t[3] = {
1380 par_shapes__dot3(turtle->points + 0, vec),
1381 par_shapes__dot3(turtle->points + 3, vec),
1382 par_shapes__dot3(turtle->points + 6, vec)
1383 };
1384 par_shapes__add3(position, t);
1385 } else if (!strcmp(cmd->cmd, "tz")) {
1386 float vec[3] = {0, 0, value};
1387 float t[3] = {
1388 par_shapes__dot3(turtle->points + 0, vec),
1389 par_shapes__dot3(turtle->points + 3, vec),
1390 par_shapes__dot3(turtle->points + 6, vec)
1391 };
1392 par_shapes__add3(position, t);
1393 } else if (!strcmp(cmd->cmd, "sx")) {
1394 scale[0] *= value;
1395 } else if (!strcmp(cmd->cmd, "sy")) {
1396 scale[1] *= value;
1397 } else if (!strcmp(cmd->cmd, "sz")) {
1398 scale[2] *= value;
1399 } else if (!strcmp(cmd->cmd, "sa")) {
1400 scale[0] *= value;
1401 scale[1] *= value;
1402 scale[2] *= value;
1403 }
1404 }
1405 }
1406 PAR_FREE(stack);
1407 PAR_FREE(program);
1408 PAR_FREE(rules);
1409 PAR_FREE(commands);
1410 return scene;
1411}
1412
1413void par_shapes_unweld(par_shapes_mesh* mesh, bool create_indices)
1414{
1415 int npoints = mesh->ntriangles * 3;
1416 float* points = PAR_MALLOC(float, 3 * npoints);
1417 float* dst = points;
1418 PAR_SHAPES_T const* index = mesh->triangles;
1419 for (int i = 0; i < npoints; i++) {
1420 float const* src = mesh->points + 3 * (*index++);
1421 *dst++ = src[0];
1422 *dst++ = src[1];
1423 *dst++ = src[2];
1424 }
1425 PAR_FREE(mesh->points);
1426 mesh->points = points;
1427 mesh->npoints = npoints;
1428 if (create_indices) {
1429 PAR_SHAPES_T* tris = PAR_MALLOC(PAR_SHAPES_T, 3 * mesh->ntriangles);
1430 PAR_SHAPES_T* index = tris;
1431 for (int i = 0; i < mesh->ntriangles * 3; i++) {
1432 *index++ = i;
1433 }
1434 PAR_FREE(mesh->triangles);
1435 mesh->triangles = tris;
1436 }
1437}
1438
1440{
1441 PAR_FREE(m->normals);
1442 m->normals = PAR_CALLOC(float, m->npoints * 3);
1443 PAR_SHAPES_T const* triangle = m->triangles;
1444 float next[3], prev[3], cp[3];
1445 for (int f = 0; f < m->ntriangles; f++, triangle += 3) {
1446 float const* pa = m->points + 3 * triangle[0];
1447 float const* pb = m->points + 3 * triangle[1];
1448 float const* pc = m->points + 3 * triangle[2];
1449 par_shapes__copy3(next, pb);
1450 par_shapes__subtract3(next, pa);
1451 par_shapes__copy3(prev, pc);
1452 par_shapes__subtract3(prev, pa);
1453 par_shapes__cross3(cp, next, prev);
1454 par_shapes__add3(m->normals + 3 * triangle[0], cp);
1455 par_shapes__copy3(next, pc);
1456 par_shapes__subtract3(next, pb);
1457 par_shapes__copy3(prev, pa);
1458 par_shapes__subtract3(prev, pb);
1459 par_shapes__cross3(cp, next, prev);
1460 par_shapes__add3(m->normals + 3 * triangle[1], cp);
1461 par_shapes__copy3(next, pa);
1462 par_shapes__subtract3(next, pc);
1463 par_shapes__copy3(prev, pb);
1464 par_shapes__subtract3(prev, pc);
1465 par_shapes__cross3(cp, next, prev);
1466 par_shapes__add3(m->normals + 3 * triangle[2], cp);
1467 }
1468 float* normal = m->normals;
1469 for (int p = 0; p < m->npoints; p++, normal += 3) {
1470 par_shapes__normalize3(normal);
1471 }
1472}
1473
1474static void par_shapes__subdivide(par_shapes_mesh* mesh)
1475{
1476 assert(mesh->npoints == mesh->ntriangles * 3 && "Must be unwelded.");
1477 int ntriangles = mesh->ntriangles * 4;
1478 int npoints = ntriangles * 3;
1479 float* points = PAR_CALLOC(float, npoints * 3);
1480 float* dpoint = points;
1481 float const* spoint = mesh->points;
1482 for (int t = 0; t < mesh->ntriangles; t++, spoint += 9, dpoint += 3) {
1483 float const* a = spoint;
1484 float const* b = spoint + 3;
1485 float const* c = spoint + 6;
1486 float const* p0 = dpoint;
1487 float const* p1 = dpoint + 3;
1488 float const* p2 = dpoint + 6;
1489 par_shapes__mix3(dpoint, a, b, 0.5);
1490 par_shapes__mix3(dpoint += 3, b, c, 0.5);
1491 par_shapes__mix3(dpoint += 3, a, c, 0.5);
1492 par_shapes__add3(dpoint += 3, a);
1493 par_shapes__add3(dpoint += 3, p0);
1494 par_shapes__add3(dpoint += 3, p2);
1495 par_shapes__add3(dpoint += 3, p0);
1496 par_shapes__add3(dpoint += 3, b);
1497 par_shapes__add3(dpoint += 3, p1);
1498 par_shapes__add3(dpoint += 3, p2);
1499 par_shapes__add3(dpoint += 3, p1);
1500 par_shapes__add3(dpoint += 3, c);
1501 }
1502 PAR_FREE(mesh->points);
1503 mesh->points = points;
1504 mesh->npoints = npoints;
1505 mesh->ntriangles = ntriangles;
1506}
1507
1509{
1511 par_shapes_unweld(mesh, false);
1512 PAR_FREE(mesh->triangles);
1513 mesh->triangles = 0;
1514 while (nsubd--) {
1515 par_shapes__subdivide(mesh);
1516 }
1517 for (int i = 0; i < mesh->npoints; i++) {
1518 par_shapes__normalize3(mesh->points + i * 3);
1519 }
1520 mesh->triangles = PAR_MALLOC(PAR_SHAPES_T, 3 * mesh->ntriangles);
1521 for (int i = 0; i < mesh->ntriangles * 3; i++) {
1522 mesh->triangles[i] = i;
1523 }
1524 par_shapes_mesh* tmp = mesh;
1525 mesh = par_shapes_weld(mesh, 0.01, 0);
1528 return mesh;
1529}
1530
1531par_shapes_mesh* par_shapes_create_rock(int seed, int subd)
1532{
1534 struct osn_context* ctx;
1535 par__simplex_noise(seed, &ctx);
1536 for (int p = 0; p < mesh->npoints; p++) {
1537 float* pt = mesh->points + p * 3;
1538 float a = 0.25, f = 1.0;
1539 double n = a * par__simplex_noise2(ctx, f * pt[0], f * pt[2]);
1540 a *= 0.5; f *= 2;
1541 n += a * par__simplex_noise2(ctx, f * pt[0], f * pt[2]);
1542 pt[0] *= 1 + 2 * n;
1543 pt[1] *= 1 + n;
1544 pt[2] *= 1 + 2 * n;
1545 if (pt[1] < 0) {
1546 pt[1] = -pow(-pt[1], 0.5) / 2;
1547 }
1548 }
1549 par__simplex_noise_free(ctx);
1551 return mesh;
1552}
1553
1555 par_shapes_mesh* clone)
1556{
1557 if (!clone) {
1558 clone = PAR_CALLOC(par_shapes_mesh, 1);
1559 }
1560 clone->npoints = mesh->npoints;
1561 clone->points = PAR_REALLOC(float, clone->points, 3 * clone->npoints);
1562 memcpy(clone->points, mesh->points, sizeof(float) * 3 * clone->npoints);
1563 clone->ntriangles = mesh->ntriangles;
1564 clone->triangles = PAR_REALLOC(PAR_SHAPES_T, clone->triangles, 3 *
1565 clone->ntriangles);
1566 memcpy(clone->triangles, mesh->triangles,
1567 sizeof(PAR_SHAPES_T) * 3 * clone->ntriangles);
1568 if (mesh->normals) {
1569 clone->normals = PAR_REALLOC(float, clone->normals, 3 * clone->npoints);
1570 memcpy(clone->normals, mesh->normals,
1571 sizeof(float) * 3 * clone->npoints);
1572 }
1573 if (mesh->tcoords) {
1574 clone->tcoords = PAR_REALLOC(float, clone->tcoords, 2 * clone->npoints);
1575 memcpy(clone->tcoords, mesh->tcoords,
1576 sizeof(float) * 2 * clone->npoints);
1577 }
1578 return clone;
1579}
1580
1581static struct {
1582 float const* points;
1583 int gridsize;
1584} par_shapes__sort_context;
1585
1586static int par_shapes__cmp1(const void *arg0, const void *arg1)
1587{
1588 const int g = par_shapes__sort_context.gridsize;
1589
1590 // Convert arg0 into a flattened grid index.
1591 PAR_SHAPES_T d0 = *(const PAR_SHAPES_T*) arg0;
1592 float const* p0 = par_shapes__sort_context.points + d0 * 3;
1593 int i0 = (int) p0[0];
1594 int j0 = (int) p0[1];
1595 int k0 = (int) p0[2];
1596 int index0 = i0 + g * j0 + g * g * k0;
1597
1598 // Convert arg1 into a flattened grid index.
1599 PAR_SHAPES_T d1 = *(const PAR_SHAPES_T*) arg1;
1600 float const* p1 = par_shapes__sort_context.points + d1 * 3;
1601 int i1 = (int) p1[0];
1602 int j1 = (int) p1[1];
1603 int k1 = (int) p1[2];
1604 int index1 = i1 + g * j1 + g * g * k1;
1605
1606 // Return the ordering.
1607 if (index0 < index1) return -1;
1608 if (index0 > index1) return 1;
1609 return 0;
1610}
1611
1612static void par_shapes__sort_points(par_shapes_mesh* mesh, int gridsize,
1613 PAR_SHAPES_T* sortmap)
1614{
1615 // Run qsort over a list of consecutive integers that get deferenced
1616 // within the comparator function; this creates a reorder mapping.
1617 for (int i = 0; i < mesh->npoints; i++) {
1618 sortmap[i] = i;
1619 }
1620 par_shapes__sort_context.gridsize = gridsize;
1621 par_shapes__sort_context.points = mesh->points;
1622 qsort(sortmap, mesh->npoints, sizeof(PAR_SHAPES_T), par_shapes__cmp1);
1623
1624 // Apply the reorder mapping to the XYZ coordinate data.
1625 float* newpts = PAR_MALLOC(float, mesh->npoints * 3);
1626 PAR_SHAPES_T* invmap = PAR_MALLOC(PAR_SHAPES_T, mesh->npoints);
1627 float* dstpt = newpts;
1628 for (int i = 0; i < mesh->npoints; i++) {
1629 invmap[sortmap[i]] = i;
1630 float const* srcpt = mesh->points + 3 * sortmap[i];
1631 *dstpt++ = *srcpt++;
1632 *dstpt++ = *srcpt++;
1633 *dstpt++ = *srcpt++;
1634 }
1635 PAR_FREE(mesh->points);
1636 mesh->points = newpts;
1637
1638 // Apply the inverse reorder mapping to the triangle indices.
1639 PAR_SHAPES_T* newinds = PAR_MALLOC(PAR_SHAPES_T, mesh->ntriangles * 3);
1640 PAR_SHAPES_T* dstind = newinds;
1641 PAR_SHAPES_T const* srcind = mesh->triangles;
1642 for (int i = 0; i < mesh->ntriangles * 3; i++) {
1643 *dstind++ = invmap[*srcind++];
1644 }
1645 PAR_FREE(mesh->triangles);
1646 mesh->triangles = newinds;
1647
1648 // Cleanup.
1649 memcpy(sortmap, invmap, sizeof(PAR_SHAPES_T) * mesh->npoints);
1650 PAR_FREE(invmap);
1651}
1652
1653static void par_shapes__weld_points(par_shapes_mesh* mesh, int gridsize,
1654 float epsilon, PAR_SHAPES_T* weldmap)
1655{
1656 // Each bin contains a "pointer" (really an index) to its first point.
1657 // We add 1 because 0 is reserved to mean that the bin is empty.
1658 // Since the points are spatially sorted, there's no need to store
1659 // a point count in each bin.
1661 gridsize * gridsize * gridsize);
1662 int prev_binindex = -1;
1663 for (int p = 0; p < mesh->npoints; p++) {
1664 float const* pt = mesh->points + p * 3;
1665 int i = (int) pt[0];
1666 int j = (int) pt[1];
1667 int k = (int) pt[2];
1668 int this_binindex = i + gridsize * j + gridsize * gridsize * k;
1669 if (this_binindex != prev_binindex) {
1670 bins[this_binindex] = 1 + p;
1671 }
1672 prev_binindex = this_binindex;
1673 }
1674
1675 // Examine all bins that intersect the epsilon-sized cube centered at each
1676 // point, and check for colocated points within those bins.
1677 float const* pt = mesh->points;
1678 int nremoved = 0;
1679 for (int p = 0; p < mesh->npoints; p++, pt += 3) {
1680
1681 // Skip if this point has already been welded.
1682 if (weldmap[p] != p) {
1683 continue;
1684 }
1685
1686 // Build a list of bins that intersect the epsilon-sized cube.
1687 int nearby[8];
1688 int nbins = 0;
1689 int minp[3], maxp[3];
1690 for (int c = 0; c < 3; c++) {
1691 minp[c] = (int) (pt[c] - epsilon);
1692 maxp[c] = (int) (pt[c] + epsilon);
1693 }
1694 for (int i = minp[0]; i <= maxp[0]; i++) {
1695 for (int j = minp[1]; j <= maxp[1]; j++) {
1696 for (int k = minp[2]; k <= maxp[2]; k++) {
1697 int binindex = i + gridsize * j + gridsize * gridsize * k;
1698 PAR_SHAPES_T binvalue = *(bins + binindex);
1699 if (binvalue > 0) {
1700 if (nbins == 8) {
1701 printf("Epsilon value is too large.\n");
1702 break;
1703 }
1704 nearby[nbins++] = binindex;
1705 }
1706 }
1707 }
1708 }
1709
1710 // Check for colocated points in each nearby bin.
1711 for (int b = 0; b < nbins; b++) {
1712 int binindex = nearby[b];
1713 PAR_SHAPES_T binvalue = bins[binindex];
1714 PAR_SHAPES_T nindex = binvalue - 1;
1715 assert(nindex < mesh->npoints);
1716 while (true) {
1717
1718 // If this isn't "self" and it's colocated, then weld it!
1719 if (nindex != p && weldmap[nindex] == nindex) {
1720 float const* thatpt = mesh->points + nindex * 3;
1721 float dist2 = par_shapes__sqrdist3(thatpt, pt);
1722 if (dist2 < epsilon) {
1723 weldmap[nindex] = p;
1724 nremoved++;
1725 }
1726 }
1727
1728 // Advance to the next point if possible.
1729 if (++nindex >= mesh->npoints) {
1730 break;
1731 }
1732
1733 // If the next point is outside the bin, then we're done.
1734 float const* nextpt = mesh->points + nindex * 3;
1735 int i = (int) nextpt[0];
1736 int j = (int) nextpt[1];
1737 int k = (int) nextpt[2];
1738 int nextbinindex = i + gridsize * j + gridsize * gridsize * k;
1739 if (nextbinindex != binindex) {
1740 break;
1741 }
1742 }
1743 }
1744 }
1745 PAR_FREE(bins);
1746
1747 // Apply the weldmap to the vertices.
1748 int npoints = mesh->npoints - nremoved;
1749 float* newpts = PAR_MALLOC(float, 3 * npoints);
1750 float* dst = newpts;
1751 PAR_SHAPES_T* condensed_map = PAR_MALLOC(PAR_SHAPES_T, mesh->npoints);
1752 PAR_SHAPES_T* cmap = condensed_map;
1753 float const* src = mesh->points;
1754 int ci = 0;
1755 for (int p = 0; p < mesh->npoints; p++, src += 3) {
1756 if (weldmap[p] == p) {
1757 *dst++ = src[0];
1758 *dst++ = src[1];
1759 *dst++ = src[2];
1760 *cmap++ = ci++;
1761 } else {
1762 *cmap++ = condensed_map[weldmap[p]];
1763 }
1764 }
1765 assert(ci == npoints);
1766 PAR_FREE(mesh->points);
1767 memcpy(weldmap, condensed_map, mesh->npoints * sizeof(PAR_SHAPES_T));
1768 PAR_FREE(condensed_map);
1769 mesh->points = newpts;
1770 mesh->npoints = npoints;
1771
1772 // Apply the weldmap to the triangle indices and skip the degenerates.
1773 PAR_SHAPES_T const* tsrc = mesh->triangles;
1774 PAR_SHAPES_T* tdst = mesh->triangles;
1775 int ntriangles = 0;
1776 for (int i = 0; i < mesh->ntriangles; i++, tsrc += 3) {
1777 PAR_SHAPES_T a = weldmap[tsrc[0]];
1778 PAR_SHAPES_T b = weldmap[tsrc[1]];
1779 PAR_SHAPES_T c = weldmap[tsrc[2]];
1780 if (a != b && a != c && b != c) {
1781 assert(a < mesh->npoints);
1782 assert(b < mesh->npoints);
1783 assert(c < mesh->npoints);
1784 *tdst++ = a;
1785 *tdst++ = b;
1786 *tdst++ = c;
1787 ntriangles++;
1788 }
1789 }
1790 mesh->ntriangles = ntriangles;
1791}
1792
1793par_shapes_mesh* par_shapes_weld(par_shapes_mesh const* mesh, float epsilon,
1794 PAR_SHAPES_T* weldmap)
1795{
1796 par_shapes_mesh* clone = par_shapes_clone(mesh, 0);
1797 float aabb[6];
1798 int gridsize = 20;
1799 float maxcell = gridsize - 1;
1800 par_shapes_compute_aabb(clone, aabb);
1801 float scale[3] = {
1802 aabb[3] == aabb[0] ? 1.0f : maxcell / (aabb[3] - aabb[0]),
1803 aabb[4] == aabb[1] ? 1.0f : maxcell / (aabb[4] - aabb[1]),
1804 aabb[5] == aabb[2] ? 1.0f : maxcell / (aabb[5] - aabb[2]),
1805 };
1806 par_shapes_translate(clone, -aabb[0], -aabb[1], -aabb[2]);
1807 par_shapes_scale(clone, scale[0], scale[1], scale[2]);
1808 PAR_SHAPES_T* sortmap = PAR_MALLOC(PAR_SHAPES_T, mesh->npoints);
1809 par_shapes__sort_points(clone, gridsize, sortmap);
1810 bool owner = false;
1811 if (!weldmap) {
1812 owner = true;
1813 weldmap = PAR_MALLOC(PAR_SHAPES_T, mesh->npoints);
1814 }
1815 for (int i = 0; i < mesh->npoints; i++) {
1816 weldmap[i] = i;
1817 }
1818 par_shapes__weld_points(clone, gridsize, epsilon, weldmap);
1819 if (owner) {
1820 PAR_FREE(weldmap);
1821 } else {
1822 PAR_SHAPES_T* newmap = PAR_MALLOC(PAR_SHAPES_T, mesh->npoints);
1823 for (int i = 0; i < mesh->npoints; i++) {
1824 newmap[i] = weldmap[sortmap[i]];
1825 }
1826 memcpy(weldmap, newmap, sizeof(PAR_SHAPES_T) * mesh->npoints);
1827 PAR_FREE(newmap);
1828 }
1829 PAR_FREE(sortmap);
1830 par_shapes_scale(clone, 1.0 / scale[0], 1.0 / scale[1], 1.0 / scale[2]);
1831 par_shapes_translate(clone, aabb[0], aabb[1], aabb[2]);
1832 return clone;
1833}
1834
1835// -----------------------------------------------------------------------------
1836// BEGIN OPEN SIMPLEX NOISE
1837// -----------------------------------------------------------------------------
1838
1839#define STRETCH_CONSTANT_2D (-0.211324865405187) // (1 / sqrt(2 + 1) - 1 ) / 2;
1840#define SQUISH_CONSTANT_2D (0.366025403784439) // (sqrt(2 + 1) -1) / 2;
1841#define STRETCH_CONSTANT_3D (-1.0 / 6.0) // (1 / sqrt(3 + 1) - 1) / 3;
1842#define SQUISH_CONSTANT_3D (1.0 / 3.0) // (sqrt(3+1)-1)/3;
1843#define STRETCH_CONSTANT_4D (-0.138196601125011) // (1 / sqrt(4 + 1) - 1) / 4;
1844#define SQUISH_CONSTANT_4D (0.309016994374947) // (sqrt(4 + 1) - 1) / 4;
1845
1846#define NORM_CONSTANT_2D (47.0)
1847#define NORM_CONSTANT_3D (103.0)
1848#define NORM_CONSTANT_4D (30.0)
1849
1850#define DEFAULT_SEED (0LL)
1851
1852struct osn_context {
1853 int16_t* perm;
1854 int16_t* permGradIndex3D;
1855};
1856
1857#define ARRAYSIZE(x) (sizeof((x)) / sizeof((x)[0]))
1858
1859/*
1860 * Gradients for 2D. They approximate the directions to the
1861 * vertices of an octagon from the center.
1862 */
1863static const int8_t gradients2D[] = {
1864 5, 2, 2, 5, -5, 2, -2, 5, 5, -2, 2, -5, -5, -2, -2, -5,
1865};
1866
1867/*
1868 * Gradients for 3D. They approximate the directions to the
1869 * vertices of a rhombicuboctahedron from the center, skewed so
1870 * that the triangular and square facets can be inscribed inside
1871 * circles of the same radius.
1872 */
1873static const signed char gradients3D[] = {
1874 -11, 4, 4, -4, 11, 4, -4, 4, 11, 11, 4, 4, 4, 11, 4, 4, 4, 11, -11, -4, 4,
1875 -4, -11, 4, -4, -4, 11, 11, -4, 4, 4, -11, 4, 4, -4, 11, -11, 4, -4, -4, 11,
1876 -4, -4, 4, -11, 11, 4, -4, 4, 11, -4, 4, 4, -11, -11, -4, -4, -4, -11, -4,
1877 -4, -4, -11, 11, -4, -4, 4, -11, -4, 4, -4, -11,
1878};
1879
1880/*
1881 * Gradients for 4D. They approximate the directions to the
1882 * vertices of a disprismatotesseractihexadecachoron from the center,
1883 * skewed so that the tetrahedral and cubic facets can be inscribed inside
1884 * spheres of the same radius.
1885 */
1886static const signed char gradients4D[] = {
1887 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, -3, 1, 1, 1, -1, 3, 1, 1,
1888 -1, 1, 3, 1, -1, 1, 1, 3, 3, -1, 1, 1, 1, -3, 1, 1, 1, -1, 3, 1, 1, -1, 1,
1889 3, -3, -1, 1, 1, -1, -3, 1, 1, -1, -1, 3, 1, -1, -1, 1, 3, 3, 1, -1, 1, 1,
1890 3, -1, 1, 1, 1, -3, 1, 1, 1, -1, 3, -3, 1, -1, 1, -1, 3, -1, 1, -1, 1, -3,
1891 1, -1, 1, -1, 3, 3, -1, -1, 1, 1, -3, -1, 1, 1, -1, -3, 1, 1, -1, -1, 3, -3,
1892 -1, -1, 1, -1, -3, -1, 1, -1, -1, -3, 1, -1, -1, -1, 3, 3, 1, 1, -1, 1, 3,
1893 1, -1, 1, 1, 3, -1, 1, 1, 1, -3, -3, 1, 1, -1, -1, 3, 1, -1, -1, 1, 3, -1,
1894 -1, 1, 1, -3, 3, -1, 1, -1, 1, -3, 1, -1, 1, -1, 3, -1, 1, -1, 1, -3, -3,
1895 -1, 1, -1, -1, -3, 1, -1, -1, -1, 3, -1, -1, -1, 1, -3, 3, 1, -1, -1, 1, 3,
1896 -1, -1, 1, 1, -3, -1, 1, 1, -1, -3, -3, 1, -1, -1, -1, 3, -1, -1, -1, 1, -3,
1897 -1, -1, 1, -1, -3, 3, -1, -1, -1, 1, -3, -1, -1, 1, -1, -3, -1, 1, -1, -1,
1898 -3, -3, -1, -1, -1, -1, -3, -1, -1, -1, -1, -3, -1, -1, -1, -1, -3,
1899};
1900
1901static double extrapolate2(
1902 struct osn_context* ctx, int xsb, int ysb, double dx, double dy)
1903{
1904 int16_t* perm = ctx->perm;
1905 int index = perm[(perm[xsb & 0xFF] + ysb) & 0xFF] & 0x0E;
1906 return gradients2D[index] * dx + gradients2D[index + 1] * dy;
1907}
1908
1909static inline int fastFloor(double x)
1910{
1911 int xi = (int) x;
1912 return x < xi ? xi - 1 : xi;
1913}
1914
1915static int allocate_perm(struct osn_context* ctx, int nperm, int ngrad)
1916{
1917 PAR_FREE(ctx->perm);
1918 PAR_FREE(ctx->permGradIndex3D);
1919 ctx->perm = PAR_MALLOC(int16_t, nperm);
1920 if (!ctx->perm) {
1921 return -ENOMEM;
1922 }
1923 ctx->permGradIndex3D = PAR_MALLOC(int16_t, ngrad);
1924 if (!ctx->permGradIndex3D) {
1925 PAR_FREE(ctx->perm);
1926 return -ENOMEM;
1927 }
1928 return 0;
1929}
1930
1931static int par__simplex_noise(int64_t seed, struct osn_context** ctx)
1932{
1933 int rc;
1934 int16_t source[256];
1935 int i;
1936 int16_t* perm;
1937 int16_t* permGradIndex3D;
1938 *ctx = PAR_MALLOC(struct osn_context, 1);
1939 if (!(*ctx)) {
1940 return -ENOMEM;
1941 }
1942 (*ctx)->perm = NULL;
1943 (*ctx)->permGradIndex3D = NULL;
1944 rc = allocate_perm(*ctx, 256, 256);
1945 if (rc) {
1946 PAR_FREE(*ctx);
1947 return rc;
1948 }
1949 perm = (*ctx)->perm;
1950 permGradIndex3D = (*ctx)->permGradIndex3D;
1951 for (i = 0; i < 256; i++) {
1952 source[i] = (int16_t) i;
1953 }
1954 seed = seed * 6364136223846793005LL + 1442695040888963407LL;
1955 seed = seed * 6364136223846793005LL + 1442695040888963407LL;
1956 seed = seed * 6364136223846793005LL + 1442695040888963407LL;
1957 for (i = 255; i >= 0; i--) {
1958 seed = seed * 6364136223846793005LL + 1442695040888963407LL;
1959 int r = (int) ((seed + 31) % (i + 1));
1960 if (r < 0)
1961 r += (i + 1);
1962 perm[i] = source[r];
1963 permGradIndex3D[i] =
1964 (short) ((perm[i] % (ARRAYSIZE(gradients3D) / 3)) * 3);
1965 source[r] = source[i];
1966 }
1967 return 0;
1968}
1969
1970static void par__simplex_noise_free(struct osn_context* ctx)
1971{
1972 if (!ctx)
1973 return;
1974 if (ctx->perm) {
1975 PAR_FREE(ctx->perm);
1976 ctx->perm = NULL;
1977 }
1978 if (ctx->permGradIndex3D) {
1979 PAR_FREE(ctx->permGradIndex3D);
1980 ctx->permGradIndex3D = NULL;
1981 }
1982 PAR_FREE(ctx);
1983}
1984
1985static double par__simplex_noise2(struct osn_context* ctx, double x, double y)
1986{
1987 // Place input coordinates onto grid.
1988 double stretchOffset = (x + y) * STRETCH_CONSTANT_2D;
1989 double xs = x + stretchOffset;
1990 double ys = y + stretchOffset;
1991
1992 // Floor to get grid coordinates of rhombus (stretched square) super-cell
1993 // origin.
1994 int xsb = fastFloor(xs);
1995 int ysb = fastFloor(ys);
1996
1997 // Skew out to get actual coordinates of rhombus origin. We'll need these
1998 // later.
1999 double squishOffset = (xsb + ysb) * SQUISH_CONSTANT_2D;
2000 double xb = xsb + squishOffset;
2001 double yb = ysb + squishOffset;
2002
2003 // Compute grid coordinates relative to rhombus origin.
2004 double xins = xs - xsb;
2005 double yins = ys - ysb;
2006
2007 // Sum those together to get a value that determines which region we're in.
2008 double inSum = xins + yins;
2009
2010 // Positions relative to origin point.
2011 double dx0 = x - xb;
2012 double dy0 = y - yb;
2013
2014 // We'll be defining these inside the next block and using them afterwards.
2015 double dx_ext, dy_ext;
2016 int xsv_ext, ysv_ext;
2017
2018 double value = 0;
2019
2020 // Contribution (1,0)
2021 double dx1 = dx0 - 1 - SQUISH_CONSTANT_2D;
2022 double dy1 = dy0 - 0 - SQUISH_CONSTANT_2D;
2023 double attn1 = 2 - dx1 * dx1 - dy1 * dy1;
2024 if (attn1 > 0) {
2025 attn1 *= attn1;
2026 value += attn1 * attn1 * extrapolate2(ctx, xsb + 1, ysb + 0, dx1, dy1);
2027 }
2028
2029 // Contribution (0,1)
2030 double dx2 = dx0 - 0 - SQUISH_CONSTANT_2D;
2031 double dy2 = dy0 - 1 - SQUISH_CONSTANT_2D;
2032 double attn2 = 2 - dx2 * dx2 - dy2 * dy2;
2033 if (attn2 > 0) {
2034 attn2 *= attn2;
2035 value += attn2 * attn2 * extrapolate2(ctx, xsb + 0, ysb + 1, dx2, dy2);
2036 }
2037
2038 if (inSum <= 1) { // We're inside the triangle (2-Simplex) at (0,0)
2039 double zins = 1 - inSum;
2040 if (zins > xins || zins > yins) {
2041 if (xins > yins) {
2042 xsv_ext = xsb + 1;
2043 ysv_ext = ysb - 1;
2044 dx_ext = dx0 - 1;
2045 dy_ext = dy0 + 1;
2046 } else {
2047 xsv_ext = xsb - 1;
2048 ysv_ext = ysb + 1;
2049 dx_ext = dx0 + 1;
2050 dy_ext = dy0 - 1;
2051 }
2052 } else { //(1,0) and (0,1) are the closest two vertices.
2053 xsv_ext = xsb + 1;
2054 ysv_ext = ysb + 1;
2055 dx_ext = dx0 - 1 - 2 * SQUISH_CONSTANT_2D;
2056 dy_ext = dy0 - 1 - 2 * SQUISH_CONSTANT_2D;
2057 }
2058 } else { // We're inside the triangle (2-Simplex) at (1,1)
2059 double zins = 2 - inSum;
2060 if (zins < xins || zins < yins) {
2061 if (xins > yins) {
2062 xsv_ext = xsb + 2;
2063 ysv_ext = ysb + 0;
2064 dx_ext = dx0 - 2 - 2 * SQUISH_CONSTANT_2D;
2065 dy_ext = dy0 + 0 - 2 * SQUISH_CONSTANT_2D;
2066 } else {
2067 xsv_ext = xsb + 0;
2068 ysv_ext = ysb + 2;
2069 dx_ext = dx0 + 0 - 2 * SQUISH_CONSTANT_2D;
2070 dy_ext = dy0 - 2 - 2 * SQUISH_CONSTANT_2D;
2071 }
2072 } else { //(1,0) and (0,1) are the closest two vertices.
2073 dx_ext = dx0;
2074 dy_ext = dy0;
2075 xsv_ext = xsb;
2076 ysv_ext = ysb;
2077 }
2078 xsb += 1;
2079 ysb += 1;
2080 dx0 = dx0 - 1 - 2 * SQUISH_CONSTANT_2D;
2081 dy0 = dy0 - 1 - 2 * SQUISH_CONSTANT_2D;
2082 }
2083
2084 // Contribution (0,0) or (1,1)
2085 double attn0 = 2 - dx0 * dx0 - dy0 * dy0;
2086 if (attn0 > 0) {
2087 attn0 *= attn0;
2088 value += attn0 * attn0 * extrapolate2(ctx, xsb, ysb, dx0, dy0);
2089 }
2090
2091 // Extra Vertex
2092 double attn_ext = 2 - dx_ext * dx_ext - dy_ext * dy_ext;
2093 if (attn_ext > 0) {
2094 attn_ext *= attn_ext;
2095 value += attn_ext * attn_ext *
2096 extrapolate2(ctx, xsv_ext, ysv_ext, dx_ext, dy_ext);
2097 }
2098
2099 return value / NORM_CONSTANT_2D;
2100}
2101
2102void par_shapes_remove_degenerate(par_shapes_mesh* mesh, float mintriarea)
2103{
2104 int ntriangles = 0;
2105 PAR_SHAPES_T* triangles = PAR_MALLOC(PAR_SHAPES_T, mesh->ntriangles * 3);
2106 PAR_SHAPES_T* dst = triangles;
2107 PAR_SHAPES_T const* src = mesh->triangles;
2108 float next[3], prev[3], cp[3];
2109 float mincplen2 = (mintriarea * 2) * (mintriarea * 2);
2110 for (int f = 0; f < mesh->ntriangles; f++, src += 3) {
2111 float const* pa = mesh->points + 3 * src[0];
2112 float const* pb = mesh->points + 3 * src[1];
2113 float const* pc = mesh->points + 3 * src[2];
2114 par_shapes__copy3(next, pb);
2115 par_shapes__subtract3(next, pa);
2116 par_shapes__copy3(prev, pc);
2117 par_shapes__subtract3(prev, pa);
2118 par_shapes__cross3(cp, next, prev);
2119 float cplen2 = par_shapes__dot3(cp, cp);
2120 if (cplen2 >= mincplen2) {
2121 *dst++ = src[0];
2122 *dst++ = src[1];
2123 *dst++ = src[2];
2124 ntriangles++;
2125 }
2126 }
2127 mesh->ntriangles = ntriangles;
2128 PAR_FREE(mesh->triangles);
2129 mesh->triangles = triangles;
2130}
2131
2132#endif // PAR_SHAPES_IMPLEMENTATION
2133#endif // PAR_SHAPES_H
2134
2135// par_shapes is distributed under the MIT license:
2136//
2137// Copyright (c) 2019 Philip Rideout
2138//
2139// Permission is hereby granted, free of charge, to any person obtaining a copy
2140// of this software and associated documentation files (the "Software"), to deal
2141// in the Software without restriction, including without limitation the rights
2142// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2143// copies of the Software, and to permit persons to whom the Software is
2144// furnished to do so, subject to the following conditions:
2145//
2146// The above copyright notice and this permission notice shall be included in
2147// all copies or substantial portions of the Software.
2148//
2149// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2150// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2151// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2152// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2153// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2154// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2155// SOFTWARE.
#define NULL
Definition: miniaudio.h:3718
void par_shapes_compute_aabb(par_shapes_mesh const *mesh, float *aabb)
void par_shapes_merge_and_free(par_shapes_mesh *dst, par_shapes_mesh *src)
par_shapes_mesh * par_shapes_create_dodecahedron()
void par_shapes_invert(par_shapes_mesh *, int startface, int nfaces)
par_shapes_mesh * par_shapes_create_parametric_sphere(int slices, int stacks)
par_shapes_mesh * par_shapes_create_cube()
#define PAR_FREE(BUF)
Definition: par_shapes.h:205
void par_shapes_remove_degenerate(par_shapes_mesh *, float minarea)
void par_shapes_scale(par_shapes_mesh *, float x, float y, float z)
par_shapes_mesh * par_shapes_create_cone(int slices, int stacks)
void par_shapes_free_mesh(par_shapes_mesh *)
void par_shapes__compute_welded_normals(par_shapes_mesh *m)
par_shapes_mesh * par_shapes_create_cylinder(int slices, int stacks)
par_shapes_mesh * par_shapes_create_parametric_disk(int slices, int stacks)
#define PAR_REALLOC(T, BUF, N)
Definition: par_shapes.h:204
#define PAR_PI
Definition: par_shapes.h:193
par_shapes_mesh * par_shapes_create_empty()
par_shapes_mesh * par_shapes_create_torus(int slices, int stacks, float radius)
void par_shapes_unweld(par_shapes_mesh *mesh, bool create_indices)
par_shapes_mesh * par_shapes_create_plane(int slices, int stacks)
par_shapes_mesh * par_shapes_create_disk(float radius, int slices, float const *center, float const *normal)
par_shapes_mesh * par_shapes_create_trefoil_knot(int slices, int stacks, float radius)
void par_shapes_set_epsilon_welded_normals(float epsilon)
void par_shapes_set_epsilon_degenerate_sphere(float epsilon)
void par_shapes_export(par_shapes_mesh const *, char const *objfile)
par_shapes_mesh * par_shapes_create_rock(int seed, int nsubdivisions)
void par_shapes_compute_normals(par_shapes_mesh *m)
#define PAR_MAX(a, b)
Definition: par_shapes.h:195
void par_shapes_translate(par_shapes_mesh *, float x, float y, float z)
#define PAR_MALLOC(T, N)
Definition: par_shapes.h:202
par_shapes_mesh * par_shapes_create_hemisphere(int slices, int stacks)
par_shapes_mesh * par_shapes_create_tetrahedron()
par_shapes_mesh * par_shapes_create_octahedron()
par_shapes_mesh * par_shapes_clone(par_shapes_mesh const *mesh, par_shapes_mesh *target)
void par_shapes__connect(par_shapes_mesh *scene, par_shapes_mesh *cylinder, int slices)
struct par_shapes_mesh_s par_shapes_mesh
#define PAR_SHAPES_T
Definition: par_shapes.h:50
void par_shapes_merge(par_shapes_mesh *dst, par_shapes_mesh const *src)
#define PAR_SWAP(T, A, B)
Definition: par_shapes.h:197
par_shapes_mesh * par_shapes_create_parametric(par_shapes_fn, int slices, int stacks, void *userdata)
par_shapes_mesh * par_shapes_create_subdivided_sphere(int nsubdivisions)
par_shapes_mesh * par_shapes_create_lsystem(char const *program, int slices, int maxdepth)
#define PAR_MIN(a, b)
Definition: par_shapes.h:194
void(* par_shapes_fn)(float const *, float *, void *)
Definition: par_shapes.h:101
#define PAR_CALLOC(T, N)
Definition: par_shapes.h:203
par_shapes_mesh * par_shapes_create_icosahedron()
void par_shapes_rotate(par_shapes_mesh *, float radians, float const *axis)
par_shapes_mesh * par_shapes_create_klein_bottle(int slices, int stacks)
par_shapes_mesh * par_shapes_weld(par_shapes_mesh const *, float epsilon, PAR_SHAPES_T *mapping)
signed short int16_t
Definition: stdint.h:76
signed __int64 int64_t
Definition: stdint.h:89
signed char int8_t
Definition: stdint.h:75
PAR_SHAPES_T * triangles
Definition: par_shapes.h:56