Merge branch 'raysan5:master' into master

This commit is contained in:
Luiz Pestana 2021-08-11 19:13:58 -03:00 committed by GitHub
commit 03c2caf8d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 609 additions and 239 deletions

7
.gitignore vendored
View File

@ -57,6 +57,13 @@ packages/
*.a *.a
*.bc *.bc
*.so *.so
*.so.*
# Ignore wasm data in examples/
examples/**/*.wasm
examples/**/*.data
examples/**/*.js
examples/**/*.html
# Ignore switch files # Ignore switch files
examples/*/*.d examples/*/*.d

View File

@ -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 | | 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 | | 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 | | 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)* | | 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 ### Utility Wrapers

View File

@ -3,6 +3,17 @@ changelog
Current Release: raylib 3.7.0 (26 April 2021) 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) Release: raylib 3.7 (26 April 2021)
------------------------------------------------------------------------- -------------------------------------------------------------------------

View File

@ -265,7 +265,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
# --memory-init-file 0 # to avoid an external memory initialization code file (.mem) # --memory-init-file 0 # to avoid an external memory initialization code file (.mem)
# --preload-file resources # specify a resources folder for data compilation # --preload-file resources # specify a resources folder for data compilation
# --source-map-base # allow debugging in browser with source map # --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, # 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 # we can compile same code for ALL platforms with no change required, but, working on bigger

View File

@ -2,18 +2,17 @@
* *
* raylib [rlgl] example - Using rlgl module as standalone module * 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. * OpenGL 1.1 does not support shaders but it can also be used.
* *
* DEPENDENCIES: * 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 * glfw3 - Windows and context initialization library
* * rlgl.h - OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2
* rlgl library is provided as a single-file header-only library, this library * glad.h - OpenGL extensions initialization library (required by rlgl)
* allows coding in a pseudo-OpenGL 1.1 style while translating calls to multiple * raymath.h - 3D math library
* OpenGL versions backends (1.1, 2.1, 3.3, ES 2.0).
* *
* WINDOWS COMPILATION: * WINDOWS COMPILATION:
* gcc -o rlgl_standalone.exe rlgl_standalone.c -s -Iexternal\include -I..\..\src \ * gcc -o rlgl_standalone.exe rlgl_standalone.c -s -Iexternal\include -I..\..\src \
@ -21,15 +20,16 @@
* *
* APPLE COMPILATION: * APPLE COMPILATION:
* gcc -o rlgl_standalone rlgl_standalone.c -I../../src -Iexternal/include -Lexternal/lib \ * gcc -o rlgl_standalone rlgl_standalone.c -I../../src -Iexternal/include -Lexternal/lib \
* -lglfw3 -std=c99 -framework CoreVideo -framework OpenGL -framework OpenAL \ * -lglfw3 -framework CoreVideo -framework OpenGL -framework IOKit -framework Cocoa
* -framework IOKit -framework Cocoa -Wno-deprecated-declarations * -Wno-deprecated-declarations -std=c99 -DGRAPHICS_API_OPENGL_33
*
* *
* LICENSE: zlib/libpng * LICENSE: zlib/libpng
* *
* This example is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * 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: * 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 * 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. * 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 DrawCubeWires(Vector3 position, float width, float height, float length, Color color);
static void DrawRectangleV(Vector2 position, Vector2 size, 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 MatrixIdentity(void);
//static Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far); //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); //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 ); glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE );
#endif #endif
GLFWwindow *window = glfwCreateWindow(screenWidth, screenHeight, "rlgl standalone", NULL, NULL); GLFWwindow *window = glfwCreateWindow(screenWidth, screenHeight, "rlgl standalone", NULL, NULL);
if (!window) if (!window)
@ -219,8 +218,8 @@ int main(void)
// Draw '2D' elements in the scene (GUI) // Draw '2D' elements in the scene (GUI)
//----------------------------------------------- //-----------------------------------------------
#define RLGL_CREATE_MATRIX_MANUALLY #define RLGL_SET_MATRIX_MANUALLY
#if defined(RLGL_CREATE_MATRIX_MANUALLY) #if defined(RLGL_SET_MATRIX_MANUALLY)
matProj = MatrixOrtho(0.0, screenWidth, screenHeight, 0.0, 0.0, 1.0); matProj = MatrixOrtho(0.0, screenWidth, screenHeight, 0.0, 0.0, 1.0);
matView = MatrixIdentity(); matView = MatrixIdentity();
@ -237,7 +236,7 @@ int main(void)
#endif #endif
DrawRectangleV((Vector2){ 10.0f, 10.0f }, (Vector2){ 780.0f, 20.0f }, DARKGRAY); 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(); rlDrawRenderBatchActive();
//----------------------------------------------- //-----------------------------------------------

View File

@ -13,6 +13,10 @@
#include "raylib.h" #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) int main(void)
{ {
// Initialization // Initialization
@ -119,4 +123,144 @@ tempor incididunt ut labore et dolore magna aliqua. Nec ullamcorper sit amet ris
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
return 0; 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;
}
} }

View File

@ -133,6 +133,9 @@ struct {
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
static void RandomizeEmoji(void); // Fills the emoji array with random emojis 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 // Global variables
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
@ -145,6 +148,9 @@ struct {
static int hovered = -1, selected = -1; static int hovered = -1, selected = -1;
//--------------------------------------------------------------------------------------
// Main entry point
//--------------------------------------------------------------------------------------
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
// Initialization // Initialization
@ -317,3 +323,143 @@ static void RandomizeEmoji(void)
emoji[i].message = GetRandomValue(0, SIZEOF(messages) - 1); 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;
}
}

View File

@ -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 // Distributed under the MIT License, see bottom of file.
// Copyright (c) 2015 Philip Rideout
#ifndef PAR_SHAPES_H #ifndef PAR_SHAPES_H
#define PAR_SHAPES_H #define PAR_SHAPES_H
@ -32,8 +31,7 @@ extern "C" {
#endif #endif
#include <stdint.h> #include <stdint.h>
// Ray (@raysan5): Commented to avoid conflict with raylib bool
// Ray: commented to avoid conflict with raylib bool
/* /*
#if !defined(_MSC_VER) #if !defined(_MSC_VER)
# include <stdbool.h> # include <stdbool.h>
@ -41,9 +39,9 @@ extern "C" {
# 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 bool int
//# define true 1 # define true 1
//# define false 0 # define false 0
# endif # endif
#endif #endif
*/ */
@ -71,6 +69,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 +178,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 +222,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 +319,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 +347,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 +372,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 +383,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 +619,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 +669,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 +801,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; float* n = mesh->normals;
if (p) { if (n) {
for (int i = 0; i < mesh->npoints; i++, p += 3) { for (int i = 0; i < mesh->npoints; i++, n += 3) {
float x = col0[0] * p[0] + col1[0] * p[1] + col2[0] * p[2]; float x = col0[0] * n[0] + col1[0] * n[1] + col2[0] * n[2];
float y = col0[1] * p[0] + col1[1] * p[1] + col2[1] * p[2]; float y = col0[1] * n[0] + col1[1] * n[1] + col2[1] * n[2];
float z = col0[2] * p[0] + col1[2] * p[1] + col2[2] * p[2]; float z = col0[2] * n[0] + col1[2] * n[1] + col2[2] * n[2];
p[0] = x; n[0] = x;
p[1] = y; n[1] = y;
p[2] = z; n[2] = z;
} }
} }
} }
@ -765,6 +822,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 +1176,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, void par_shapes__connect(par_shapes_mesh* scene, par_shapes_mesh* cylinder,
par_shapes_mesh* cylinder, int slices) int slices)
{ {
int stacks = 1; int stacks = 1;
int npoints = (slices + 1) * (stacks + 1); int npoints = (slices + 1) * (stacks + 1);
@ -1118,7 +1196,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 +1233,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 +1287,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 +1295,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 +1335,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 +1698,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 +1710,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 +1778,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 +2131,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.

View File

@ -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)
{ {
@ -3123,11 +3178,10 @@ RayCollision GetRayCollisionBox(Ray ray, BoundingBox box)
collision.normal = Vector3Scale(collision.normal, 2.01f); collision.normal = Vector3Scale(collision.normal, 2.01f);
collision.normal = Vector3Divide(collision.normal, Vector3Subtract(box.max, box.min)); 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) // 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 // and the others are somewhere between -1.0 and 1.0 casting to int is exactly our wanted normal!
// casting to int is exactly our wanted normal! collision.normal.x = (float)((int)collision.normal.x);
collision.normal.x = (int)collision.normal.x; collision.normal.y = (float)((int)collision.normal.y);
collision.normal.y = (int)collision.normal.y; collision.normal.z = (float)((int)collision.normal.z);
collision.normal.z = (int)collision.normal.z;
collision.normal = Vector3Normalize(collision.normal); collision.normal = Vector3Normalize(collision.normal);
@ -4937,7 +4991,7 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
{ {
output->framePoses[frame] = RL_MALLOC(output->boneCount*sizeof(Transform)); 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)); 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(); else output->framePoses[frame][i].translation = Vector3Zero();
@ -5130,7 +5184,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); outModel->meshes[(*primitiveIndex)].vertices = ReadGLTFValuesAs(acc, cgltf_component_type_r_32f, false);
// Transform using the nodes matrix attributes // 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 = { Vector3 vertex = {
outModel->meshes[(*primitiveIndex)].vertices[(v*3 + 0)], outModel->meshes[(*primitiveIndex)].vertices[(v*3 + 0)],
@ -5156,7 +5210,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); outModel->meshes[(*primitiveIndex)].normals = ReadGLTFValuesAs(acc, cgltf_component_type_r_32f, false);
// Transform using the nodes matrix attributes // 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 = { Vector3 normal = {
outModel->meshes[(*primitiveIndex)].normals[(v*3 + 0)], outModel->meshes[(*primitiveIndex)].normals[(v*3 + 0)],

View File

@ -282,23 +282,23 @@ typedef struct NPatchInfo {
int layout; // Layout of the n-patch: 3x3, 1x3 or 3x1 int layout; // Layout of the n-patch: 3x3, 1x3 or 3x1
} NPatchInfo; } NPatchInfo;
// CharInfo, font character info // GlyphInfo, font characters glyphs info
typedef struct CharInfo { typedef struct GlyphInfo {
int value; // Character value (Unicode) int value; // Character value (Unicode)
int offsetX; // Character offset X when drawing int offsetX; // Character offset X when drawing
int offsetY; // Character offset Y when drawing int offsetY; // Character offset Y when drawing
int advanceX; // Character advance position X int advanceX; // Character advance position X
Image image; // Character image data Image image; // Character image data
} CharInfo; } GlyphInfo;
// Font, font texture and CharInfo array data // Font, font texture and GlyphInfo array data
typedef struct Font { typedef struct Font {
int baseSize; // Base size (default chars height) int baseSize; // Base size (default chars height)
int charsCount; // Number of characters int charsCount; // Number of characters
int charsPadding; // Padding around the chars int charsPadding; // Padding around the chars
Texture2D texture; // Characters texture atlas Texture2D texture; // Characters texture atlas
Rectangle *recs; // Characters rectangles in texture Rectangle *recs; // Characters rectangles in texture
CharInfo *chars; // Characters info data GlyphInfo *chars; // Characters glyphs info data
} Font; } Font;
// Camera, defines position/orientation in 3d space // 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 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 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 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 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 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 // Input-related functions: gamepads
RLAPI bool IsGamepadAvailable(int gamepad); // Check if a gamepad is available 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 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 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 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 // Image manipulation functions
RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations)
@ -1320,34 +1320,42 @@ 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 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 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 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 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 CharInfo *chars, Rectangle **recs, int charsCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info 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(CharInfo *chars, int charsCount); // Unload font chars info data (RAM) RLAPI void UnloadFontData(GlyphInfo *chars, int charsCount); // Unload font chars info data (RAM)
RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM)
// Text drawing functions // Text drawing functions
RLAPI void DrawFPS(int posX, int posY); // Draw current FPS 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 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); 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 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) 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 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 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! // 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 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 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 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 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 *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 (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 *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 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! RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor!
@ -1356,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 *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 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 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) // Basic 3d Shapes Drawing Functions (Module: models)
@ -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

View File

@ -138,11 +138,11 @@ typedef struct Matrix {
// NOTE: Helper types to be used instead of array return types for *ToFloat functions // NOTE: Helper types to be used instead of array return types for *ToFloat functions
typedef struct float3 { typedef struct float3 {
float v[3]; float v[3];
} float3; } float3;
typedef struct float16 { typedef struct float16 {
float v[16]; float v[16];
} float16; } float16;
#include <math.h> // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), fminf(), fmaxf(), fabs() #include <math.h> // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), fminf(), fmaxf(), fabs()

View File

@ -53,14 +53,15 @@
#include "config.h" // Defines module configuration flags #include "config.h" // Defines module configuration flags
#endif #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 <stdlib.h> // Required for: malloc(), free() #include <stdlib.h> // Required for: malloc(), free()
#include <stdio.h> // Required for: vsprintf() #include <stdio.h> // Required for: vsprintf()
#include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()] #include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()]
#include <stdarg.h> // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()] #include <stdarg.h> // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()]
#include <ctype.h> // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()] #include <ctype.h> // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
#include "utils.h" // Required for: LoadFileText()
#if defined(SUPPORT_FILEFORMAT_TTF) #if defined(SUPPORT_FILEFORMAT_TTF)
#define STB_RECT_PACK_IMPLEMENTATION #define STB_RECT_PACK_IMPLEMENTATION
#include "external/stb_rect_pack.h" // Required for: ttf font rectangles packaging #include "external/stb_rect_pack.h" // Required for: ttf font rectangles packaging
@ -125,7 +126,7 @@ extern void LoadFontDefault(void)
{ {
#define BIT_CHECK(a,b) ((a) & (1u << (b))) #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 // Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
defaultFont.charsCount = 224; // Number of chars included in our default font defaultFont.charsCount = 224; // Number of chars included in our default font
@ -224,7 +225,7 @@ extern void LoadFontDefault(void)
// Allocate space for our characters info data // Allocate space for our characters info data
// NOTE: This memory should be freed at end! --> CloseWindow() // 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)); defaultFont.recs = (Rectangle *)RL_MALLOC(defaultFont.charsCount*sizeof(Rectangle));
int currentLine = 0; int currentLine = 0;
@ -453,7 +454,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
// We got tempCharValues and tempCharsRecs populated with chars data // We got tempCharValues and tempCharsRecs populated with chars data
// Now we move temp data to sized charValues and charRecs arrays // 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)); font.recs = (Rectangle *)RL_MALLOC(font.charsCount*sizeof(Rectangle));
for (int i = 0; i < font.charsCount; i++) for (int i = 0; i < font.charsCount; i++)
@ -523,7 +524,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
// Load font data for further use // Load font data for further use
// NOTE: Requires TTF font memory data and can generate SDF data // 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, // NOTE: Using some SDF generation default values,
// trades off precision with ability to handle *smaller* sizes // trades off precision with ability to handle *smaller* sizes
@ -540,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 #define FONT_BITMAP_ALPHA_THRESHOLD 80 // Bitmap (B&W) font generation alpha threshold
#endif #endif
CharInfo *chars = NULL; GlyphInfo *chars = NULL;
#if defined(SUPPORT_FILEFORMAT_TTF) #if defined(SUPPORT_FILEFORMAT_TTF)
// Load font data (including pixel data) from TTF memory file // Load font data (including pixel data) from TTF memory file
@ -573,7 +574,7 @@ CharInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize
genFontChars = true; genFontChars = true;
} }
chars = (CharInfo *)RL_MALLOC(charsCount*sizeof(CharInfo)); chars = (GlyphInfo *)RL_MALLOC(charsCount*sizeof(GlyphInfo));
// NOTE: Using simple packaging, one char after another // NOTE: Using simple packaging, one char after another
for (int i = 0; i < charsCount; i++) for (int i = 0; i < charsCount; i++)
@ -649,7 +650,7 @@ CharInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize
// Generate image font atlas using chars info // Generate image font atlas using chars info
// NOTE: Packing method: 0-Default, 1-Skyline // NOTE: Packing method: 0-Default, 1-Skyline
#if defined(SUPPORT_FILEFORMAT_TTF) #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 }; Image atlas = { 0 };
@ -792,7 +793,7 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
#endif #endif
// Unload font chars info data (RAM) // 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); for (int i = 0; i < charsCount; i++) UnloadImage(chars[i].image);
@ -890,140 +891,18 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
} }
} }
// Draw text using font inside rectangle limits // Draw text using Font and pro parameters (rotation)
void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint) void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint)
{ {
DrawTextRecEx(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, WHITE, WHITE); rlPushMatrix();
}
// Draw text using font inside rectangle limits with support for text selection rlTranslatef(position.x, position.y, 0.0f);
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) rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
{ rlTranslatef(-origin.x, -origin.y, 0.0f);
int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop
DrawTextEx(font, text, (Vector2){ 0.0f, 0.0f }, fontSize, spacing, tint);
float textOffsetY = 0; // Offset between lines (on line break '\n')
float textOffsetX = 0.0f; // Offset X to next character to draw rlPopMatrix();
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) // Draw one character (codepoint)
@ -1123,6 +1002,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
} }
// Get index position for a unicode character on font // 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) int GetGlyphIndex(Font font, int codepoint)
{ {
#ifndef GLYPH_NOTFOUND_CHAR_FALLBACK #ifndef GLYPH_NOTFOUND_CHAR_FALLBACK
@ -1149,6 +1029,28 @@ int GetGlyphIndex(Font font, int codepoint)
#endif #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 // Text strings management functions
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -1446,7 +1348,7 @@ const char *TextToUpper(const char *text)
buffer[i] = (char)toupper(text[i]); buffer[i] = (char)toupper(text[i]);
//if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32; //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; //if ((text[i] >= 'à') && (text[i] <= 'ý')) buffer[i] = text[i] - 32;
} }
else { buffer[i] = '\0'; break; } else { buffer[i] = '\0'; break; }
@ -1499,10 +1401,10 @@ const char *TextToPascal(const char *text)
return buffer; return buffer;
} }
// Encode text codepoint into utf8 text // Encode text codepoint into UTF-8 text
// REQUIRES: memcpy() // REQUIRES: memcpy()
// WARNING: Allocated memory should be manually freed // 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 // We allocate enough memory fo fit all possible codepoints
// NOTE: 5 bytes for every codepoint should be enough // NOTE: 5 bytes for every codepoint should be enough
@ -1512,7 +1414,7 @@ char *TextToUtf8(int *codepoints, int length)
for (int i = 0, bytes = 0; i < length; i++) for (int i = 0, bytes = 0; i < length; i++)
{ {
utf8 = CodepointToUtf8(codepoints[i], &bytes); utf8 = CodepointToUTF8(codepoints[i], &bytes);
memcpy(text + size, utf8, bytes); memcpy(text + size, utf8, bytes);
size += bytes; size += bytes;
} }
@ -1526,7 +1428,8 @@ char *TextToUtf8(int *codepoints, int length)
} }
// Encode codepoint into utf8 text (char array length returned as parameter) // 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 }; static char utf8[6] = { 0 };
int length = 0; int length = 0;
@ -1563,7 +1466,7 @@ RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength)
return utf8; 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 *LoadCodepoints(const char *text, int *count)
{ {
int textLength = TextLength(text); int textLength = TextLength(text);
@ -1595,8 +1498,8 @@ void UnloadCodepoints(int *codepoints)
RL_FREE(codepoints); RL_FREE(codepoints);
} }
// Get total number of characters(codepoints) in a UTF8 encoded text, until '\0' is found // Get total number of characters(codepoints) in a UTF-8 encoded text, until '\0' is found
// NOTE: If an invalid UTF8 sequence is encountered a '?'(0x3f) codepoint is counted instead // NOTE: If an invalid UTF-8 sequence is encountered a '?'(0x3f) codepoint is counted instead
int GetCodepointsCount(const char *text) int GetCodepointsCount(const char *text)
{ {
unsigned int len = 0; unsigned int len = 0;
@ -1617,8 +1520,8 @@ int GetCodepointsCount(const char *text)
} }
#endif // SUPPORT_TEXT_MANIPULATION #endif // SUPPORT_TEXT_MANIPULATION
// Get next codepoint in a UTF8 encoded text, scanning until '\0' is found // Get next codepoint in a UTF-8 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 // 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 // Total number of bytes processed are returned as a parameter
// NOTE: the standard says U+FFFD should be returned in case of errors // 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 // but that character is not supported by the default font in raylib
@ -1626,7 +1529,7 @@ int GetCodepointsCount(const char *text)
int GetCodepoint(const char *text, int *bytesProcessed) 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 Char. number range | UTF-8 octet sequence
(hexadecimal) | (binary) (hexadecimal) | (binary)
@ -1845,7 +1748,7 @@ static Font LoadBMFont(const char *fileName)
font.baseSize = fontSize; font.baseSize = fontSize;
font.charsCount = charsCount; font.charsCount = charsCount;
font.charsPadding = 0; 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)); font.recs = (Rectangle *)RL_MALLOC(charsCount*sizeof(Rectangle));
int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX; int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX;