Browse Source

ADDED: GenMeshCone() #1903

pull/1909/head
raysan5 3 years ago
parent
commit
5e63cd3c97
3 changed files with 188 additions and 31 deletions
  1. +132
    -31
      src/external/par_shapes.h
  2. +55
    -0
      src/models.c
  3. +1
    -0
      src/raylib.h

+ 132
- 31
src/external/par_shapes.h View File

@ -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)
o">//# define bool int
o">//# define true 1
o">//# define false 0
cp"># define bool int
cp"># define true 1
cp"># 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, mf">0.01, weldmap);
par_shapes_mesh* welded = par_shapes_weld(m, n">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, mf">0.0001);
par_shapes_remove_degenerate(m, n">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, mf">0.0001);
par_shapes_remove_degenerate(m, n">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;
kt">floatn>*pan> 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,
n">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) {
o">//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) {
o">//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 = o">*(bins + binindex);
PAR_SHAPES_T binvalue = n">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
- 0
src/models.c View File

@ -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)
{

+ 1
- 0
src/raylib.h View File

@ -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…
Cancel
Save