From 07e0b105156b08718500fe4e2c74e583361278a8 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 7 Aug 2021 11:28:35 +0200 Subject: [PATCH 01/15] Added rayex, elixir binding --- BINDINGS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BINDINGS.md b/BINDINGS.md index 87a076b00..b154dc7b2 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -96,6 +96,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to | raylib-never | 3.0 | [Never](https://github.com/never-lang/never) | https://github.com/never-lang/raylib-never | | hb-raylib | 3.5 | [Harbour](https://harbour.github.io) | https://github.com/MarcosLeonardoMendezGerencir/hb-raylib | | Relib | 3.5 | [ReCT](https://github.com/RedCubeDev-ByteSpace/ReCT) | https://github.com/RedCubeDev-ByteSpace/Relib | +| rayex | 3.7 | [elixir](https://elixir-lang.org/) | https://github.com/shiryel/rayex | | raylib.cbl | 2.0 | [COBOL](https://en.wikipedia.org/wiki/COBOL) | *[code examples](https://github.com/Martinfx/Cobol/tree/master/OpenCobol/Games/raylib)* | ### Utility Wrapers From 7ca9131fd46e6928910cd995f4dc4240f36e2560 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 7 Aug 2021 11:58:39 +0200 Subject: [PATCH 02/15] Update rlgl_standalone.c --- examples/others/rlgl_standalone.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/examples/others/rlgl_standalone.c b/examples/others/rlgl_standalone.c index c8c0b0deb..cc0eda2db 100644 --- a/examples/others/rlgl_standalone.c +++ b/examples/others/rlgl_standalone.c @@ -2,18 +2,17 @@ * * raylib [rlgl] example - Using rlgl module as standalone module * -* NOTE: This example requires OpenGL 3.3 or ES2 versions for shaders support, +* rlgl library is an abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, ES 2.0) +* that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...) +* +* NOTE: This example requires OpenGL 3.3 or OpenGL ES 2.0 for shaders support, * OpenGL 1.1 does not support shaders but it can also be used. * * DEPENDENCIES: -* rlgl.h - OpenGL 1.1 immediate-mode style coding translation layer -* glad.h - OpenGL extensions initialization library (required by rlgl) -* raymath.h - 3D math library (required by rlgl) * glfw3 - Windows and context initialization library -* -* rlgl library is provided as a single-file header-only library, this library -* allows coding in a pseudo-OpenGL 1.1 style while translating calls to multiple -* OpenGL versions backends (1.1, 2.1, 3.3, ES 2.0). +* rlgl.h - OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2 +* glad.h - OpenGL extensions initialization library (required by rlgl) +* raymath.h - 3D math library * * WINDOWS COMPILATION: * gcc -o rlgl_standalone.exe rlgl_standalone.c -s -Iexternal\include -I..\..\src \ @@ -21,15 +20,16 @@ * * APPLE COMPILATION: * gcc -o rlgl_standalone rlgl_standalone.c -I../../src -Iexternal/include -Lexternal/lib \ -* -lglfw3 -std=c99 -framework CoreVideo -framework OpenGL -framework OpenAL \ -* -framework IOKit -framework Cocoa -Wno-deprecated-declarations +* -lglfw3 -framework CoreVideo -framework OpenGL -framework IOKit -framework Cocoa +* -Wno-deprecated-declarations -std=c99 -DGRAPHICS_API_OPENGL_33 +* * * LICENSE: zlib/libpng * * This example is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software: * -* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2021 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -107,7 +107,7 @@ static void DrawCube(Vector3 position, float width, float height, float length, static void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); static void DrawRectangleV(Vector2 position, Vector2 size, Color color); -// NOTE: We used raymath to get this functionality but it can be implemented here +// NOTE: We use raymath to get this functionality but it could be implemented in this module //static Matrix MatrixIdentity(void); //static Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far); //static Matrix MatrixPerspective(double fovy, double aspect, double near, double far); @@ -144,7 +144,6 @@ int main(void) glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE ); #endif - GLFWwindow *window = glfwCreateWindow(screenWidth, screenHeight, "rlgl standalone", NULL, NULL); if (!window) @@ -219,8 +218,8 @@ int main(void) // Draw '2D' elements in the scene (GUI) //----------------------------------------------- -#define RLGL_CREATE_MATRIX_MANUALLY -#if defined(RLGL_CREATE_MATRIX_MANUALLY) +#define RLGL_SET_MATRIX_MANUALLY +#if defined(RLGL_SET_MATRIX_MANUALLY) matProj = MatrixOrtho(0.0, screenWidth, screenHeight, 0.0, 0.0, 1.0); matView = MatrixIdentity(); @@ -237,7 +236,7 @@ int main(void) #endif DrawRectangleV((Vector2){ 10.0f, 10.0f }, (Vector2){ 780.0f, 20.0f }, DARKGRAY); - // Draw internal render batch buffers (3D data) + // Draw internal render batch buffers (2D data) rlDrawRenderBatchActive(); //----------------------------------------------- From e6fe8169c27825580e9b0e73ae633e89dc83b786 Mon Sep 17 00:00:00 2001 From: Ryan Roden-Corrent Date: Sat, 7 Aug 2021 17:30:48 -0400 Subject: [PATCH 03/15] Fix Makefile to build WASM examples. (#1906) * Fix Makefile to build WASM examples. - Add --preload-file flag before specifying the resource dir - Add empty resource dir to `shapes/` (otherwise wasm-ld will fail) - Add wasm outputs to .gitigore * Delete .gitignore Co-authored-by: Ray --- .gitignore | 6 ++++++ examples/Makefile | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9153a03ea..00c9bdcec 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,12 @@ packages/ *.bc *.so +# Ignore wasm data in examples/ +examples/**/*.wasm +examples/**/*.data +examples/**/*.js +examples/**/*.html + # Ignore files build by xcode *.mode*v* *.pbxuser diff --git a/examples/Makefile b/examples/Makefile index bded27e53..5abf0c708 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -244,7 +244,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB) # --memory-init-file 0 # to avoid an external memory initialization code file (.mem) # --preload-file resources # specify a resources folder for data compilation # --source-map-base # allow debugging in browser with source map - CFLAGS += -s USE_GLFW=3 -s ASYNCIFY -s TOTAL_MEMORY=67108864 -s FORCE_FILESYSTEM=1 $(dir $<)resources@resources + CFLAGS += -s USE_GLFW=3 -s ASYNCIFY -s TOTAL_MEMORY=67108864 -s FORCE_FILESYSTEM=1 --preload-file $(dir $<)resources@resources # NOTE: Simple raylib examples are compiled to be interpreter with asyncify, that way, # we can compile same code for ALL platforms with no change required, but, working on bigger From 5e63cd3c97a8b45c5effa961b00b533223c4e44f Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 8 Aug 2021 11:29:24 +0200 Subject: [PATCH 04/15] ADDED: GenMeshCone() #1903 --- src/external/par_shapes.h | 163 ++++++++++++++++++++++++++++++-------- src/models.c | 55 +++++++++++++ src/raylib.h | 1 + 3 files changed, 188 insertions(+), 31 deletions(-) diff --git a/src/external/par_shapes.h b/src/external/par_shapes.h index 8b65e384a..f44987a30 100644 --- a/src/external/par_shapes.h +++ b/src/external/par_shapes.h @@ -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 - -// Ray: commented to avoid conflict with raylib bool -/* #if !defined(_MSC_VER) # include #else // MSVC # if _MSC_VER >= 1800 # include # 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 #include +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. diff --git a/src/models.c b/src/models.c index bce9c8d82..2b6f9a589 100644 --- a/src/models.c +++ b/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) { diff --git a/src/raylib.h b/src/raylib.h index 781c14202..92e592e90 100644 --- a/src/raylib.h +++ b/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 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 From ee72497eef324aaac0abede3bfe6a89b0e1d8fb7 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 8 Aug 2021 13:02:51 +0200 Subject: [PATCH 05/15] REVIEWED: Some warnings... --- src/models.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/models.c b/src/models.c index 2b6f9a589..68785347e 100644 --- a/src/models.c +++ b/src/models.c @@ -79,6 +79,7 @@ #define PAR_SHAPES_IMPLEMENTATION #include "external/par_shapes.h" // Shapes 3d parametric generation + #undef bool #endif #if defined(_WIN32) @@ -3178,11 +3179,10 @@ RayCollision GetRayCollisionBox(Ray ray, BoundingBox box) collision.normal = Vector3Scale(collision.normal, 2.01f); collision.normal = Vector3Divide(collision.normal, Vector3Subtract(box.max, box.min)); // The relevant elemets of the vector are now slightly larger than 1.0f (or smaller than -1.0f) - // and the others are somewhere between -1.0 and 1.0 - // casting to int is exactly our wanted normal! - collision.normal.x = (int)collision.normal.x; - collision.normal.y = (int)collision.normal.y; - collision.normal.z = (int)collision.normal.z; + // and the others are somewhere between -1.0 and 1.0 casting to int is exactly our wanted normal! + collision.normal.x = (float)((int)collision.normal.x); + collision.normal.y = (float)((int)collision.normal.y); + collision.normal.z = (float)((int)collision.normal.z); collision.normal = Vector3Normalize(collision.normal); @@ -4992,7 +4992,7 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo { output->framePoses[frame] = RL_MALLOC(output->boneCount*sizeof(Transform)); - for (unsigned int i = 0; i < output->boneCount; i++) + for (int i = 0; i < output->boneCount; i++) { if (data->nodes[i].has_translation) memcpy(&output->framePoses[frame][i].translation, data->nodes[i].translation, 3*sizeof(float)); else output->framePoses[frame][i].translation = Vector3Zero(); @@ -5185,7 +5185,7 @@ void LoadGLTFMesh(cgltf_data* data, cgltf_mesh* mesh, Model* outModel, Matrix cu outModel->meshes[(*primitiveIndex)].vertices = ReadGLTFValuesAs(acc, cgltf_component_type_r_32f, false); // Transform using the nodes matrix attributes - for (unsigned int v = 0; v < outModel->meshes[(*primitiveIndex)].vertexCount; v++) + for (int v = 0; v < outModel->meshes[(*primitiveIndex)].vertexCount; v++) { Vector3 vertex = { outModel->meshes[(*primitiveIndex)].vertices[(v*3 + 0)], @@ -5211,7 +5211,7 @@ void LoadGLTFMesh(cgltf_data* data, cgltf_mesh* mesh, Model* outModel, Matrix cu outModel->meshes[(*primitiveIndex)].normals = ReadGLTFValuesAs(acc, cgltf_component_type_r_32f, false); // Transform using the nodes matrix attributes - for (unsigned int v = 0; v < outModel->meshes[(*primitiveIndex)].vertexCount; v++) + for (int v = 0; v < outModel->meshes[(*primitiveIndex)].vertexCount; v++) { Vector3 normal = { outModel->meshes[(*primitiveIndex)].normals[(v*3 + 0)], From a135d9c25d668640c43bbaffa54903b2c55f80f4 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 8 Aug 2021 13:23:04 +0200 Subject: [PATCH 06/15] REVIEWED: Avoid conflict with bool --- src/external/par_shapes.h | 3 +++ src/models.c | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/external/par_shapes.h b/src/external/par_shapes.h index f44987a30..994a605a9 100644 --- a/src/external/par_shapes.h +++ b/src/external/par_shapes.h @@ -31,6 +31,8 @@ extern "C" { #endif #include +// Ray (@raysan5): Commented to avoid conflict with raylib bool +/* #if !defined(_MSC_VER) # include #else // MSVC @@ -42,6 +44,7 @@ extern "C" { # define false 0 # endif #endif +*/ #ifndef PAR_SHAPES_T #define PAR_SHAPES_T uint16_t diff --git a/src/models.c b/src/models.c index 68785347e..329d8d4a8 100644 --- a/src/models.c +++ b/src/models.c @@ -79,7 +79,6 @@ #define PAR_SHAPES_IMPLEMENTATION #include "external/par_shapes.h" // Shapes 3d parametric generation - #undef bool #endif #if defined(_WIN32) From 311fe8f35b8dbe79af162b10ea980824b92115b4 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 8 Aug 2021 21:09:11 +0200 Subject: [PATCH 07/15] Replaced TABS by spaces --- src/raymath.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/raymath.h b/src/raymath.h index 2eb7bbd0d..0909eb7e5 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -138,11 +138,11 @@ typedef struct Matrix { // NOTE: Helper types to be used instead of array return types for *ToFloat functions typedef struct float3 { - float v[3]; + float v[3]; } float3; typedef struct float16 { - float v[16]; + float v[16]; } float16; #include // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), fminf(), fmaxf(), fabs() From e3f0a11053beae4c21249e814b2714a717f9bdb2 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 10 Aug 2021 17:48:31 +0200 Subject: [PATCH 08/15] Update CHANGELOG --- CHANGELOG | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index c37aa3162..54bf0db61 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,17 @@ changelog Current Release: raylib 3.7.0 (26 April 2021) +------------------------------------------------------------------------- +Release: raylib 4.0 (November? 2021) +------------------------------------------------------------------------- +KEY CHANGES: + - + - + - + +Detailed changes: + + ------------------------------------------------------------------------- Release: raylib 3.7 (26 April 2021) ------------------------------------------------------------------------- From ef9fdd0fa5dcfbf4c3c538b56d285230e8d6af1e Mon Sep 17 00:00:00 2001 From: Ryan Roden-Corrent Date: Tue, 10 Aug 2021 12:38:32 -0400 Subject: [PATCH 09/15] Document Get{Key,Char}Pressed return value. (#1909) I think it is useful to know what the empty behavior is in cases where you are enumerating key presses (e.g. implementing "press any key to continue"). --- src/raylib.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 92e592e90..f02f46f66 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1077,8 +1077,8 @@ RLAPI bool IsKeyDown(int key); // Check if a key RLAPI bool IsKeyReleased(int key); // Check if a key has been released once RLAPI bool IsKeyUp(int key); // Check if a key is NOT being pressed RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) -RLAPI int GetKeyPressed(void); // Get key pressed (keycode), call it multiple times for keys queued -RLAPI int GetCharPressed(void); // Get char pressed (unicode), call it multiple times for chars queued +RLAPI int GetKeyPressed(void); // Get key pressed (keycode), call it multiple times for keys queued. Returns 0 when the queue is empty. +RLAPI int GetCharPressed(void); // Get char pressed (unicode), call it multiple times for chars queued. Returns 0 when the queue is empty. // Input-related functions: gamepads RLAPI bool IsGamepadAvailable(int gamepad); // Check if a gamepad is available From 0ba49cce45405a688f7e7893e203f7d3f0bc780c Mon Sep 17 00:00:00 2001 From: Tommi Sinivuo <600815+TommiSinivuo@users.noreply.github.com> Date: Wed, 11 Aug 2021 12:56:05 +0300 Subject: [PATCH 10/15] Add *.so.* to .gitignore to ignore build artifacts (#1912) When building a shared Raylib library on Linux, the build process produces 3 files: libraylib.so (symlink), libraylib.so.381 (symlink) and libraylib.so.3.8.1 (the library). Only the first one of these (.so) is currently ignored by Git. Adding *.so.* to .gitinore makes Git ignore the rest of them as well. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 00c9bdcec..dcfa5bce2 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,7 @@ packages/ *.a *.bc *.so +*.so.* # Ignore wasm data in examples/ examples/**/*.wasm From 5a259fa10ffb1ad44528d2678d3781cddd0bb1c0 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 11 Aug 2021 18:31:32 +0200 Subject: [PATCH 11/15] WARNING: REMOVED: DrawTextRec() and DrawTextRecEx() - DrawTextRec() and DrawTextRecEx() have been moved to example, those functions could be very specific depending on user needs so it's better to give the user the full source in case of special requirements instead of allowing a function with +10 input parameters. --- examples/text/text_rectangle_bounds.c | 144 +++++++++++++++++++++++++ examples/text/text_unicode.c | 146 ++++++++++++++++++++++++++ src/raylib.h | 3 - src/text.c | 133 ----------------------- 4 files changed, 290 insertions(+), 136 deletions(-) diff --git a/examples/text/text_rectangle_bounds.c b/examples/text/text_rectangle_bounds.c index 9754cd456..c763fb2ec 100644 --- a/examples/text/text_rectangle_bounds.c +++ b/examples/text/text_rectangle_bounds.c @@ -13,6 +13,10 @@ #include "raylib.h" +static void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint); // Draw text using font inside rectangle limits +static void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint); // Draw text using font inside rectangle limits with support for text selection + +// Main entry point int main(void) { // Initialization @@ -119,4 +123,144 @@ tempor incididunt ut labore et dolore magna aliqua. Nec ullamcorper sit amet ris //-------------------------------------------------------------------------------------- return 0; +} + +//-------------------------------------------------------------------------------------- +// Module functions definition +//-------------------------------------------------------------------------------------- + +// Draw text using font inside rectangle limits +static void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint) +{ + DrawTextRecEx(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, WHITE, WHITE); +} + +// Draw text using font inside rectangle limits with support for text selection +static void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint) +{ + int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop + + float textOffsetY = 0; // Offset between lines (on line break '\n') + float textOffsetX = 0.0f; // Offset X to next character to draw + + float scaleFactor = fontSize/(float)font.baseSize; // Character rectangle scaling factor + + // Word/character wrapping mechanism variables + enum { MEASURE_STATE = 0, DRAW_STATE = 1 }; + int state = wordWrap? MEASURE_STATE : DRAW_STATE; + + int startLine = -1; // Index where to begin drawing (where a line begins) + int endLine = -1; // Index where to stop drawing (where a line ends) + int lastk = -1; // Holds last value of the character position + + for (int i = 0, k = 0; i < length; i++, k++) + { + // Get next codepoint from byte string and glyph index in font + int codepointByteCount = 0; + int codepoint = GetCodepoint(&text[i], &codepointByteCount); + int index = GetGlyphIndex(font, codepoint); + + // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) + // but we need to draw all of the bad bytes using the '?' symbol moving one byte + if (codepoint == 0x3f) codepointByteCount = 1; + i += (codepointByteCount - 1); + + float glyphWidth = 0; + if (codepoint != '\n') + { + glyphWidth = (font.chars[index].advanceX == 0) ? font.recs[index].width*scaleFactor : font.chars[index].advanceX*scaleFactor; + + if (i + 1 < length) glyphWidth = glyphWidth + spacing; + } + + // NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside of the rec container + // We store this info in startLine and endLine, then we change states, draw the text between those two variables + // and change states again and again recursively until the end of the text (or until we get outside of the container). + // When wordWrap is OFF we don't need the measure state so we go to the drawing state immediately + // and begin drawing on the next line before we can get outside the container. + if (state == MEASURE_STATE) + { + // TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more + // Ref: http://jkorpela.fi/chars/spaces.html + if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i; + + if ((textOffsetX + glyphWidth) > rec.width) + { + endLine = (endLine < 1)? i : endLine; + if (i == endLine) endLine -= codepointByteCount; + if ((startLine + codepointByteCount) == endLine) endLine = (i - codepointByteCount); + + state = !state; + } + else if ((i + 1) == length) + { + endLine = i; + state = !state; + } + else if (codepoint == '\n') state = !state; + + if (state == DRAW_STATE) + { + textOffsetX = 0; + i = startLine; + glyphWidth = 0; + + // Save character position when we switch states + int tmp = lastk; + lastk = k - 1; + k = tmp; + } + } + else + { + if (codepoint == '\n') + { + if (!wordWrap) + { + textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; + textOffsetX = 0; + } + } + else + { + if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width)) + { + textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; + textOffsetX = 0; + } + + // When text overflows rectangle height limit, just stop drawing + if ((textOffsetY + font.baseSize*scaleFactor) > rec.height) break; + + // Draw selection background + bool isGlyphSelected = false; + if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength))) + { + DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, glyphWidth, (float)font.baseSize*scaleFactor }, selectBackTint); + isGlyphSelected = true; + } + + // Draw current character glyph + if ((codepoint != ' ') && (codepoint != '\t')) + { + DrawTextCodepoint(font, codepoint, (Vector2){ rec.x + textOffsetX, rec.y + textOffsetY }, fontSize, isGlyphSelected? selectTint : tint); + } + } + + if (wordWrap && (i == endLine)) + { + textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; + textOffsetX = 0; + startLine = endLine; + endLine = -1; + glyphWidth = 0; + selectStart += lastk - k; + k = lastk; + + state = !state; + } + } + + textOffsetX += glyphWidth; + } } \ No newline at end of file diff --git a/examples/text/text_unicode.c b/examples/text/text_unicode.c index fa336de7f..2954a28e1 100644 --- a/examples/text/text_unicode.c +++ b/examples/text/text_unicode.c @@ -133,6 +133,9 @@ struct { //-------------------------------------------------------------------------------------- static void RandomizeEmoji(void); // Fills the emoji array with random emojis +static void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint); // Draw text using font inside rectangle limits +static void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint); // Draw text using font inside rectangle limits with support for text selection + //-------------------------------------------------------------------------------------- // Global variables //-------------------------------------------------------------------------------------- @@ -145,6 +148,9 @@ struct { static int hovered = -1, selected = -1; +//-------------------------------------------------------------------------------------- +// Main entry point +//-------------------------------------------------------------------------------------- int main(int argc, char **argv) { // Initialization @@ -317,3 +323,143 @@ static void RandomizeEmoji(void) emoji[i].message = GetRandomValue(0, SIZEOF(messages) - 1); } } + +//-------------------------------------------------------------------------------------- +// Module functions definition +//-------------------------------------------------------------------------------------- + +// Draw text using font inside rectangle limits +static void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint) +{ + DrawTextRecEx(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, WHITE, WHITE); +} + +// Draw text using font inside rectangle limits with support for text selection +static void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint) +{ + int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop + + float textOffsetY = 0; // Offset between lines (on line break '\n') + float textOffsetX = 0.0f; // Offset X to next character to draw + + float scaleFactor = fontSize/(float)font.baseSize; // Character rectangle scaling factor + + // Word/character wrapping mechanism variables + enum { MEASURE_STATE = 0, DRAW_STATE = 1 }; + int state = wordWrap? MEASURE_STATE : DRAW_STATE; + + int startLine = -1; // Index where to begin drawing (where a line begins) + int endLine = -1; // Index where to stop drawing (where a line ends) + int lastk = -1; // Holds last value of the character position + + for (int i = 0, k = 0; i < length; i++, k++) + { + // Get next codepoint from byte string and glyph index in font + int codepointByteCount = 0; + int codepoint = GetCodepoint(&text[i], &codepointByteCount); + int index = GetGlyphIndex(font, codepoint); + + // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) + // but we need to draw all of the bad bytes using the '?' symbol moving one byte + if (codepoint == 0x3f) codepointByteCount = 1; + i += (codepointByteCount - 1); + + float glyphWidth = 0; + if (codepoint != '\n') + { + glyphWidth = (font.chars[index].advanceX == 0) ? font.recs[index].width*scaleFactor : font.chars[index].advanceX*scaleFactor; + + if (i + 1 < length) glyphWidth = glyphWidth + spacing; + } + + // NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside of the rec container + // We store this info in startLine and endLine, then we change states, draw the text between those two variables + // and change states again and again recursively until the end of the text (or until we get outside of the container). + // When wordWrap is OFF we don't need the measure state so we go to the drawing state immediately + // and begin drawing on the next line before we can get outside the container. + if (state == MEASURE_STATE) + { + // TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more + // Ref: http://jkorpela.fi/chars/spaces.html + if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i; + + if ((textOffsetX + glyphWidth) > rec.width) + { + endLine = (endLine < 1)? i : endLine; + if (i == endLine) endLine -= codepointByteCount; + if ((startLine + codepointByteCount) == endLine) endLine = (i - codepointByteCount); + + state = !state; + } + else if ((i + 1) == length) + { + endLine = i; + state = !state; + } + else if (codepoint == '\n') state = !state; + + if (state == DRAW_STATE) + { + textOffsetX = 0; + i = startLine; + glyphWidth = 0; + + // Save character position when we switch states + int tmp = lastk; + lastk = k - 1; + k = tmp; + } + } + else + { + if (codepoint == '\n') + { + if (!wordWrap) + { + textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; + textOffsetX = 0; + } + } + else + { + if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width)) + { + textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; + textOffsetX = 0; + } + + // When text overflows rectangle height limit, just stop drawing + if ((textOffsetY + font.baseSize*scaleFactor) > rec.height) break; + + // Draw selection background + bool isGlyphSelected = false; + if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength))) + { + DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, glyphWidth, (float)font.baseSize*scaleFactor }, selectBackTint); + isGlyphSelected = true; + } + + // Draw current character glyph + if ((codepoint != ' ') && (codepoint != '\t')) + { + DrawTextCodepoint(font, codepoint, (Vector2){ rec.x + textOffsetX, rec.y + textOffsetY }, fontSize, isGlyphSelected? selectTint : tint); + } + } + + if (wordWrap && (i == endLine)) + { + textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; + textOffsetX = 0; + startLine = endLine; + endLine = -1; + glyphWidth = 0; + selectStart += lastk - k; + k = lastk; + + state = !state; + } + } + + textOffsetX += glyphWidth; + } +} \ No newline at end of file diff --git a/src/raylib.h b/src/raylib.h index f02f46f66..fc64858ea 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1329,9 +1329,6 @@ RLAPI void UnloadFont(Font font); RLAPI void DrawFPS(int posX, int posY); // Draw current FPS RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters -//RLAPI void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint); -RLAPI void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint); // Draw text using font inside rectangle limits -RLAPI void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint); // Draw text using font inside rectangle limits with support for text selection RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint) // Text misc. functions diff --git a/src/text.c b/src/text.c index 0371a0cec..f12518f46 100644 --- a/src/text.c +++ b/src/text.c @@ -890,140 +890,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f } } -// Draw text using font inside rectangle limits -void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint) { - DrawTextRecEx(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, WHITE, WHITE); -} - -// Draw text using font inside rectangle limits with support for text selection -void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint) -{ - int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop - - float textOffsetY = 0; // Offset between lines (on line break '\n') - float textOffsetX = 0.0f; // Offset X to next character to draw - - float scaleFactor = fontSize/(float)font.baseSize; // Character quad scaling factor - - // Word/character wrapping mechanism variables - enum { MEASURE_STATE = 0, DRAW_STATE = 1 }; - int state = wordWrap? MEASURE_STATE : DRAW_STATE; - - int startLine = -1; // Index where to begin drawing (where a line begins) - int endLine = -1; // Index where to stop drawing (where a line ends) - int lastk = -1; // Holds last value of the character position - - for (int i = 0, k = 0; i < length; i++, k++) - { - // Get next codepoint from byte string and glyph index in font - int codepointByteCount = 0; - int codepoint = GetCodepoint(&text[i], &codepointByteCount); - int index = GetGlyphIndex(font, codepoint); - - // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) - // but we need to draw all of the bad bytes using the '?' symbol moving one byte - if (codepoint == 0x3f) codepointByteCount = 1; - i += (codepointByteCount - 1); - - float glyphWidth = 0; - if (codepoint != '\n') - { - glyphWidth = (font.chars[index].advanceX == 0) ? font.recs[index].width*scaleFactor : font.chars[index].advanceX*scaleFactor; - - if (i + 1 < length) glyphWidth = glyphWidth + spacing; - } - - // NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside of the rec container - // We store this info in startLine and endLine, then we change states, draw the text between those two variables - // and change states again and again recursively until the end of the text (or until we get outside of the container). - // When wordWrap is OFF we don't need the measure state so we go to the drawing state immediately - // and begin drawing on the next line before we can get outside the container. - if (state == MEASURE_STATE) - { - // TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more - // Ref: http://jkorpela.fi/chars/spaces.html - if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i; - - if ((textOffsetX + glyphWidth) > rec.width) - { - endLine = (endLine < 1)? i : endLine; - if (i == endLine) endLine -= codepointByteCount; - if ((startLine + codepointByteCount) == endLine) endLine = (i - codepointByteCount); - - state = !state; - } - else if ((i + 1) == length) - { - endLine = i; - state = !state; - } - else if (codepoint == '\n') state = !state; - - if (state == DRAW_STATE) - { - textOffsetX = 0; - i = startLine; - glyphWidth = 0; - - // Save character position when we switch states - int tmp = lastk; - lastk = k - 1; - k = tmp; - } - } - else - { - if (codepoint == '\n') - { - if (!wordWrap) - { - textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; - textOffsetX = 0; - } - } - else - { - if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width)) - { - textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; - textOffsetX = 0; - } - - // When text overflows rectangle height limit, just stop drawing - if ((textOffsetY + font.baseSize*scaleFactor) > rec.height) break; - - // Draw selection background - bool isGlyphSelected = false; - if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength))) - { - DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, glyphWidth, (float)font.baseSize*scaleFactor }, selectBackTint); - isGlyphSelected = true; - } - - // Draw current character glyph - if ((codepoint != ' ') && (codepoint != '\t')) - { - DrawTextCodepoint(font, codepoint, (Vector2){ rec.x + textOffsetX, rec.y + textOffsetY }, fontSize, isGlyphSelected? selectTint : tint); - } - } - - if (wordWrap && (i == endLine)) - { - textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; - textOffsetX = 0; - startLine = endLine; - endLine = -1; - glyphWidth = 0; - selectStart += lastk - k; - k = lastk; - - state = !state; - } - } - - textOffsetX += glyphWidth; - } } // Draw one character (codepoint) From b55418effd288d9989b86d34831c8d60a5c6c7a7 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 11 Aug 2021 18:31:56 +0200 Subject: [PATCH 12/15] ADDED: DrawTextPro() with text rotation support --- src/raylib.h | 3 ++- src/text.c | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/raylib.h b/src/raylib.h index fc64858ea..438a079dc 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1328,7 +1328,8 @@ RLAPI void UnloadFont(Font font); // Text drawing functions RLAPI void DrawFPS(int posX, int posY); // Draw current FPS RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) -RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters +RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters +RLAPI void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint); // Draw text using Font and pro parameters (rotation) RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint) // Text misc. functions diff --git a/src/text.c b/src/text.c index f12518f46..d8c3a6b7f 100644 --- a/src/text.c +++ b/src/text.c @@ -890,7 +890,17 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f } } +// Draw text using Font and pro parameters (rotation) +void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint) { + rlPushMatrix(); + + rlTranslatef(origin.x, origin.y, 0.0f); + rlRotatef(rotation, 0.0f, 0.0f, 1.0f); + + DrawTextEx(font, text, position, fontSize, spacing, tint); + + rlPopMatrix(); } // Draw one character (codepoint) From 7e27c2ffa82337c6b4649295b4df1c7e1829c7fc Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 11 Aug 2021 18:53:06 +0200 Subject: [PATCH 13/15] TODO: DrawTextPro() rotation not working? --- src/text.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/text.c b/src/text.c index d8c3a6b7f..891c5497c 100644 --- a/src/text.c +++ b/src/text.c @@ -893,12 +893,15 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f // Draw text using Font and pro parameters (rotation) void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint) { + // TODO: Not working... why??? + rlPushMatrix(); - rlTranslatef(origin.x, origin.y, 0.0f); + //rlTranslatef(position.x, position.y, 0.0f); rlRotatef(rotation, 0.0f, 0.0f, 1.0f); + rlTranslatef(-origin.x, -origin.y, 0.0f); - DrawTextEx(font, text, position, fontSize, spacing, tint); + DrawTextEx(font, text, (Vector2){ position.x, position.y }, fontSize, spacing, tint); rlPopMatrix(); } From b6541b7a558304f8a6e27533195c898ea728b712 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 11 Aug 2021 19:02:15 +0200 Subject: [PATCH 14/15] REVIEWED: DrawTextPro() WARNING: DrawTextPro() requires including `rlgl.h`, before it was only dependant on `textures` module. --- src/text.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/text.c b/src/text.c index 891c5497c..1724153f9 100644 --- a/src/text.c +++ b/src/text.c @@ -53,6 +53,8 @@ #include "config.h" // Defines module configuration flags #endif +#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 -> Only DrawTextPro() + #include // Required for: malloc(), free() #include // Required for: vsprintf() #include // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()] @@ -893,15 +895,13 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f // Draw text using Font and pro parameters (rotation) void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint) { - // TODO: Not working... why??? - rlPushMatrix(); - //rlTranslatef(position.x, position.y, 0.0f); + rlTranslatef(position.x, position.y, 0.0f); rlRotatef(rotation, 0.0f, 0.0f, 1.0f); rlTranslatef(-origin.x, -origin.y, 0.0f); - DrawTextEx(font, text, (Vector2){ position.x, position.y }, fontSize, spacing, tint); + DrawTextEx(font, text, (Vector2){ 0.0f, 0.0f }, fontSize, spacing, tint); rlPopMatrix(); } From 621a8766a812e508037e580c4e5d8419d12977be Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 11 Aug 2021 21:16:39 +0200 Subject: [PATCH 15/15] WARNING: BREAKING: Renamed `CharInfo` to `GlyphInfo` and more... This commit introduces some breaking changes for library consistency, hopefully not too dramatic... Here the full list: - RENAMED: struct `CharInfo` to `GlyphInfo`, actually that's the correct naming for the data contained. It contains the character glyph metrics and the glyph image; in the past it also contained rectangle within the font atlas but that data has been moved to `Font` struct directly, so, `GlyphInfo` is a more correct name. - RENAMED: `CodepointToUtf8()` to `CodepointToUTF8()`, capitalization of UTF-8 is the correct form, it would also require de hyphen but it can be omitted in this case. - RENAMED: `TextToUtf8()` to `TextCodepointsToUTF8` for consistency and more detail on the functionality. - ADDED: `GetGlyphInfo()` to get glyph info for a specific codepoint - ADDED: `GetGlyphAtlasRec()` to get glyph rectangle within the generated font atlas - Some additional tweaks for consistency --- src/raylib.h | 52 ++++++++++++++++++++-------------------- src/text.c | 67 +++++++++++++++++++++++++++++++++++----------------- 2 files changed, 72 insertions(+), 47 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 438a079dc..7f8728137 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -282,23 +282,23 @@ typedef struct NPatchInfo { int layout; // Layout of the n-patch: 3x3, 1x3 or 3x1 } NPatchInfo; -// CharInfo, font character info -typedef struct CharInfo { +// GlyphInfo, font characters glyphs info +typedef struct GlyphInfo { int value; // Character value (Unicode) int offsetX; // Character offset X when drawing int offsetY; // Character offset Y when drawing int advanceX; // Character advance position X Image image; // Character image data -} CharInfo; +} GlyphInfo; -// Font, font texture and CharInfo array data +// Font, font texture and GlyphInfo array data typedef struct Font { int baseSize; // Base size (default chars height) int charsCount; // Number of characters int charsPadding; // Padding around the chars Texture2D texture; // Characters texture atlas Rectangle *recs; // Characters rectangles in texture - CharInfo *chars; // Characters info data + GlyphInfo *chars; // Characters glyphs info data } Font; // Camera, defines position/orientation in 3d space @@ -1077,8 +1077,8 @@ RLAPI bool IsKeyDown(int key); // Check if a key RLAPI bool IsKeyReleased(int key); // Check if a key has been released once RLAPI bool IsKeyUp(int key); // Check if a key is NOT being pressed RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) -RLAPI int GetKeyPressed(void); // Get key pressed (keycode), call it multiple times for keys queued. Returns 0 when the queue is empty. -RLAPI int GetCharPressed(void); // Get char pressed (unicode), call it multiple times for chars queued. Returns 0 when the queue is empty. +RLAPI int GetKeyPressed(void); // Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty +RLAPI int GetCharPressed(void); // Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty // Input-related functions: gamepads RLAPI bool IsGamepadAvailable(int gamepad); // Check if a gamepad is available @@ -1217,7 +1217,7 @@ RLAPI Image GenImageGradientRadial(int width, int height, float density, Color i RLAPI Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2); // Generate image: checked RLAPI Image GenImageWhiteNoise(int width, int height, float factor); // Generate image: white noise RLAPI Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale); // Generate image: perlin noise -RLAPI Image GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm. Bigger tileSize means bigger cells +RLAPI Image GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm, bigger tileSize means bigger cells // Image manipulation functions RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) @@ -1320,9 +1320,9 @@ RLAPI Font LoadFont(const char *fileName); RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount); // Load font from file with extended parameters RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style) RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' -RLAPI CharInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount, int type); // Load font data for further use -RLAPI Image GenImageFontAtlas(const CharInfo *chars, Rectangle **recs, int charsCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info -RLAPI void UnloadFontData(CharInfo *chars, int charsCount); // Unload font chars info data (RAM) +RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount, int type); // Load font data for further use +RLAPI Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **recs, int charsCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info +RLAPI void UnloadFontData(GlyphInfo *chars, int charsCount); // Unload font chars info data (RAM) RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) // Text drawing functions @@ -1332,20 +1332,30 @@ RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontS RLAPI void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint); // Draw text using Font and pro parameters (rotation) RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint) -// Text misc. functions +// Text font info functions RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font -RLAPI int GetGlyphIndex(Font font, int codepoint); // Get index position for a unicode character on font +RLAPI int GetGlyphIndex(Font font, int codepoint); // Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found +RLAPI GlyphInfo GetGlyphInfo(Font font, int codepoint); // Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found +RLAPI Rectangle GetGlyphAtlasRec(Font font, int codepoint); // Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found -// Text strings management functions (no utf8 strings, only byte chars) +// Text codepoints management functions (unicode characters) +RLAPI int *LoadCodepoints(const char *text, int *count); // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter +RLAPI void UnloadCodepoints(int *codepoints); // Unload codepoints data from memory +RLAPI int GetCodepointsCount(const char *text); // Get total number of codepoints in a UTF-8 encoded string +RLAPI int GetCodepoint(const char *text, int *bytesProcessed); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure +RLAPI const char *CodepointToUTF8(int codepoint, int *byteLength); // Encode one codepoint into UTF-8 byte array (array length returned as parameter) +RLAPI char *TextCodepointsToUTF8(int *codepoints, int length); // Encode text as codepoints array into UTF-8 text string (WARNING: memory must be freed!) + +// Text strings management functions (no UTF-8 strings, only byte chars) // NOTE: Some strings allocate memory internally for returned strings, just be careful! RLAPI int TextCopy(char *dst, const char *src); // Copy one string to another, returns bytes copied RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending -RLAPI const char *TextFormat(const char *text, ...); // Text formatting with variables (sprintf style) +RLAPI const char *TextFormat(const char *text, ...); // Text formatting with variables (sprintf() style) RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string -RLAPI char *TextReplace(char *text, const char *replace, const char *by); // Replace text string (memory must be freed!) -RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (memory must be freed!) +RLAPI char *TextReplace(char *text, const char *replace, const char *by); // Replace text string (WARNING: memory must be freed!) +RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (WARNING: memory must be freed!) RLAPI const char *TextJoin(const char **textList, int count, const char *delimiter); // Join text strings with delimiter RLAPI const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor! @@ -1354,14 +1364,6 @@ RLAPI const char *TextToUpper(const char *text); // Get upp RLAPI const char *TextToLower(const char *text); // Get lower case version of provided string RLAPI const char *TextToPascal(const char *text); // Get Pascal case notation version of provided string RLAPI int TextToInteger(const char *text); // Get integer value from text (negative values not supported) -RLAPI char *TextToUtf8(int *codepoints, int length); // Encode text codepoint into utf8 text (memory must be freed!) - -// UTF8 text strings management functions -RLAPI int *LoadCodepoints(const char *text, int *count); // Load all codepoints from a UTF8 text string, codepoints count returned by parameter -RLAPI void UnloadCodepoints(int *codepoints); // Unload codepoints data from memory -RLAPI int GetCodepointsCount(const char *text); // Get total number of characters (codepoints) in a UTF8 encoded string -RLAPI int GetCodepoint(const char *text, int *bytesProcessed); // Get next codepoint in a UTF8 encoded string, 0x3f('?') is returned on failure -RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength); // Encode codepoint into utf8 text (char array length returned as parameter) //------------------------------------------------------------------------------------ // Basic 3d Shapes Drawing Functions (Module: models) diff --git a/src/text.c b/src/text.c index 1724153f9..9d336f218 100644 --- a/src/text.c +++ b/src/text.c @@ -53,6 +53,7 @@ #include "config.h" // Defines module configuration flags #endif +#include "utils.h" // Required for: LoadFileText() #include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 -> Only DrawTextPro() #include // Required for: malloc(), free() @@ -61,8 +62,6 @@ #include // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()] #include // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()] -#include "utils.h" // Required for: LoadFileText() - #if defined(SUPPORT_FILEFORMAT_TTF) #define STB_RECT_PACK_IMPLEMENTATION #include "external/stb_rect_pack.h" // Required for: ttf font rectangles packaging @@ -127,7 +126,7 @@ extern void LoadFontDefault(void) { #define BIT_CHECK(a,b) ((a) & (1u << (b))) - // NOTE: Using UTF8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement + // NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement // Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl defaultFont.charsCount = 224; // Number of chars included in our default font @@ -226,7 +225,7 @@ extern void LoadFontDefault(void) // Allocate space for our characters info data // NOTE: This memory should be freed at end! --> CloseWindow() - defaultFont.chars = (CharInfo *)RL_MALLOC(defaultFont.charsCount*sizeof(CharInfo)); + defaultFont.chars = (GlyphInfo *)RL_MALLOC(defaultFont.charsCount*sizeof(GlyphInfo)); defaultFont.recs = (Rectangle *)RL_MALLOC(defaultFont.charsCount*sizeof(Rectangle)); int currentLine = 0; @@ -455,7 +454,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar) // We got tempCharValues and tempCharsRecs populated with chars data // Now we move temp data to sized charValues and charRecs arrays - font.chars = (CharInfo *)RL_MALLOC(font.charsCount*sizeof(CharInfo)); + font.chars = (GlyphInfo *)RL_MALLOC(font.charsCount*sizeof(GlyphInfo)); font.recs = (Rectangle *)RL_MALLOC(font.charsCount*sizeof(Rectangle)); for (int i = 0; i < font.charsCount; i++) @@ -525,7 +524,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int // Load font data for further use // NOTE: Requires TTF font memory data and can generate SDF data -CharInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount, int type) +GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount, int type) { // NOTE: Using some SDF generation default values, // trades off precision with ability to handle *smaller* sizes @@ -542,7 +541,7 @@ CharInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize #define FONT_BITMAP_ALPHA_THRESHOLD 80 // Bitmap (B&W) font generation alpha threshold #endif - CharInfo *chars = NULL; + GlyphInfo *chars = NULL; #if defined(SUPPORT_FILEFORMAT_TTF) // Load font data (including pixel data) from TTF memory file @@ -575,7 +574,7 @@ CharInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize genFontChars = true; } - chars = (CharInfo *)RL_MALLOC(charsCount*sizeof(CharInfo)); + chars = (GlyphInfo *)RL_MALLOC(charsCount*sizeof(GlyphInfo)); // NOTE: Using simple packaging, one char after another for (int i = 0; i < charsCount; i++) @@ -651,7 +650,7 @@ CharInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize // Generate image font atlas using chars info // NOTE: Packing method: 0-Default, 1-Skyline #if defined(SUPPORT_FILEFORMAT_TTF) -Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCount, int fontSize, int padding, int packMethod) +Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int charsCount, int fontSize, int padding, int packMethod) { Image atlas = { 0 }; @@ -794,7 +793,7 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo #endif // Unload font chars info data (RAM) -void UnloadFontData(CharInfo *chars, int charsCount) +void UnloadFontData(GlyphInfo *chars, int charsCount) { for (int i = 0; i < charsCount; i++) UnloadImage(chars[i].image); @@ -1003,6 +1002,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing } // Get index position for a unicode character on font +// NOTE: If codepoint is not found in the font it fallbacks to '?' int GetGlyphIndex(Font font, int codepoint) { #ifndef GLYPH_NOTFOUND_CHAR_FALLBACK @@ -1029,6 +1029,28 @@ int GetGlyphIndex(Font font, int codepoint) #endif } +// Get glyph font info data for a codepoint (unicode character) +// NOTE: If codepoint is not found in the font it fallbacks to '?' +GlyphInfo GetGlyphInfo(Font font, int codepoint) +{ + GlyphInfo info = { 0 }; + + info = font.chars[GetGlyphIndex(font, codepoint)]; + + return info; +} + +// Get glyph rectangle in font atlas for a codepoint (unicode character) +// NOTE: If codepoint is not found in the font it fallbacks to '?' +Rectangle GetGlyphAtlasRec(Font font, int codepoint) +{ + Rectangle rec = { 0 }; + + rec = font.recs[GetGlyphIndex(font, codepoint)]; + + return rec; +} + //---------------------------------------------------------------------------------- // Text strings management functions //---------------------------------------------------------------------------------- @@ -1326,7 +1348,7 @@ const char *TextToUpper(const char *text) buffer[i] = (char)toupper(text[i]); //if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32; - // TODO: Support Utf8 diacritics! + // TODO: Support UTF-8 diacritics! //if ((text[i] >= 'à') && (text[i] <= 'ý')) buffer[i] = text[i] - 32; } else { buffer[i] = '\0'; break; } @@ -1379,10 +1401,10 @@ const char *TextToPascal(const char *text) return buffer; } -// Encode text codepoint into utf8 text +// Encode text codepoint into UTF-8 text // REQUIRES: memcpy() // WARNING: Allocated memory should be manually freed -char *TextToUtf8(int *codepoints, int length) +char *TextCodepointsToUTF8(int *codepoints, int length) { // We allocate enough memory fo fit all possible codepoints // NOTE: 5 bytes for every codepoint should be enough @@ -1392,7 +1414,7 @@ char *TextToUtf8(int *codepoints, int length) for (int i = 0, bytes = 0; i < length; i++) { - utf8 = CodepointToUtf8(codepoints[i], &bytes); + utf8 = CodepointToUTF8(codepoints[i], &bytes); memcpy(text + size, utf8, bytes); size += bytes; } @@ -1406,7 +1428,8 @@ char *TextToUtf8(int *codepoints, int length) } // Encode codepoint into utf8 text (char array length returned as parameter) -RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength) +// NOTE: It uses a static array to store UTF-8 bytes +RLAPI const char *CodepointToUTF8(int codepoint, int *byteLength) { static char utf8[6] = { 0 }; int length = 0; @@ -1443,7 +1466,7 @@ RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength) return utf8; } -// Load all codepoints from a UTF8 text string, codepoints count returned by parameter +// Load all codepoints from a UTF-8 text string, codepoints count returned by parameter int *LoadCodepoints(const char *text, int *count) { int textLength = TextLength(text); @@ -1475,8 +1498,8 @@ void UnloadCodepoints(int *codepoints) RL_FREE(codepoints); } -// Get total number of characters(codepoints) in a UTF8 encoded text, until '\0' is found -// NOTE: If an invalid UTF8 sequence is encountered a '?'(0x3f) codepoint is counted instead +// Get total number of characters(codepoints) in a UTF-8 encoded text, until '\0' is found +// NOTE: If an invalid UTF-8 sequence is encountered a '?'(0x3f) codepoint is counted instead int GetCodepointsCount(const char *text) { unsigned int len = 0; @@ -1497,8 +1520,8 @@ int GetCodepointsCount(const char *text) } #endif // SUPPORT_TEXT_MANIPULATION -// Get next codepoint in a UTF8 encoded text, scanning until '\0' is found -// When a invalid UTF8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned +// Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found +// When a invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned // Total number of bytes processed are returned as a parameter // NOTE: the standard says U+FFFD should be returned in case of errors // but that character is not supported by the default font in raylib @@ -1506,7 +1529,7 @@ int GetCodepointsCount(const char *text) int GetCodepoint(const char *text, int *bytesProcessed) { /* - UTF8 specs from https://www.ietf.org/rfc/rfc3629.txt + UTF-8 specs from https://www.ietf.org/rfc/rfc3629.txt Char. number range | UTF-8 octet sequence (hexadecimal) | (binary) @@ -1725,7 +1748,7 @@ static Font LoadBMFont(const char *fileName) font.baseSize = fontSize; font.charsCount = charsCount; font.charsPadding = 0; - font.chars = (CharInfo *)RL_MALLOC(charsCount*sizeof(CharInfo)); + font.chars = (GlyphInfo *)RL_MALLOC(charsCount*sizeof(GlyphInfo)); font.recs = (Rectangle *)RL_MALLOC(charsCount*sizeof(Rectangle)); int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX;