ADDED: GenMeshCone() #1903
This commit is contained in:
parent
e6fe8169c2
commit
5e63cd3c97
3 changed files with 188 additions and 31 deletions
163
src/external/par_shapes.h
vendored
163
src/external/par_shapes.h
vendored
|
@ -21,8 +21,7 @@
|
|||
// coordinates (one per vertex). That's it! If you need something fancier,
|
||||
// look elsewhere.
|
||||
//
|
||||
// The MIT License
|
||||
// Copyright (c) 2015 Philip Rideout
|
||||
// Distributed under the MIT License, see bottom of file.
|
||||
|
||||
#ifndef PAR_SHAPES_H
|
||||
#define PAR_SHAPES_H
|
||||
|
@ -32,21 +31,17 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Ray: commented to avoid conflict with raylib bool
|
||||
/*
|
||||
#if !defined(_MSC_VER)
|
||||
# include <stdbool.h>
|
||||
#else // MSVC
|
||||
# if _MSC_VER >= 1800
|
||||
# include <stdbool.h>
|
||||
# else // stdbool.h missing prior to MSVC++ 12.0 (VS2013)
|
||||
//# define bool int
|
||||
//# define true 1
|
||||
//# define false 0
|
||||
# define bool int
|
||||
# define true 1
|
||||
# define false 0
|
||||
# endif
|
||||
#endif
|
||||
*/
|
||||
|
||||
#ifndef PAR_SHAPES_T
|
||||
#define PAR_SHAPES_T uint16_t
|
||||
|
@ -71,6 +66,14 @@ void par_shapes_free_mesh(par_shapes_mesh*);
|
|||
// both 1.0, but they can easily be changed with par_shapes_scale.
|
||||
par_shapes_mesh* par_shapes_create_cylinder(int slices, int stacks);
|
||||
|
||||
// Cone is similar to cylinder but the radius diminishes to zero as Z increases.
|
||||
// Again, height and radius are 1.0, but can be changed with par_shapes_scale.
|
||||
par_shapes_mesh* par_shapes_create_cone(int slices, int stacks);
|
||||
|
||||
// Create a disk of radius 1.0 with texture coordinates and normals by squashing
|
||||
// a cone flat on the Z=0 plane.
|
||||
par_shapes_mesh* par_shapes_create_parametric_disk(int slices, int stacks);
|
||||
|
||||
// Create a donut that sits on the Z=0 plane with the specified inner radius.
|
||||
// The outer radius can be controlled with par_shapes_scale.
|
||||
par_shapes_mesh* par_shapes_create_torus(int slices, int stacks, float radius);
|
||||
|
@ -172,6 +175,17 @@ par_shapes_mesh* par_shapes_weld(par_shapes_mesh const*, float epsilon,
|
|||
// Compute smooth normals by averaging adjacent facet normals.
|
||||
void par_shapes_compute_normals(par_shapes_mesh* m);
|
||||
|
||||
// Global Config ---------------------------------------------------------------
|
||||
|
||||
void par_shapes_set_epsilon_welded_normals(float epsilon);
|
||||
void par_shapes_set_epsilon_degenerate_sphere(float epsilon);
|
||||
|
||||
// Advanced --------------------------------------------------------------------
|
||||
|
||||
void par_shapes__compute_welded_normals(par_shapes_mesh* m);
|
||||
void par_shapes__connect(par_shapes_mesh* scene, par_shapes_mesh* cylinder,
|
||||
int slices);
|
||||
|
||||
#ifndef PAR_PI
|
||||
#define PAR_PI (3.14159265359)
|
||||
#define PAR_MIN(a, b) (a > b ? b : a)
|
||||
|
@ -205,11 +219,15 @@ void par_shapes_compute_normals(par_shapes_mesh* m);
|
|||
#include <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
static float par_shapes__epsilon_welded_normals = 0.001;
|
||||
static float par_shapes__epsilon_degenerate_sphere = 0.0001;
|
||||
|
||||
static void par_shapes__sphere(float const* uv, float* xyz, void*);
|
||||
static void par_shapes__hemisphere(float const* uv, float* xyz, void*);
|
||||
static void par_shapes__plane(float const* uv, float* xyz, void*);
|
||||
static void par_shapes__klein(float const* uv, float* xyz, void*);
|
||||
static void par_shapes__cylinder(float const* uv, float* xyz, void*);
|
||||
static void par_shapes__cone(float const* uv, float* xyz, void*);
|
||||
static void par_shapes__torus(float const* uv, float* xyz, void*);
|
||||
static void par_shapes__trefoil(float const* uv, float* xyz, void*);
|
||||
|
||||
|
@ -298,11 +316,12 @@ static float par_shapes__sqrdist3(float const* a, float const* b)
|
|||
return dx * dx + dy * dy + dz * dz;
|
||||
}
|
||||
|
||||
static void par_shapes__compute_welded_normals(par_shapes_mesh* m)
|
||||
void par_shapes__compute_welded_normals(par_shapes_mesh* m)
|
||||
{
|
||||
const float epsilon = par_shapes__epsilon_welded_normals;
|
||||
m->normals = PAR_MALLOC(float, m->npoints * 3);
|
||||
PAR_SHAPES_T* weldmap = PAR_MALLOC(PAR_SHAPES_T, m->npoints);
|
||||
par_shapes_mesh* welded = par_shapes_weld(m, 0.01, weldmap);
|
||||
par_shapes_mesh* welded = par_shapes_weld(m, epsilon, weldmap);
|
||||
par_shapes_compute_normals(welded);
|
||||
float* pdst = m->normals;
|
||||
for (int i = 0; i < m->npoints; i++, pdst += 3) {
|
||||
|
@ -325,6 +344,24 @@ par_shapes_mesh* par_shapes_create_cylinder(int slices, int stacks)
|
|||
stacks, 0);
|
||||
}
|
||||
|
||||
par_shapes_mesh* par_shapes_create_cone(int slices, int stacks)
|
||||
{
|
||||
if (slices < 3 || stacks < 1) {
|
||||
return 0;
|
||||
}
|
||||
return par_shapes_create_parametric(par_shapes__cone, slices,
|
||||
stacks, 0);
|
||||
}
|
||||
|
||||
par_shapes_mesh* par_shapes_create_parametric_disk(int slices, int stacks)
|
||||
{
|
||||
par_shapes_mesh* m = par_shapes_create_cone(slices, stacks);
|
||||
if (m) {
|
||||
par_shapes_scale(m, 1.0f, 1.0f, 0.0f);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
par_shapes_mesh* par_shapes_create_parametric_sphere(int slices, int stacks)
|
||||
{
|
||||
if (slices < 3 || stacks < 3) {
|
||||
|
@ -332,7 +369,7 @@ par_shapes_mesh* par_shapes_create_parametric_sphere(int slices, int stacks)
|
|||
}
|
||||
par_shapes_mesh* m = par_shapes_create_parametric(par_shapes__sphere,
|
||||
slices, stacks, 0);
|
||||
par_shapes_remove_degenerate(m, 0.0001);
|
||||
par_shapes_remove_degenerate(m, par_shapes__epsilon_degenerate_sphere);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
@ -343,7 +380,7 @@ par_shapes_mesh* par_shapes_create_hemisphere(int slices, int stacks)
|
|||
}
|
||||
par_shapes_mesh* m = par_shapes_create_parametric(par_shapes__hemisphere,
|
||||
slices, stacks, 0);
|
||||
par_shapes_remove_degenerate(m, 0.0001);
|
||||
par_shapes_remove_degenerate(m, par_shapes__epsilon_degenerate_sphere);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
@ -579,6 +616,15 @@ static void par_shapes__cylinder(float const* uv, float* xyz, void* userdata)
|
|||
xyz[2] = uv[0];
|
||||
}
|
||||
|
||||
static void par_shapes__cone(float const* uv, float* xyz, void* userdata)
|
||||
{
|
||||
float r = 1.0f - uv[0];
|
||||
float theta = uv[1] * 2 * PAR_PI;
|
||||
xyz[0] = r * sinf(theta);
|
||||
xyz[1] = r * cosf(theta);
|
||||
xyz[2] = uv[0];
|
||||
}
|
||||
|
||||
static void par_shapes__torus(float const* uv, float* xyz, void* userdata)
|
||||
{
|
||||
float major = 1;
|
||||
|
@ -620,6 +666,14 @@ static void par_shapes__trefoil(float const* uv, float* xyz, void* userdata)
|
|||
xyz[2] = z + d * ww[2] * sin(v);
|
||||
}
|
||||
|
||||
void par_shapes_set_epsilon_welded_normals(float epsilon) {
|
||||
par_shapes__epsilon_welded_normals = epsilon;
|
||||
}
|
||||
|
||||
void par_shapes_set_epsilon_degenerate_sphere(float epsilon) {
|
||||
par_shapes__epsilon_degenerate_sphere = epsilon;
|
||||
}
|
||||
|
||||
void par_shapes_merge(par_shapes_mesh* dst, par_shapes_mesh const* src)
|
||||
{
|
||||
PAR_SHAPES_T offset = dst->npoints;
|
||||
|
@ -744,15 +798,15 @@ void par_shapes_rotate(par_shapes_mesh* mesh, float radians, float const* axis)
|
|||
p[1] = y;
|
||||
p[2] = z;
|
||||
}
|
||||
p = mesh->normals;
|
||||
if (p) {
|
||||
for (int i = 0; i < mesh->npoints; i++, p += 3) {
|
||||
float x = col0[0] * p[0] + col1[0] * p[1] + col2[0] * p[2];
|
||||
float y = col0[1] * p[0] + col1[1] * p[1] + col2[1] * p[2];
|
||||
float z = col0[2] * p[0] + col1[2] * p[1] + col2[2] * p[2];
|
||||
p[0] = x;
|
||||
p[1] = y;
|
||||
p[2] = z;
|
||||
float* n = mesh->normals;
|
||||
if (n) {
|
||||
for (int i = 0; i < mesh->npoints; i++, n += 3) {
|
||||
float x = col0[0] * n[0] + col1[0] * n[1] + col2[0] * n[2];
|
||||
float y = col0[1] * n[0] + col1[1] * n[1] + col2[1] * n[2];
|
||||
float z = col0[2] * n[0] + col1[2] * n[1] + col2[2] * n[2];
|
||||
n[0] = x;
|
||||
n[1] = y;
|
||||
n[2] = z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -765,6 +819,27 @@ void par_shapes_scale(par_shapes_mesh* m, float x, float y, float z)
|
|||
*points++ *= y;
|
||||
*points++ *= z;
|
||||
}
|
||||
float* n = m->normals;
|
||||
if (n && !(x == y && y == z)) {
|
||||
bool x_zero = x == 0;
|
||||
bool y_zero = y == 0;
|
||||
bool z_zero = z == 0;
|
||||
if (!x_zero && !y_zero && !z_zero) {
|
||||
x = 1.0f / x;
|
||||
y = 1.0f / y;
|
||||
z = 1.0f / z;
|
||||
} else {
|
||||
x = x_zero && !y_zero && !z_zero;
|
||||
y = y_zero && !x_zero && !z_zero;
|
||||
z = z_zero && !x_zero && !y_zero;
|
||||
}
|
||||
for (int i = 0; i < m->npoints; i++, n += 3) {
|
||||
n[0] *= x;
|
||||
n[1] *= y;
|
||||
n[2] *= z;
|
||||
par_shapes__normalize3(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void par_shapes_merge_and_free(par_shapes_mesh* dst, par_shapes_mesh* src)
|
||||
|
@ -1098,8 +1173,8 @@ static par_shapes_mesh* par_shapes__apply_turtle(par_shapes_mesh* mesh,
|
|||
return m;
|
||||
}
|
||||
|
||||
static void par_shapes__connect(par_shapes_mesh* scene,
|
||||
par_shapes_mesh* cylinder, int slices)
|
||||
void par_shapes__connect(par_shapes_mesh* scene, par_shapes_mesh* cylinder,
|
||||
int slices)
|
||||
{
|
||||
int stacks = 1;
|
||||
int npoints = (slices + 1) * (stacks + 1);
|
||||
|
@ -1118,7 +1193,8 @@ static void par_shapes__connect(par_shapes_mesh* scene,
|
|||
// Create the new triangle list.
|
||||
int ntriangles = scene->ntriangles + 2 * slices * stacks;
|
||||
PAR_SHAPES_T* triangles = PAR_MALLOC(PAR_SHAPES_T, ntriangles * 3);
|
||||
memcpy(triangles, scene->triangles, 2 * scene->ntriangles * 3);
|
||||
memcpy(triangles, scene->triangles,
|
||||
sizeof(PAR_SHAPES_T) * scene->ntriangles * 3);
|
||||
int v = scene->npoints - (slices + 1);
|
||||
PAR_SHAPES_T* face = triangles + scene->ntriangles * 3;
|
||||
for (int stack = 0; stack < stacks; stack++) {
|
||||
|
@ -1154,7 +1230,7 @@ par_shapes_mesh* par_shapes_create_lsystem(char const* text, int slices,
|
|||
while (cmd) {
|
||||
char *arg = strtok(0, " ");
|
||||
if (!arg) {
|
||||
//puts("lsystem error: unexpected end of program.");
|
||||
puts("lsystem error: unexpected end of program.");
|
||||
break;
|
||||
}
|
||||
if (!strcmp(cmd, "rule")) {
|
||||
|
@ -1208,7 +1284,6 @@ par_shapes_mesh* par_shapes_create_lsystem(char const* text, int slices,
|
|||
|
||||
// For testing purposes, dump out the parsed program.
|
||||
#ifdef TEST_PARSE
|
||||
/*
|
||||
for (int i = 0; i < nrules; i++) {
|
||||
par_shapes__rule rule = rules[i];
|
||||
printf("rule %s.%d\n", rule.name, rule.weight);
|
||||
|
@ -1217,7 +1292,6 @@ par_shapes_mesh* par_shapes_create_lsystem(char const* text, int slices,
|
|||
printf("\t%s %s\n", cmd.cmd, cmd.arg);
|
||||
}
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
// Instantiate the aggregated shape and the template shapes.
|
||||
|
@ -1258,7 +1332,8 @@ par_shapes_mesh* par_shapes_create_lsystem(char const* text, int slices,
|
|||
|
||||
par_shapes__command* cmd = rule->commands + (frame->pc++);
|
||||
#ifdef DUMP_TRACE
|
||||
//printf("%5s %5s %5s:%d %03d\n", cmd->cmd, cmd->arg, rule->name, frame->pc - 1, stackptr);
|
||||
printf("%5s %5s %5s:%d %03d\n", cmd->cmd, cmd->arg, rule->name,
|
||||
frame->pc - 1, stackptr);
|
||||
#endif
|
||||
|
||||
float value;
|
||||
|
@ -1620,7 +1695,7 @@ static void par_shapes__weld_points(par_shapes_mesh* mesh, int gridsize,
|
|||
PAR_SHAPES_T binvalue = *(bins + binindex);
|
||||
if (binvalue > 0) {
|
||||
if (nbins == 8) {
|
||||
//printf("Epsilon value is too large.\n");
|
||||
printf("Epsilon value is too large.\n");
|
||||
break;
|
||||
}
|
||||
nearby[nbins++] = binindex;
|
||||
|
@ -1632,8 +1707,9 @@ static void par_shapes__weld_points(par_shapes_mesh* mesh, int gridsize,
|
|||
// Check for colocated points in each nearby bin.
|
||||
for (int b = 0; b < nbins; b++) {
|
||||
int binindex = nearby[b];
|
||||
PAR_SHAPES_T binvalue = *(bins + binindex);
|
||||
PAR_SHAPES_T binvalue = bins[binindex];
|
||||
PAR_SHAPES_T nindex = binvalue - 1;
|
||||
assert(nindex < mesh->npoints);
|
||||
while (true) {
|
||||
|
||||
// If this isn't "self" and it's colocated, then weld it!
|
||||
|
@ -1699,6 +1775,9 @@ static void par_shapes__weld_points(par_shapes_mesh* mesh, int gridsize,
|
|||
PAR_SHAPES_T b = weldmap[tsrc[1]];
|
||||
PAR_SHAPES_T c = weldmap[tsrc[2]];
|
||||
if (a != b && a != c && b != c) {
|
||||
assert(a < mesh->npoints);
|
||||
assert(b < mesh->npoints);
|
||||
assert(c < mesh->npoints);
|
||||
*tdst++ = a;
|
||||
*tdst++ = b;
|
||||
*tdst++ = c;
|
||||
|
@ -2049,3 +2128,25 @@ void par_shapes_remove_degenerate(par_shapes_mesh* mesh, float mintriarea)
|
|||
|
||||
#endif // PAR_SHAPES_IMPLEMENTATION
|
||||
#endif // PAR_SHAPES_H
|
||||
|
||||
// par_shapes is distributed under the MIT license:
|
||||
//
|
||||
// Copyright (c) 2019 Philip Rideout
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
|
55
src/models.c
55
src/models.c
|
@ -2084,6 +2084,61 @@ Mesh GenMeshCylinder(float radius, float height, int slices)
|
|||
return mesh;
|
||||
}
|
||||
|
||||
// Generate cone/pyramid mesh
|
||||
Mesh GenMeshCone(float radius, float height, int slices)
|
||||
{
|
||||
Mesh mesh = { 0 };
|
||||
|
||||
if (slices >= 3)
|
||||
{
|
||||
// Instance a cone that sits on the Z=0 plane using the given tessellation
|
||||
// levels across the UV domain. Think of "slices" like a number of pizza
|
||||
// slices, and "stacks" like a number of stacked rings.
|
||||
// Height and radius are both 1.0, but they can easily be changed with par_shapes_scale
|
||||
par_shapes_mesh *cone = par_shapes_create_cone(slices, 8);
|
||||
par_shapes_scale(cone, radius, radius, height);
|
||||
par_shapes_rotate(cone, -PI/2.0f, (float[]){ 1, 0, 0 });
|
||||
par_shapes_rotate(cone, PI/2.0f, (float[]){ 0, 1, 0 });
|
||||
|
||||
// Generate an orientable disk shape (bottom cap)
|
||||
par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 });
|
||||
capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints);
|
||||
for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f;
|
||||
par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 });
|
||||
|
||||
par_shapes_merge_and_free(cone, capBottom);
|
||||
|
||||
mesh.vertices = (float *)RL_MALLOC(cone->ntriangles*3*3*sizeof(float));
|
||||
mesh.texcoords = (float *)RL_MALLOC(cone->ntriangles*3*2*sizeof(float));
|
||||
mesh.normals = (float *)RL_MALLOC(cone->ntriangles*3*3*sizeof(float));
|
||||
|
||||
mesh.vertexCount = cone->ntriangles*3;
|
||||
mesh.triangleCount = cone->ntriangles;
|
||||
|
||||
for (int k = 0; k < mesh.vertexCount; k++)
|
||||
{
|
||||
mesh.vertices[k*3] = cone->points[cone->triangles[k]*3];
|
||||
mesh.vertices[k*3 + 1] = cone->points[cone->triangles[k]*3 + 1];
|
||||
mesh.vertices[k*3 + 2] = cone->points[cone->triangles[k]*3 + 2];
|
||||
|
||||
mesh.normals[k*3] = cone->normals[cone->triangles[k]*3];
|
||||
mesh.normals[k*3 + 1] = cone->normals[cone->triangles[k]*3 + 1];
|
||||
mesh.normals[k*3 + 2] = cone->normals[cone->triangles[k]*3 + 2];
|
||||
|
||||
mesh.texcoords[k*2] = cone->tcoords[cone->triangles[k]*2];
|
||||
mesh.texcoords[k*2 + 1] = cone->tcoords[cone->triangles[k]*2 + 1];
|
||||
}
|
||||
|
||||
par_shapes_free_mesh(cone);
|
||||
|
||||
// Upload vertex data to GPU (static mesh)
|
||||
UploadMesh(&mesh, false);
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "MESH: Failed to generate mesh: cone");
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
// Generate torus mesh
|
||||
Mesh GenMeshTorus(float radius, float size, int radSeg, int sides)
|
||||
{
|
||||
|
|
|
@ -1428,6 +1428,7 @@ RLAPI Mesh GenMeshCube(float width, float height, float length);
|
|||
RLAPI Mesh GenMeshSphere(float radius, int rings, int slices); // Generate sphere mesh (standard sphere)
|
||||
RLAPI Mesh GenMeshHemiSphere(float radius, int rings, int slices); // Generate half-sphere mesh (no bottom cap)
|
||||
RLAPI Mesh GenMeshCylinder(float radius, float height, int slices); // Generate cylinder mesh
|
||||
RLAPI Mesh GenMeshCone(float radius, float height, int slices); // Generate cone/pyramid mesh
|
||||
RLAPI Mesh GenMeshTorus(float radius, float size, int radSeg, int sides); // Generate torus mesh
|
||||
RLAPI Mesh GenMeshKnot(float radius, float size, int radSeg, int sides); // Generate trefoil knot mesh
|
||||
RLAPI Mesh GenMeshHeightmap(Image heightmap, Vector3 size); // Generate heightmap mesh from image data
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue