Browse Source

ADDED: GenMeshCone() #1903

raysan5 4 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

@@ -21,8 +21,7 @@
 // coordinates (one per vertex).  That's it!  If you need something fancier,
 // coordinates (one per vertex).  That's it!  If you need something fancier,
 // look elsewhere.
 // look elsewhere.
 //
 //
-// The MIT License
-// Copyright (c) 2015 Philip Rideout
+// Distributed under the MIT License, see bottom of file.
 
 
 #ifndef PAR_SHAPES_H
 #ifndef PAR_SHAPES_H
 #define PAR_SHAPES_H
 #define PAR_SHAPES_H
@@ -32,21 +31,17 @@ extern "C" {
 #endif
 #endif
 
 
 #include <stdint.h>
 #include <stdint.h>
-
-// Ray: commented to avoid conflict with raylib bool
-/*
 #if !defined(_MSC_VER)
 #if !defined(_MSC_VER)
 # include <stdbool.h>
 # include <stdbool.h>
 #else // MSVC
 #else // MSVC
 # if _MSC_VER >= 1800
 # if _MSC_VER >= 1800
 #  include <stdbool.h>
 #  include <stdbool.h>
 # else // stdbool.h missing prior to MSVC++ 12.0 (VS2013)
 # 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
 #endif
 #endif
-*/
 
 
 #ifndef PAR_SHAPES_T
 #ifndef PAR_SHAPES_T
 #define PAR_SHAPES_T uint16_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.
 // both 1.0, but they can easily be changed with par_shapes_scale.
 par_shapes_mesh* par_shapes_create_cylinder(int slices, int stacks);
 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.
 // 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.
 // The outer radius can be controlled with par_shapes_scale.
 par_shapes_mesh* par_shapes_create_torus(int slices, int stacks, float radius);
 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.
 // Compute smooth normals by averaging adjacent facet normals.
 void par_shapes_compute_normals(par_shapes_mesh* m);
 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
 #ifndef PAR_PI
 #define PAR_PI (3.14159265359)
 #define PAR_PI (3.14159265359)
 #define PAR_MIN(a, b) (a > b ? b : a)
 #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 <math.h>
 #include <errno.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__sphere(float const* uv, float* xyz, void*);
 static void par_shapes__hemisphere(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__plane(float const* uv, float* xyz, void*);
 static void par_shapes__klein(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__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__torus(float const* uv, float* xyz, void*);
 static void par_shapes__trefoil(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;
     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);
     m->normals = PAR_MALLOC(float, m->npoints * 3);
     PAR_SHAPES_T* weldmap = PAR_MALLOC(PAR_SHAPES_T, m->npoints);
     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);
     par_shapes_compute_normals(welded);
     float* pdst = m->normals;
     float* pdst = m->normals;
     for (int i = 0; i < m->npoints; i++, pdst += 3) {
     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);
         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)
 par_shapes_mesh* par_shapes_create_parametric_sphere(int slices, int stacks)
 {
 {
     if (slices < 3 || stacks < 3) {
     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,
     par_shapes_mesh* m = par_shapes_create_parametric(par_shapes__sphere,
         slices, stacks, 0);
         slices, stacks, 0);
-    par_shapes_remove_degenerate(m, 0.0001);
+    par_shapes_remove_degenerate(m, par_shapes__epsilon_degenerate_sphere);
     return m;
     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,
     par_shapes_mesh* m = par_shapes_create_parametric(par_shapes__hemisphere,
         slices, stacks, 0);
         slices, stacks, 0);
-    par_shapes_remove_degenerate(m, 0.0001);
+    par_shapes_remove_degenerate(m, par_shapes__epsilon_degenerate_sphere);
     return m;
     return m;
 }
 }
 
 
@@ -579,6 +616,15 @@ static void par_shapes__cylinder(float const* uv, float* xyz, void* userdata)
     xyz[2] = uv[0];
     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)
 static void par_shapes__torus(float const* uv, float* xyz, void* userdata)
 {
 {
     float major = 1;
     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);
     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)
 void par_shapes_merge(par_shapes_mesh* dst, par_shapes_mesh const* src)
 {
 {
     PAR_SHAPES_T offset = dst->npoints;
     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[1] = y;
         p[2] = z;
         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++ *= y;
         *points++ *= z;
         *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)
 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;
     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 stacks = 1;
     int npoints = (slices + 1) * (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.
     // Create the new triangle list.
     int ntriangles = scene->ntriangles + 2 * slices * stacks;
     int ntriangles = scene->ntriangles + 2 * slices * stacks;
     PAR_SHAPES_T* triangles = PAR_MALLOC(PAR_SHAPES_T, ntriangles * 3);
     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);
     int v = scene->npoints - (slices + 1);
     PAR_SHAPES_T* face = triangles + scene->ntriangles * 3;
     PAR_SHAPES_T* face = triangles + scene->ntriangles * 3;
     for (int stack = 0; stack < stacks; stack++) {
     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) {
     while (cmd) {
         char *arg = strtok(0, " ");
         char *arg = strtok(0, " ");
         if (!arg) {
         if (!arg) {
-            //puts("lsystem error: unexpected end of program.");
+            puts("lsystem error: unexpected end of program.");
             break;
             break;
         }
         }
         if (!strcmp(cmd, "rule")) {
         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.
     // For testing purposes, dump out the parsed program.
     #ifdef TEST_PARSE
     #ifdef TEST_PARSE
-    /*
     for (int i = 0; i < nrules; i++) {
     for (int i = 0; i < nrules; i++) {
         par_shapes__rule rule = rules[i];
         par_shapes__rule rule = rules[i];
         printf("rule %s.%d\n", rule.name, rule.weight);
         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);
             printf("\t%s %s\n", cmd.cmd, cmd.arg);
         }
         }
     }
     }
-    */
     #endif
     #endif
 
 
     // Instantiate the aggregated shape and the template shapes.
     // 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++);
         par_shapes__command* cmd = rule->commands + (frame->pc++);
         #ifdef DUMP_TRACE
         #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
         #endif
 
 
         float value;
         float value;
@@ -1620,7 +1695,7 @@ static void par_shapes__weld_points(par_shapes_mesh* mesh, int gridsize,
                     PAR_SHAPES_T binvalue = *(bins + binindex);
                     PAR_SHAPES_T binvalue = *(bins + binindex);
                     if (binvalue > 0) {
                     if (binvalue > 0) {
                         if (nbins == 8) {
                         if (nbins == 8) {
-                            //printf("Epsilon value is too large.\n");
+                            printf("Epsilon value is too large.\n");
                             break;
                             break;
                         }
                         }
                         nearby[nbins++] = binindex;
                         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.
         // Check for colocated points in each nearby bin.
         for (int b = 0; b < nbins; b++) {
         for (int b = 0; b < nbins; b++) {
             int binindex = nearby[b];
             int binindex = nearby[b];
-            PAR_SHAPES_T binvalue = *(bins + binindex);
+            PAR_SHAPES_T binvalue = bins[binindex];
             PAR_SHAPES_T nindex = binvalue - 1;
             PAR_SHAPES_T nindex = binvalue - 1;
+            assert(nindex < mesh->npoints);
             while (true) {
             while (true) {
 
 
                 // If this isn't "self" and it's colocated, then weld it!
                 // 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 b = weldmap[tsrc[1]];
         PAR_SHAPES_T c = weldmap[tsrc[2]];
         PAR_SHAPES_T c = weldmap[tsrc[2]];
         if (a != b && a != c && b != c) {
         if (a != b && a != c && b != c) {
+            assert(a < mesh->npoints);
+            assert(b < mesh->npoints);
+            assert(c < mesh->npoints);
             *tdst++ = a;
             *tdst++ = a;
             *tdst++ = b;
             *tdst++ = b;
             *tdst++ = c;
             *tdst++ = c;
@@ -2049,3 +2128,25 @@ void par_shapes_remove_degenerate(par_shapes_mesh* mesh, float mintriarea)
 
 
 #endif // PAR_SHAPES_IMPLEMENTATION
 #endif // PAR_SHAPES_IMPLEMENTATION
 #endif // PAR_SHAPES_H
 #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

@@ -2084,6 +2084,61 @@ Mesh GenMeshCylinder(float radius, float height, int slices)
     return mesh;
     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
 // Generate torus mesh
 Mesh GenMeshTorus(float radius, float size, int radSeg, int sides)
 Mesh GenMeshTorus(float radius, float size, int radSeg, int sides)
 {
 {

+ 1 - 0
src/raylib.h

@@ -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 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 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 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 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 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
 RLAPI Mesh GenMeshHeightmap(Image heightmap, Vector3 size);                                 // Generate heightmap mesh from image data