This commit is contained in:
lesleyrs 2023-07-20 00:51:53 +02:00
commit 73d62aab54
22 changed files with 950 additions and 303 deletions

View File

@ -21,6 +21,7 @@ Please, before submitting a new issue verify and check:
- [ ] I tested it on latest raylib version from master branch - [ ] I tested it on latest raylib version from master branch
- [ ] I checked there is no similar issue already reported - [ ] I checked there is no similar issue already reported
- [ ] I checked the documentation on the [wiki](https://github.com/raysan5/raylib/wiki)
- [ ] My code has no errors or misuse of raylib - [ ] My code has no errors or misuse of raylib
### Issue description ### Issue description

View File

@ -15,9 +15,9 @@ Some people ported raylib to other languages in form of bindings or wrappers to
| chez-raylib | **auto** | [Chez Scheme](https://cisco.github.io/ChezScheme/) | GPLv3 | https://github.com/Yunoinsky/chez-raylib | | chez-raylib | **auto** | [Chez Scheme](https://cisco.github.io/ChezScheme/) | GPLv3 | https://github.com/Yunoinsky/chez-raylib |
| raylib-cr | **4.6-dev (5e1a81)** | [Crystal](https://crystal-lang.org/) | Apache-2.0 | https://github.com/sol-vin/raylib-cr | | raylib-cr | **4.6-dev (5e1a81)** | [Crystal](https://crystal-lang.org/) | Apache-2.0 | https://github.com/sol-vin/raylib-cr |
| ray-cyber | 4.5 | [Cyber](https://cyberscript.dev) | MIT | https://github.com/fubark/ray-cyber | | ray-cyber | 4.5 | [Cyber](https://cyberscript.dev) | MIT | https://github.com/fubark/ray-cyber |
| raylib-c3 | **4.5** | [C3](https://c3-lang.org/) | MIT | https://github.com/Its-Kenta/Raylib-C3 | | raylib-c3 | **4.5** | [C3](https://c3-lang.org/) | Zlib | https://github.com/Its-Kenta/Raylib-C3 |
| dart-raylib | 4.0 | [Dart](https://dart.dev/) | MIT | https://gitlab.com/wolfenrain/dart-raylib | | dart-raylib | 4.0 | [Dart](https://dart.dev/) | MIT | https://gitlab.com/wolfenrain/dart-raylib |
| bindbc-raylib3 | 4.0 | [D](https://dlang.org/) | BSL-1.0 | https://github.com/o3o/bindbc-raylib3 | | bindbc-raylib3 | **4.5** | [D](https://dlang.org/) | BSL-1.0 | https://github.com/o3o/bindbc-raylib3 |
| dray | 4.2 | [D](https://dlang.org/) | Apache-2.0 | https://github.com/redthing1/dray | | dray | 4.2 | [D](https://dlang.org/) | Apache-2.0 | https://github.com/redthing1/dray |
| raylib-d | **4.5** | [D](https://dlang.org/) | Zlib | https://github.com/schveiguy/raylib-d | | raylib-d | **4.5** | [D](https://dlang.org/) | Zlib | https://github.com/schveiguy/raylib-d |
| dlang_raylib | 4.0 | [D](https://dlang.org) | MPL-2.0 |https://github.com/rc-05/dlang_raylib | | dlang_raylib | 4.0 | [D](https://dlang.org) | MPL-2.0 |https://github.com/rc-05/dlang_raylib |
@ -28,7 +28,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to
| raylib-go | 4.5 | [Go](https://golang.org/) | Zlib | https://github.com/gen2brain/raylib-go | | raylib-go | 4.5 | [Go](https://golang.org/) | Zlib | https://github.com/gen2brain/raylib-go |
| raylib-guile | **auto** | [Guile](https://www.gnu.org/software/guile/) | Zlib | https://github.com/petelliott/raylib-guile | | raylib-guile | **auto** | [Guile](https://www.gnu.org/software/guile/) | Zlib | https://github.com/petelliott/raylib-guile |
| gforth-raylib | 3.5 | [Gforth](https://gforth.org/) | MIT | https://github.com/ArnautDaniel/gforth-raylib | | gforth-raylib | 3.5 | [Gforth](https://gforth.org/) | MIT | https://github.com/ArnautDaniel/gforth-raylib |
| h-raylib | **4.5** | [Haskell](https://haskell.org/) | Apache-2.0 | https://github.com/Anut-py/h-raylib | | h-raylib | **4.6-dev** | [Haskell](https://haskell.org/) | Apache-2.0 | https://github.com/Anut-py/h-raylib |
| raylib-hx | 4.2 | [Haxe](https://haxe.org/) | Zlib | https://github.com/foreignsasquatch/raylib-hx | | raylib-hx | 4.2 | [Haxe](https://haxe.org/) | Zlib | https://github.com/foreignsasquatch/raylib-hx |
| hb-raylib | 3.5 | [Harbour](https://harbour.github.io) | MIT | https://github.com/MarcosLeonardoMendezGerencir/hb-raylib | | hb-raylib | 3.5 | [Harbour](https://harbour.github.io) | MIT | https://github.com/MarcosLeonardoMendezGerencir/hb-raylib |
| jaylib | 4.5 | [Janet](https://janet-lang.org/) | MIT | https://github.com/janet-lang/jaylib | | jaylib | 4.5 | [Janet](https://janet-lang.org/) | MIT | https://github.com/janet-lang/jaylib |
@ -40,7 +40,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to
| raylib-lua | **4.5** | [Lua](http://www.lua.org/) | ISC | https://github.com/TSnake41/raylib-lua | | raylib-lua | **4.5** | [Lua](http://www.lua.org/) | ISC | https://github.com/TSnake41/raylib-lua |
| raylua | 4.0 | [Lua](http://www.lua.org/) | MIT | https://github.com/Rabios/raylua | | raylua | 4.0 | [Lua](http://www.lua.org/) | MIT | https://github.com/Rabios/raylua |
| nelua-raylib | 4.0 | [nelua](https://nelua.io/) | MIT | https://github.com/AKDev21/nelua-raylib | | nelua-raylib | 4.0 | [nelua](https://nelua.io/) | MIT | https://github.com/AKDev21/nelua-raylib |
| Raylib-Nelua | **4.5-dev** | [nelua](https://nelua.io/) | MIT | https://github.com/Its-Kenta/Raylib-Nelua | | Raylib.nelua | **4.5** | [nelua](https://nelua.io/) | Zlib | https://github.com/Its-Kenta/Raylib-Nelua |
| NimraylibNow! | 4.2 | [Nim](https://nim-lang.org/) | MIT | https://github.com/greenfork/nimraylib_now | | NimraylibNow! | 4.2 | [Nim](https://nim-lang.org/) | MIT | https://github.com/greenfork/nimraylib_now |
| raylib-Forever | auto | [Nim](https://nim-lang.org/) | ? | https://github.com/Guevara-chan/Raylib-Forever | | raylib-Forever | auto | [Nim](https://nim-lang.org/) | ? | https://github.com/Guevara-chan/Raylib-Forever |
| naylib | auto | [Nim](https://nim-lang.org/) | MIT | https://github.com/planetis-m/naylib | | naylib | auto | [Nim](https://nim-lang.org/) | MIT | https://github.com/planetis-m/naylib |
@ -59,6 +59,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to
| raylib-php | 3.5 | [PHP](https://en.wikipedia.org/wiki/PHP) | Zlib | https://github.com/joseph-montanez/raylib-php | | raylib-php | 3.5 | [PHP](https://en.wikipedia.org/wiki/PHP) | Zlib | https://github.com/joseph-montanez/raylib-php |
| raylib-phpcpp | 3.5 | [PHP](https://en.wikipedia.org/wiki/PHP) | Zlib | https://github.com/oraoto/raylib-phpcpp | | raylib-phpcpp | 3.5 | [PHP](https://en.wikipedia.org/wiki/PHP) | Zlib | https://github.com/oraoto/raylib-phpcpp |
| raylibr | 4.0 | [R](https://www.r-project.org) | MIT | https://github.com/jeroenjanssens/raylibr | | raylibr | 4.0 | [R](https://www.r-project.org) | MIT | https://github.com/jeroenjanssens/raylibr |
| raylib-ffi | 4.5 | [Rust](https://www.rust-lang.org/) | GPLv3 | https://github.com/ewpratten/raylib-ffi |
| raylib-rs | 3.5 | [Rust](https://www.rust-lang.org/) | Zlib | https://github.com/deltaphc/raylib-rs | | raylib-rs | 3.5 | [Rust](https://www.rust-lang.org/) | Zlib | https://github.com/deltaphc/raylib-rs |
| 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 |
| racket-raylib | 4.0 | [Racket](https://racket-lang.org/) | MIT/Apache-2.0 | https://github.com/eutro/racket-raylib | | racket-raylib | 4.0 | [Racket](https://racket-lang.org/) | MIT/Apache-2.0 | https://github.com/eutro/racket-raylib |

View File

@ -73,6 +73,7 @@ cmake_dependent_option(SUPPORT_FILEFORMAT_PVR "Support loading PVR as textures"
cmake_dependent_option(SUPPORT_FILEFORMAT_FNT "Support loading fonts in FNT format" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_FILEFORMAT_FNT "Support loading fonts in FNT format" ON CUSTOMIZE_BUILD ON)
cmake_dependent_option(SUPPORT_FILEFORMAT_TTF "Support loading font in TTF/OTF format" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_FILEFORMAT_TTF "Support loading font in TTF/OTF format" ON CUSTOMIZE_BUILD ON)
cmake_dependent_option(SUPPORT_TEXT_MANIPULATION "Support text manipulation functions" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_TEXT_MANIPULATION "Support text manipulation functions" ON CUSTOMIZE_BUILD ON)
cmake_dependent_option(SUPPORT_FONT_ATLAS_WHITE_REC "Support white rec on font atlas bottom-right corner" ON CUSTOMIZE_BUILD ON)
# rmodels.c # rmodels.c
cmake_dependent_option(SUPPORT_MESH_GENERATION "Support procedural mesh generation functions, uses external par_shapes.h library. NOTE: Some generated meshes DO NOT include generated texture coordinates" ON CUSTOMIZE_BUILD ON) cmake_dependent_option(SUPPORT_MESH_GENERATION "Support procedural mesh generation functions, uses external par_shapes.h library. NOTE: Some generated meshes DO NOT include generated texture coordinates" ON CUSTOMIZE_BUILD ON)

View File

@ -106,7 +106,7 @@ elseif ("${PLATFORM}" MATCHES "DRM")
endif () endif ()
if (NOT ${OPENGL_VERSION}) if (NOT ${OPENGL_VERSION} MATCHES "OFF")
set(${SUGGESTED_GRAPHICS} "${GRAPHICS}") set(${SUGGESTED_GRAPHICS} "${GRAPHICS}")
if (${OPENGL_VERSION} MATCHES "4.3") if (${OPENGL_VERSION} MATCHES "4.3")
set(GRAPHICS "GRAPHICS_API_OPENGL_43") set(GRAPHICS "GRAPHICS_API_OPENGL_43")

View File

@ -405,6 +405,7 @@ CORE = \
core/core_input_gamepad \ core/core_input_gamepad \
core/core_input_multitouch \ core/core_input_multitouch \
core/core_input_gestures \ core/core_input_gestures \
core/core_input_gestures_web \
core/core_2d_camera \ core/core_2d_camera \
core/core_2d_camera_platformer \ core/core_2d_camera_platformer \
core/core_2d_camera_mouse_zoom \ core/core_2d_camera_mouse_zoom \
@ -536,12 +537,20 @@ AUDIO = \
audio/audio_stream_effects \ audio/audio_stream_effects \
audio/audio_mixed_processor audio/audio_mixed_processor
OTHERS = \
others/easings_testbed \
others/embedded_files_loading \
others/raylib_opengl_interop \
others/raymath_vector_angle \
others/rlgl_compute_shader \
others/rlgl_standalone
CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST)) CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST))
# Define processes to execute # Define processes to execute
#------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------
# Default target entry # Default target entry
all: $(CORE) $(SHAPES) $(TEXT) $(TEXTURES) $(MODELS) $(SHADERS) $(AUDIO) all: $(CORE) $(SHAPES) $(TEXT) $(TEXTURES) $(MODELS) $(SHADERS) $(AUDIO) $(OTHERS)
core: $(CORE) core: $(CORE)
shapes: $(SHAPES) shapes: $(SHAPES)
@ -550,6 +559,7 @@ text: $(TEXT)
models: $(MODELS) models: $(MODELS)
shaders: $(SHADERS) shaders: $(SHADERS)
audio: $(AUDIO) audio: $(AUDIO)
others: $(OTHERS)
# Generic compilation pattern # Generic compilation pattern
# NOTE: Examples must be ready for Android compilation! # NOTE: Examples must be ready for Android compilation!

View File

@ -386,6 +386,7 @@ CORE = \
core/core_input_gamepad \ core/core_input_gamepad \
core/core_input_multitouch \ core/core_input_multitouch \
core/core_input_gestures \ core/core_input_gestures \
core/core_input_gestures_web \
core/core_2d_camera \ core/core_2d_camera \
core/core_2d_camera_platformer \ core/core_2d_camera_platformer \
core/core_2d_camera_mouse_zoom \ core/core_2d_camera_mouse_zoom \
@ -558,6 +559,9 @@ core/core_input_multitouch: core/core_input_multitouch.c
core/core_input_gestures: core/core_input_gestures.c core/core_input_gestures: core/core_input_gestures.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
core/core_input_gestures_web: core/core_input_gestures_web.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
core/core_2d_camera: core/core_2d_camera.c core/core_2d_camera: core/core_2d_camera.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)

View File

@ -0,0 +1,338 @@
/*******************************************************************************************
*
* raylib [core] example - Input Gestures for Web
*
* Example originally created with raylib 4.6-dev, last time updated with raylib 4.6-dev
*
* Example contributed by ubkp (@ubkp) and reviewed by Ramon Santamaria (@raysan5)
*
* Example 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) 2023 ubkp (@ubkp)
*
********************************************************************************************/
#include "raylib.h"
#include "math.h" // Required for the protractor angle graphic drawing
#if defined(PLATFORM_WEB)
#include <emscripten/emscripten.h> // Required for the Web/HTML5
#endif
//--------------------------------------------------------------------------------------
// Global definitions and declarations
//--------------------------------------------------------------------------------------
// Common variables definitions
//--------------------------------------------------------------------------------------
int screenWidth = 800; // Update depending on web canvas
const int screenHeight = 450;
Vector2 messagePosition = { 160, 7 };
// Last gesture variables definitions
//--------------------------------------------------------------------------------------
int lastGesture = 0;
Vector2 lastGesturePosition = { 165, 130 };
// Gesture log variables definitions and functions declarations
//--------------------------------------------------------------------------------------
#define GESTURE_LOG_SIZE 20
char gestureLog[GESTURE_LOG_SIZE][12] = { "" }; // The gesture log uses an array (as an inverted circular queue) to store the performed gestures
int gestureLogIndex = GESTURE_LOG_SIZE; // The index for the inverted circular queue (moving from last to first direction, then looping around)
int previousGesture = 0;
char const *GetGestureName(int i)
{
switch (i) {
case 0: return "None"; break;
case 1: return "Tap"; break;
case 2: return "Double Tap"; break;
case 4: return "Hold"; break;
case 8: return "Drag"; break;
case 16: return "Swipe Right"; break;
case 32: return "Swipe Left"; break;
case 64: return "Swipe Up"; break;
case 128: return "Swipe Down"; break;
case 256: return "Pinch In"; break;
case 512: return "Pinch Out"; break;
default: return "Unknown"; break;
}
}
Color GetGestureColor(int i)
{
switch (i) {
case 0: return BLACK; break;
case 1: return BLUE; break;
case 2: return SKYBLUE; break;
case 4: return BLACK; break;
case 8: return LIME; break;
case 16: return RED; break;
case 32: return RED; break;
case 64: return RED; break;
case 128: return RED; break;
case 256: return VIOLET; break;
case 512: return ORANGE; break;
default: return BLACK; break;
}
}
int logMode = 1; // Log mode values: 0 shows repeated events; 1 hides repeated events; 2 shows repeated events but hide hold events; 3 hides repeated events and hide hold events
Color gestureColor = { 0, 0, 0, 255 };
Rectangle logButton1 = { 53, 7, 48, 26 };
Rectangle logButton2 = { 108, 7, 36, 26 };
Vector2 gestureLogPosition = { 10, 10 };
// Protractor variables definitions
//--------------------------------------------------------------------------------------
float angleLength = 90.0f;
float currentAngleDegrees = 0.0f;
Vector2 finalVector = { 0.0f, 0.0f };
char currentAngleStr[7] = "";
Vector2 protractorPosition = { 266.0f, 315.0f };
// Update
//--------------------------------------------------------------------------------------
void Update(void)
{
// Handle common
//--------------------------------------------------------------------------------------
int i, ii; // Iterators that will be reused by all for loops
const int currentGesture = GetGestureDetected();
const float currentDragDegrees = GetGestureDragAngle();
const float currentPitchDegrees = GetGesturePinchAngle();
const int touchCount = GetTouchPointCount();
// Handle last gesture
//--------------------------------------------------------------------------------------
if ((currentGesture != 0) && (currentGesture != 4) && (currentGesture != previousGesture)) lastGesture = currentGesture; // Filter the meaningful gestures (1, 2, 8 to 512) for the display
// Handle gesture log
//--------------------------------------------------------------------------------------
if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT))
{
if (CheckCollisionPointRec(GetMousePosition(), logButton1))
{
switch (logMode)
{
case 3: logMode=2; break;
case 2: logMode=3; break;
case 1: logMode=0; break;
default: logMode=1; break;
}
}
else if (CheckCollisionPointRec(GetMousePosition(), logButton2))
{
switch (logMode)
{
case 3: logMode=1; break;
case 2: logMode=0; break;
case 1: logMode=3; break;
default: logMode=2; break;
}
}
}
int fillLog = 0; // Gate variable to be used to allow or not the gesture log to be filled
if (currentGesture !=0)
{
if (logMode == 3) // 3 hides repeated events and hide hold events
{
if (((currentGesture != 4) && (currentGesture != previousGesture)) || (currentGesture < 3)) fillLog = 1;
}
else if (logMode == 2) // 2 shows repeated events but hide hold events
{
if (currentGesture != 4) fillLog = 1;
}
else if (logMode == 1) // 1 hides repeated events
{
if (currentGesture != previousGesture) fillLog = 1;
}
else // 0 shows repeated events
{
fillLog = 1;
}
}
if (fillLog) // If one of the conditions from logMode was met, fill the gesture log
{
previousGesture = currentGesture;
gestureColor = GetGestureColor(currentGesture);
if (gestureLogIndex <= 0) gestureLogIndex = GESTURE_LOG_SIZE;
gestureLogIndex--;
// Copy the gesture respective name to the gesture log array
TextCopy(gestureLog[gestureLogIndex], GetGestureName(currentGesture));
}
// Handle protractor
//--------------------------------------------------------------------------------------
if (currentGesture > 255) // aka Pinch In and Pinch Out
{
currentAngleDegrees = currentPitchDegrees;
}
else if (currentGesture > 15) // aka Swipe Right, Swipe Left, Swipe Up and Swipe Down
{
currentAngleDegrees = currentDragDegrees;
}
else if (currentGesture > 0) // aka Tap, Doubletap, Hold and Grab
{
currentAngleDegrees = 0.0f;
}
float currentAngleRadians = ((currentAngleDegrees +90.0f)*PI/180); // Convert the current angle to Radians
finalVector = (Vector2){ (angleLength*sinf(currentAngleRadians)) + protractorPosition.x, (angleLength*cosf(currentAngleRadians)) + protractorPosition.y }; // Calculate the final vector for display
// Handle touch and mouse pointer points
//--------------------------------------------------------------------------------------
#define MAX_TOUCH_COUNT 32
Vector2 touchPosition[MAX_TOUCH_COUNT] = { 0 };
Vector2 mousePosition = {0, 0};
if (currentGesture != GESTURE_NONE)
{
if (touchCount != 0)
{
for (i = 0; i < touchCount; i++) touchPosition[i] = GetTouchPosition(i); // Fill the touch positions
}
else mousePosition = GetMousePosition();
}
// Draw
//--------------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
// Draw common
//--------------------------------------------------------------------------------------
DrawText("*", messagePosition.x + 5, messagePosition.y + 5, 10, BLACK);
DrawText("Example optimized for Web/HTML5\non Smartphones with Touch Screen.", messagePosition.x + 15, messagePosition.y + 5, 10, BLACK);
DrawText("*", messagePosition.x + 5, messagePosition.y + 35, 10, BLACK);
DrawText("While running on Desktop Web Browsers,\ninspect and turn on Touch Emulation.", messagePosition.x + 15, messagePosition.y + 35, 10, BLACK);
// Draw last gesture
//--------------------------------------------------------------------------------------
DrawText("Last gesture", lastGesturePosition.x + 33, lastGesturePosition.y - 47, 20, BLACK);
DrawText("Swipe Tap Pinch Touch", lastGesturePosition.x + 17, lastGesturePosition.y - 18, 10, BLACK);
DrawRectangle(lastGesturePosition.x + 20, lastGesturePosition.y, 20, 20, lastGesture == GESTURE_SWIPE_UP ? RED : LIGHTGRAY);
DrawRectangle(lastGesturePosition.x, lastGesturePosition.y + 20, 20, 20, lastGesture == GESTURE_SWIPE_LEFT ? RED : LIGHTGRAY);
DrawRectangle(lastGesturePosition.x + 40, lastGesturePosition.y + 20, 20, 20, lastGesture == GESTURE_SWIPE_RIGHT ? RED : LIGHTGRAY);
DrawRectangle(lastGesturePosition.x + 20, lastGesturePosition.y + 40, 20, 20, lastGesture == GESTURE_SWIPE_DOWN ? RED : LIGHTGRAY);
DrawCircle(lastGesturePosition.x + 80, lastGesturePosition.y + 16, 10, lastGesture == GESTURE_TAP ? BLUE : LIGHTGRAY);
DrawRing( (Vector2){lastGesturePosition.x + 103, lastGesturePosition.y + 16}, 6.0f, 11.0f, 0.0f, 360.0f, 0, lastGesture == GESTURE_DRAG ? LIME : LIGHTGRAY);
DrawCircle(lastGesturePosition.x + 80, lastGesturePosition.y + 43, 10, lastGesture == GESTURE_DOUBLETAP ? SKYBLUE : LIGHTGRAY);
DrawCircle(lastGesturePosition.x + 103, lastGesturePosition.y + 43, 10, lastGesture == GESTURE_DOUBLETAP ? SKYBLUE : LIGHTGRAY);
DrawTriangle((Vector2){ lastGesturePosition.x + 122, lastGesturePosition.y + 16 }, (Vector2){ lastGesturePosition.x + 137, lastGesturePosition.y + 26 }, (Vector2){ lastGesturePosition.x + 137, lastGesturePosition.y + 6 }, lastGesture == GESTURE_PINCH_OUT? ORANGE : LIGHTGRAY);
DrawTriangle((Vector2){ lastGesturePosition.x + 147, lastGesturePosition.y + 6 }, (Vector2){ lastGesturePosition.x + 147, lastGesturePosition.y + 26 }, (Vector2){ lastGesturePosition.x + 162, lastGesturePosition.y + 16 }, lastGesture == GESTURE_PINCH_OUT? ORANGE : LIGHTGRAY);
DrawTriangle((Vector2){ lastGesturePosition.x + 125, lastGesturePosition.y + 33 }, (Vector2){ lastGesturePosition.x + 125, lastGesturePosition.y + 53 }, (Vector2){ lastGesturePosition.x + 140, lastGesturePosition.y + 43 }, lastGesture == GESTURE_PINCH_IN? VIOLET : LIGHTGRAY);
DrawTriangle((Vector2){ lastGesturePosition.x + 144, lastGesturePosition.y + 43 }, (Vector2){ lastGesturePosition.x + 159, lastGesturePosition.y + 53 }, (Vector2){ lastGesturePosition.x + 159, lastGesturePosition.y + 33 }, lastGesture == GESTURE_PINCH_IN? VIOLET : LIGHTGRAY);
for (i = 0; i < 4; i++) DrawCircle(lastGesturePosition.x + 180, lastGesturePosition.y + 7 + i*15, 5, touchCount <= i? LIGHTGRAY : gestureColor);
// Draw gesture log
//--------------------------------------------------------------------------------------
DrawText("Log", gestureLogPosition.x, gestureLogPosition.y, 20, BLACK);
// Loop in both directions to print the gesture log array in the inverted order (and looping around if the index started somewhere in the middle)
for (i = 0, ii = gestureLogIndex; i < GESTURE_LOG_SIZE; i++, ii = (ii + 1) % GESTURE_LOG_SIZE) DrawText(gestureLog[ii], gestureLogPosition.x, gestureLogPosition.y + 410 - i*20, 20, (i == 0 ? gestureColor : LIGHTGRAY));
Color logButton1Color, logButton2Color;
switch (logMode)
{
case 3: logButton1Color=MAROON; logButton2Color=MAROON; break;
case 2: logButton1Color=GRAY; logButton2Color=MAROON; break;
case 1: logButton1Color=MAROON; logButton2Color=GRAY; break;
default: logButton1Color=GRAY; logButton2Color=GRAY; break;
}
DrawRectangleRec(logButton1, logButton1Color);
DrawText("Hide", logButton1.x + 7, logButton1.y + 3, 10, WHITE);
DrawText("Repeat", logButton1.x + 7, logButton1.y + 13, 10, WHITE);
DrawRectangleRec(logButton2, logButton2Color);
DrawText("Hide", logButton1.x + 62, logButton1.y + 3, 10, WHITE);
DrawText("Hold", logButton1.x + 62, logButton1.y + 13, 10, WHITE);
// Draw protractor
//--------------------------------------------------------------------------------------
DrawText("Angle", protractorPosition.x + 55, protractorPosition.y + 76, 10, BLACK);
const char *angleString = TextFormat("%f", currentAngleDegrees);
const int angleStringDot = TextFindIndex(angleString, ".");
const char *angleStringTrim = TextSubtext(angleString, 0, angleStringDot + 3);
DrawText( angleStringTrim, protractorPosition.x + 55, protractorPosition.y + 92, 20, gestureColor);
DrawCircle(protractorPosition.x, protractorPosition.y, 80.0f, WHITE);
DrawLineEx((Vector2){ protractorPosition.x - 90, protractorPosition.y }, (Vector2){ protractorPosition.x + 90, protractorPosition.y }, 3.0f, LIGHTGRAY);
DrawLineEx((Vector2){ protractorPosition.x, protractorPosition.y - 90 }, (Vector2){ protractorPosition.x, protractorPosition.y + 90 }, 3.0f, LIGHTGRAY);
DrawLineEx((Vector2){ protractorPosition.x - 80, protractorPosition.y - 45 }, (Vector2){ protractorPosition.x + 80, protractorPosition.y + 45 }, 3.0f, GREEN);
DrawLineEx((Vector2){ protractorPosition.x - 80, protractorPosition.y + 45 }, (Vector2){ protractorPosition.x + 80, protractorPosition.y - 45 }, 3.0f, GREEN);
DrawText("0", protractorPosition.x + 96, protractorPosition.y - 9, 20, BLACK);
DrawText("30", protractorPosition.x + 74, protractorPosition.y - 68, 20, BLACK);
DrawText("90", protractorPosition.x - 11, protractorPosition.y - 110, 20, BLACK);
DrawText("150", protractorPosition.x - 100, protractorPosition.y - 68, 20, BLACK);
DrawText("180", protractorPosition.x - 124, protractorPosition.y - 9, 20, BLACK);
DrawText("210", protractorPosition.x - 100, protractorPosition.y + 50, 20, BLACK);
DrawText("270", protractorPosition.x - 18, protractorPosition.y + 92, 20, BLACK);
DrawText("330", protractorPosition.x + 72, protractorPosition.y + 50, 20, BLACK);
if (currentAngleDegrees != 0.0f) DrawLineEx(protractorPosition, finalVector, 3.0f, gestureColor);
// Draw touch and mouse pointer points
//--------------------------------------------------------------------------------------
if (currentGesture != GESTURE_NONE)
{
if ( touchCount != 0 )
{
for (i = 0; i < touchCount; i++)
{
DrawCircleV(touchPosition[i], 50.0f, Fade(gestureColor, 0.5f));
DrawCircleV(touchPosition[i], 5.0f, gestureColor);
}
if (touchCount == 2) DrawLineEx(touchPosition[0], touchPosition[1], ((currentGesture == 512)? 8 : 12), gestureColor);
}
else
{
DrawCircleV(mousePosition, 35.0f, Fade(gestureColor, 0.5f));
DrawCircleV(mousePosition, 5.0f, gestureColor);
}
}
EndDrawing();
//--------------------------------------------------------------------------------------
}
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
#if defined( PLATFORM_WEB )
// Using Emscripten EM_ASM_INT macro, get the page canvas width
const int canvasWidth = EM_ASM_INT( return document.getElementById('canvas').getBoundingClientRect().width; );
if (canvasWidth > 400) screenWidth = canvasWidth;
else screenWidth = 400; // Set a minimum width for the screen
#endif
InitWindow(screenWidth, screenHeight, "raylib [core] example - input gestures web");
//--------------------------------------------------------------------------------------
// Main game loop
//--------------------------------------------------------------------------------------
#if defined(PLATFORM_WEB)
emscripten_set_main_loop(Update, 0, 1);
#else
SetTargetFPS(60);
while (!WindowShouldClose()) Update(); // Detect window close button or ESC key
#endif
//--------------------------------------------------------------------------------------
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -41,7 +41,7 @@
* *
* raylib [core] example - Basic window * raylib [core] example - Basic window
* *
* Example originally created with raylib 4.2, last time updated with raylib 4.2 * Example originally created with raylib 4.5, last time updated with raylib 4.5
* *
* Example contributed by <user_name> (@<user_github>) and reviewed by Ramon Santamaria (@raysan5) * Example contributed by <user_name> (@<user_github>) and reviewed by Ramon Santamaria (@raysan5)
* *

View File

@ -0,0 +1,106 @@
/*******************************************************************************************
*
* raylib [shapes] example - Vector Angle
*
* Example originally created with raylib 1.0, last time updated with raylib 4.2
*
* Example 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) 2023 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include "raylib.h"
#include "raymath.h"
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [math] example - vector angle");
Vector2 v0 = { screenWidth/2, screenHeight/2 };
Vector2 v1 = { 100.0f, 80.0f };
Vector2 v2 = { 0 }; // Updated with mouse position
float angle = 0.0f; // Angle in degrees
int angleMode = 0; // 0-Vector2Angle(), 1-Vector2LineAngle()
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KEY_SPACE)) angleMode = !angleMode;
if (angleMode == 0)
{
// Calculate angle between two vectors, considering a common origin (v0)
v1 = Vector2Add(v0, (Vector2){ 100.0f, 80.0f });
v2 = GetMousePosition();
angle = Vector2Angle(Vector2Normalize(Vector2Subtract(v1, v0)), Vector2Normalize(Vector2Subtract(v2, v0)))*RAD2DEG;
}
else if (angleMode == 1)
{
// Calculate angle defined by a two vectors line, in reference to horizontal line
v1 = (Vector2){ screenWidth/2, screenHeight/2 };
v2 = GetMousePosition();
angle = Vector2LineAngle(v1, v2)*RAD2DEG;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
if (angleMode == 0) DrawText("v0", v0.x, v0.y, 10, DARKGRAY);
DrawText("v1", v1.x, v1.y, 10, DARKGRAY);
DrawText("v2", v2.x, v2.y, 10, DARKGRAY);
if (angleMode == 0)
{
DrawText("MODE: Angle between V1 and V2", 10, 10, 20, BLACK);
DrawLineEx(v0, v1, 2.0f, BLACK);
DrawLineEx(v0, v2, 2.0f, RED);
float startangle = 90 - Vector2LineAngle(v0, v1)*RAD2DEG;
DrawCircleSector(v0, 40.0f, startangle, startangle + angle - 360.0f*(angle > 180.0f), 32, Fade(GREEN, 0.6f));
}
else if (angleMode == 1)
{
DrawText("MODE: Angle formed by line V1 to V2", 10, 10, 20, BLACK);
DrawLine(0, screenHeight/2, screenWidth, screenHeight/2, LIGHTGRAY);
DrawLineEx(v1, v2, 2.0f, RED);
DrawCircleSector(v1, 40.0f, 90.0f, 180 - angle - 90, 32, Fade(GREEN, 0.6f));
}
DrawText("Press SPACE to change MODE", 460, 10, 20, DARKGRAY);
DrawText(TextFormat("ANGLE: %2.2f", angle), 10, 40, 20, LIME);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -181,6 +181,11 @@
// If not defined, still some functions are supported: TextLength(), TextFormat() // If not defined, still some functions are supported: TextLength(), TextFormat()
#define SUPPORT_TEXT_MANIPULATION 1 #define SUPPORT_TEXT_MANIPULATION 1
// On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle
// at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow
// drawing text and shapes with a single draw call [SetShapesTexture()].
#define SUPPORT_FONT_ATLAS_WHITE_REC 1
// rtext: Configuration values // rtext: Configuration values
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions: #define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:

145
src/external/sdefl.h vendored
View File

@ -71,7 +71,7 @@ Results on the [Silesia compression corpus](http://sun.aei.polsl.pl/~sdeor/index
This software is available under 2 licenses -- choose whichever you prefer. This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
ALTERNATIVE A - MIT License ALTERNATIVE A - MIT License
Copyright (c) 2020 Micha Mettke Copyright (c) 2020-2023 Micha Mettke
Permission is hereby granted, free of charge, to any person obtaining a copy of 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 this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to the Software without restriction, including without limitation the rights to
@ -125,7 +125,7 @@ extern "C" {
#define SDEFL_MIN_MATCH 4 #define SDEFL_MIN_MATCH 4
#define SDEFL_BLK_MAX (256*1024) #define SDEFL_BLK_MAX (256*1024)
#define SDEFL_SEQ_SIZ ((SDEFL_BLK_MAX + SDEFL_MIN_MATCH)/SDEFL_MIN_MATCH) #define SDEFL_SEQ_SIZ ((SDEFL_BLK_MAX+2)/3)
#define SDEFL_SYM_MAX (288) #define SDEFL_SYM_MAX (288)
#define SDEFL_OFF_MAX (32) #define SDEFL_OFF_MAX (32)
@ -185,6 +185,7 @@ extern int zsdeflate(struct sdefl *s, void *o, const void *i, int n, int lvl);
#define SDEFL_MAX_CODE_LEN (15) #define SDEFL_MAX_CODE_LEN (15)
#define SDEFL_SYM_BITS (10u) #define SDEFL_SYM_BITS (10u)
#define SDEFL_SYM_MSK ((1u << SDEFL_SYM_BITS)-1u) #define SDEFL_SYM_MSK ((1u << SDEFL_SYM_BITS)-1u)
#define SDEFL_RAW_BLK_SIZE (65535)
#define SDEFL_LIT_LEN_CODES (14) #define SDEFL_LIT_LEN_CODES (14)
#define SDEFL_OFF_CODES (15) #define SDEFL_OFF_CODES (15)
#define SDEFL_PRE_CODES (7) #define SDEFL_PRE_CODES (7)
@ -192,6 +193,7 @@ extern int zsdeflate(struct sdefl *s, void *o, const void *i, int n, int lvl);
#define SDEFL_EOB (256) #define SDEFL_EOB (256)
#define sdefl_npow2(n) (1 << (sdefl_ilog2((n)-1) + 1)) #define sdefl_npow2(n) (1 << (sdefl_ilog2((n)-1) + 1))
#define sdefl_div_round_up(n,d) (((n)+((d)-1))/(d))
static int static int
sdefl_ilog2(int n) { sdefl_ilog2(int n) {
@ -438,12 +440,12 @@ sdefl_precode(struct sdefl_symcnt *cnt, unsigned *freqs, unsigned *items,
} while (run_start != total); } while (run_start != total);
cnt->items = (int)(at - items); cnt->items = (int)(at - items);
} }
struct sdefl_match_codes { struct sdefl_match_codest {
int ls, lc; int ls, lc;
int dc, dx; int dc, dx;
}; };
static void static void
sdefl_match_codes(struct sdefl_match_codes *cod, int dist, int len) { sdefl_match_codes(struct sdefl_match_codest *cod, int dist, int len) {
static const short dxmax[] = {0,6,12,24,48,96,192,384,768,1536,3072,6144,12288,24576}; static const short dxmax[] = {0,6,12,24,48,96,192,384,768,1536,3072,6144,12288,24576};
static const unsigned char lslot[258+1] = { static const unsigned char lslot[258+1] = {
0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12,
@ -471,6 +473,44 @@ sdefl_match_codes(struct sdefl_match_codes *cod, int dist, int len) {
cod->dx = sdefl_ilog2(sdefl_npow2(dist) >> 2); cod->dx = sdefl_ilog2(sdefl_npow2(dist) >> 2);
cod->dc = cod->dx ? ((cod->dx + 1) << 1) + (dist > dxmax[cod->dx]) : dist-1; cod->dc = cod->dx ? ((cod->dx + 1) << 1) + (dist > dxmax[cod->dx]) : dist-1;
} }
enum sdefl_blk_type {
SDEFL_BLK_UCOMPR,
SDEFL_BLK_DYN
};
static enum sdefl_blk_type
sdefl_blk_type(const struct sdefl *s, int blk_len, int pre_item_len,
const unsigned *pre_freq, const unsigned char *pre_len) {
static const unsigned char x_pre_bits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
static const unsigned char x_len_bits[] = {0,0,0,0,0,0,0,0, 1,1,1,1,2,2,2,2,
3,3,3,3,4,4,4,4, 5,5,5,5,0};
static const unsigned char x_off_bits[] = {0,0,0,0,1,1,2,2, 3,3,4,4,5,5,6,6,
7,7,8,8,9,9,10,10, 11,11,12,12,13,13};
int dyn_cost = 0;
int fix_cost = 0;
int sym = 0;
dyn_cost += 5 + 5 + 4 + (3 * pre_item_len);
for (sym = 0; sym < SDEFL_PRE_MAX; sym++)
dyn_cost += pre_freq[sym] * (x_pre_bits[sym] + pre_len[sym]);
for (sym = 0; sym < 256; sym++)
dyn_cost += s->freq.lit[sym] * s->cod.len.lit[sym];
dyn_cost += s->cod.len.lit[SDEFL_EOB];
for (sym = 257; sym < 286; sym++)
dyn_cost += s->freq.lit[sym] * (x_len_bits[sym - 257] + s->cod.len.lit[sym]);
for (sym = 0; sym < 30; sym++)
dyn_cost += s->freq.off[sym] * (x_off_bits[sym] + s->cod.len.off[sym]);
fix_cost += 8*(5 * sdefl_div_round_up(blk_len, SDEFL_RAW_BLK_SIZE) + blk_len + 1 + 2);
return (dyn_cost < fix_cost) ? SDEFL_BLK_DYN : SDEFL_BLK_UCOMPR;
}
static void
sdefl_put16(unsigned char **dst, unsigned short x) {
unsigned char *val = *dst;
val[0] = (unsigned char)(x & 0xff);
val[1] = (unsigned char)(x >> 8);
*dst = val + 2;
}
static void static void
sdefl_match(unsigned char **dst, struct sdefl *s, int dist, int len) { sdefl_match(unsigned char **dst, struct sdefl *s, int dist, int len) {
static const char lxn[] = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; static const char lxn[] = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
@ -479,7 +519,7 @@ sdefl_match(unsigned char **dst, struct sdefl *s, int dist, int len) {
static const short dmin[] = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257, static const short dmin[] = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,
385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577}; 385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577};
struct sdefl_match_codes cod; struct sdefl_match_codest cod;
sdefl_match_codes(&cod, dist, len); sdefl_match_codes(&cod, dist, len);
sdefl_put(dst, s, (int)s->cod.word.lit[cod.lc], s->cod.len.lit[cod.lc]); sdefl_put(dst, s, (int)s->cod.word.lit[cod.lc], s->cod.len.lit[cod.lc]);
sdefl_put(dst, s, len - lmin[cod.ls], lxn[cod.ls]); sdefl_put(dst, s, len - lmin[cod.ls], lxn[cod.ls]);
@ -488,7 +528,8 @@ sdefl_match(unsigned char **dst, struct sdefl *s, int dist, int len) {
} }
static void static void
sdefl_flush(unsigned char **dst, struct sdefl *s, int is_last, sdefl_flush(unsigned char **dst, struct sdefl *s, int is_last,
const unsigned char *in) { const unsigned char *in, int blk_begin, int blk_end) {
int blk_len = blk_end - blk_begin;
int j, i = 0, item_cnt = 0; int j, i = 0, item_cnt = 0;
struct sdefl_symcnt symcnt = {0}; struct sdefl_symcnt symcnt = {0};
unsigned codes[SDEFL_PRE_MAX]; unsigned codes[SDEFL_PRE_MAX];
@ -498,7 +539,7 @@ sdefl_flush(unsigned char **dst, struct sdefl *s, int is_last,
static const unsigned char perm[SDEFL_PRE_MAX] = {16,17,18,0,8,7,9,6,10,5,11, static const unsigned char perm[SDEFL_PRE_MAX] = {16,17,18,0,8,7,9,6,10,5,11,
4,12,3,13,2,14,1,15}; 4,12,3,13,2,14,1,15};
/* huffman codes */ /* calculate huffman codes */
s->freq.lit[SDEFL_EOB]++; s->freq.lit[SDEFL_EOB]++;
sdefl_huff(s->cod.len.lit, s->cod.word.lit, s->freq.lit, SDEFL_SYM_MAX, SDEFL_LIT_LEN_CODES); sdefl_huff(s->cod.len.lit, s->cod.word.lit, s->freq.lit, SDEFL_SYM_MAX, SDEFL_LIT_LEN_CODES);
sdefl_huff(s->cod.len.off, s->cod.word.off, s->freq.off, SDEFL_OFF_MAX, SDEFL_OFF_CODES); sdefl_huff(s->cod.len.off, s->cod.word.off, s->freq.off, SDEFL_OFF_MAX, SDEFL_OFF_CODES);
@ -509,8 +550,30 @@ sdefl_flush(unsigned char **dst, struct sdefl *s, int is_last,
break; break;
} }
} }
/* block header */ /* write block */
sdefl_put(dst, s, is_last ? 0x01 : 0x00, 1); /* block */ switch (sdefl_blk_type(s, blk_len, item_cnt, freqs, lens)) {
case SDEFL_BLK_UCOMPR: {
/* uncompressed blocks */
int n = sdefl_div_round_up(blk_len, SDEFL_RAW_BLK_SIZE);
for (i = 0; i < n; ++i) {
int fin = is_last && (i + 1 == n);
int amount = blk_len < SDEFL_RAW_BLK_SIZE ? blk_len : SDEFL_RAW_BLK_SIZE;
sdefl_put(dst, s, !!fin, 1); /* block */
sdefl_put(dst, s, 0x00, 2); /* stored block */
if (s->bitcnt) {
sdefl_put(dst, s, 0x00, 8 - s->bitcnt);
}
assert(s->bitcnt == 0);
sdefl_put16(dst, (unsigned short)amount);
sdefl_put16(dst, ~(unsigned short)amount);
memcpy(*dst, in + blk_begin + i * SDEFL_RAW_BLK_SIZE, amount);
*dst = *dst + amount;
blk_len -= amount;
}
} break;
case SDEFL_BLK_DYN: {
/* dynamic huffman block */
sdefl_put(dst, s, !!is_last, 1); /* block */
sdefl_put(dst, s, 0x02, 2); /* dynamic huffman */ sdefl_put(dst, s, 0x02, 2); /* dynamic huffman */
sdefl_put(dst, s, symcnt.lit - 257, 5); sdefl_put(dst, s, symcnt.lit - 257, 5);
sdefl_put(dst, s, symcnt.off - 1, 5); sdefl_put(dst, s, symcnt.off - 1, 5);
@ -538,6 +601,7 @@ sdefl_flush(unsigned char **dst, struct sdefl *s, int is_last,
} }
} }
sdefl_put(dst, s, (int)(s)->cod.word.lit[SDEFL_EOB], (s)->cod.len.lit[SDEFL_EOB]); sdefl_put(dst, s, (int)(s)->cod.word.lit[SDEFL_EOB], (s)->cod.len.lit[SDEFL_EOB]);
} break;}
memset(&s->freq, 0, sizeof(s->freq)); memset(&s->freq, 0, sizeof(s->freq));
s->seq_cnt = 0; s->seq_cnt = 0;
} }
@ -550,8 +614,12 @@ sdefl_seq(struct sdefl *s, int off, int len) {
} }
static void static void
sdefl_reg_match(struct sdefl *s, int off, int len) { sdefl_reg_match(struct sdefl *s, int off, int len) {
struct sdefl_match_codes cod; struct sdefl_match_codest cod;
sdefl_match_codes(&cod, off, len); sdefl_match_codes(&cod, off, len);
assert(cod.lc < SDEFL_SYM_MAX);
assert(cod.dc < SDEFL_OFF_MAX);
s->freq.lit[cod.lc]++; s->freq.lit[cod.lc]++;
s->freq.off[cod.dc]++; s->freq.off[cod.dc]++;
} }
@ -560,22 +628,35 @@ struct sdefl_match {
int len; int len;
}; };
static void static void
sdefl_fnd(struct sdefl_match *m, const struct sdefl *s, sdefl_fnd(struct sdefl_match *m, const struct sdefl *s, int chain_len,
int chain_len, int max_match, const unsigned char *in, int p) { int max_match, const unsigned char *in, int p, int e) {
int i = s->tbl[sdefl_hash32(&in[p])]; int i = s->tbl[sdefl_hash32(in + p)];
int limit = ((p-SDEFL_WIN_SIZ)<SDEFL_NIL)?SDEFL_NIL:(p-SDEFL_WIN_SIZ); int limit = ((p - SDEFL_WIN_SIZ) < SDEFL_NIL) ? SDEFL_NIL : (p-SDEFL_WIN_SIZ);
assert(p < e);
assert(p + max_match <= e);
while (i > limit) { while (i > limit) {
if (in[i+m->len] == in[p+m->len] && assert(i + m->len < e);
(sdefl_uload32(&in[i]) == sdefl_uload32(&in[p]))){ assert(p + m->len < e);
assert(i + SDEFL_MIN_MATCH < e);
assert(p + SDEFL_MIN_MATCH < e);
if (in[i + m->len] == in[p + m->len] &&
(sdefl_uload32(&in[i]) == sdefl_uload32(&in[p]))) {
int n = SDEFL_MIN_MATCH; int n = SDEFL_MIN_MATCH;
while (n < max_match && in[i+n] == in[p+n]) n++; while (n < max_match && in[i + n] == in[p + n]) {
assert(i + n < e);
assert(p + n < e);
n++;
}
if (n > m->len) { if (n > m->len) {
m->len = n, m->off = p - i; m->len = n, m->off = p - i;
if (n == max_match) break; if (n == max_match)
break;
} }
} }
if (!(--chain_len)) break; if (!(--chain_len)) break;
i = s->prv[i&SDEFL_WIN_MSK]; i = s->prv[i & SDEFL_WIN_MSK];
} }
} }
static int static int
@ -588,19 +669,20 @@ sdefl_compr(struct sdefl *s, unsigned char *out, const unsigned char *in,
for (n = 0; n < SDEFL_HASH_SIZ; ++n) { for (n = 0; n < SDEFL_HASH_SIZ; ++n) {
s->tbl[n] = SDEFL_NIL; s->tbl[n] = SDEFL_NIL;
} }
do {int blk_end = ((i + SDEFL_BLK_MAX) < in_len) ? (i + SDEFL_BLK_MAX) : in_len; do {int blk_begin = i;
int blk_end = ((i + SDEFL_BLK_MAX) < in_len) ? (i + SDEFL_BLK_MAX) : in_len;
while (i < blk_end) { while (i < blk_end) {
struct sdefl_match m = {0}; struct sdefl_match m = {0};
int left = blk_end - i; int left = blk_end - i;
int max_match = (left >= SDEFL_MAX_MATCH) ? SDEFL_MAX_MATCH : left; int max_match = (left > SDEFL_MAX_MATCH) ? SDEFL_MAX_MATCH : left;
int nice_match = pref[lvl] < max_match ? pref[lvl] : max_match; int nice_match = pref[lvl] < max_match ? pref[lvl] : max_match;
int run = 1, inc = 1, run_inc = 0; int run = 1, inc = 1, run_inc = 0;
if (max_match > SDEFL_MIN_MATCH) { if (max_match > SDEFL_MIN_MATCH) {
sdefl_fnd(&m, s, max_chain, max_match, in, i); sdefl_fnd(&m, s, max_chain, max_match, in, i, in_len);
} }
if (lvl >= 5 && m.len >= SDEFL_MIN_MATCH && m.len < nice_match){ if (lvl >= 5 && m.len >= SDEFL_MIN_MATCH && m.len + 1 < nice_match){
struct sdefl_match m2 = {0}; struct sdefl_match m2 = {0};
sdefl_fnd(&m2, s, max_chain, m.len+1, in, i+1); sdefl_fnd(&m2, s, max_chain, m.len + 1, in, i + 1, in_len);
m.len = (m2.len > m.len) ? 0 : m.len; m.len = (m2.len > m.len) ? 0 : m.len;
} }
if (m.len >= SDEFL_MIN_MATCH) { if (m.len >= SDEFL_MIN_MATCH) {
@ -636,12 +718,12 @@ sdefl_compr(struct sdefl *s, unsigned char *out, const unsigned char *in,
sdefl_seq(s, i - litlen, litlen); sdefl_seq(s, i - litlen, litlen);
litlen = 0; litlen = 0;
} }
sdefl_flush(&q, s, blk_end == in_len, in); sdefl_flush(&q, s, blk_end == in_len, in, blk_begin, blk_end);
} while (i < in_len); } while (i < in_len);
if (s->bitcnt) {
if (s->bitcnt > 0)
sdefl_put(&q, s, 0x00, 8 - s->bitcnt); sdefl_put(&q, s, 0x00, 8 - s->bitcnt);
}
assert(s->bitcnt == 0);
return (int)(q - out); return (int)(q - out);
} }
extern int extern int
@ -701,9 +783,8 @@ zsdeflate(struct sdefl *s, void *out, const void *in, int n, int lvl) {
} }
extern int extern int
sdefl_bound(int len) { sdefl_bound(int len) {
int a = 128 + (len * 110) / 100; int max_blocks = 1 + sdefl_div_round_up(len, SDEFL_RAW_BLK_SIZE);
int b = 128 + len + ((len / (31 * 1024)) + 1) * 5; int bound = 5 * max_blocks + len + 1 + 4 + 8;
return (a > b) ? a : b; return bound;
} }
#endif /* SDEFL_IMPLEMENTATION */ #endif /* SDEFL_IMPLEMENTATION */

28
src/external/sinfl.h vendored
View File

@ -72,7 +72,7 @@ Results on the [Silesia compression corpus](http://sun.aei.polsl.pl/~sdeor/index
This software is available under 2 licenses -- choose whichever you prefer. This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
ALTERNATIVE A - MIT License ALTERNATIVE A - MIT License
Copyright (c) 2020 Micha Mettke Copyright (c) 2020-2023 Micha Mettke
Permission is hereby granted, free of charge, to any person obtaining a copy of 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 this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to the Software without restriction, including without limitation the rights to
@ -400,17 +400,21 @@ sinfl_decompress(unsigned char *out, int cap, const unsigned char *in, int size)
} break; } break;
case stored: { case stored: {
/* uncompressed block */ /* uncompressed block */
int len, nlen; unsigned len, nlen;
sinfl_refill(&s);
sinfl__get(&s,s.bitcnt & 7); sinfl__get(&s,s.bitcnt & 7);
len = sinfl__get(&s,16); len = (unsigned short)sinfl__get(&s,16);
nlen = sinfl__get(&s,16); nlen = (unsigned short)sinfl__get(&s,16);
in -= 2; s.bitcnt = 0; s.bitptr -= s.bitcnt / 8;
s.bitbuf = s.bitcnt = 0;
if (len > (e-in) || !len) if ((unsigned short)len != (unsigned short)~nlen)
return (int)(out-o); return (int)(out-o);
memcpy(out, in, (size_t)len); if (len > (e - s.bitptr) || !len)
in += len, out += len; return (int)(out-o);
memcpy(out, s.bitptr, (size_t)len);
s.bitptr += len, out += len;
if (last) return (int)(out-o);
state = hdr; state = hdr;
} break; } break;
case fixed: { case fixed: {
@ -443,8 +447,9 @@ sinfl_decompress(unsigned char *out, int cap, const unsigned char *in, int size)
/* decode code lengths */ /* decode code lengths */
for (n = 0; n < nlit + ndist;) { for (n = 0; n < nlit + ndist;) {
int sym = 0;
sinfl_refill(&s); sinfl_refill(&s);
int sym = sinfl_decode(&s, hlens, 7); sym = sinfl_decode(&s, hlens, 7);
switch (sym) {default: lens[n++] = (unsigned char)sym; break; switch (sym) {default: lens[n++] = (unsigned char)sym; break;
case 16: for (i=3+sinfl_get(&s,2);i;i--,n++) lens[n]=lens[n-1]; break; case 16: for (i=3+sinfl_get(&s,2);i;i--,n++) lens[n]=lens[n-1]; break;
case 17: for (i=3+sinfl_get(&s,3);i;i--,n++) lens[n]=0; break; case 17: for (i=3+sinfl_get(&s,3);i;i--,n++) lens[n]=0; break;
@ -458,8 +463,9 @@ sinfl_decompress(unsigned char *out, int cap, const unsigned char *in, int size)
case blk: { case blk: {
/* decompress block */ /* decompress block */
while (1) { while (1) {
int sym;
sinfl_refill(&s); sinfl_refill(&s);
int sym = sinfl_decode(&s, s.lits, 10); sym = sinfl_decode(&s, s.lits, 10);
if (sym < 256) { if (sym < 256) {
/* literal */ /* literal */
if (sinfl_unlikely(out >= oe)) { if (sinfl_unlikely(out >= oe)) {

View File

@ -958,6 +958,7 @@ RLAPI void SetWindowMonitor(int monitor); // Set monitor
RLAPI void SetWindowMinSize(int width, int height); // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) RLAPI void SetWindowMinSize(int width, int height); // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE)
RLAPI void SetWindowSize(int width, int height); // Set window dimensions RLAPI void SetWindowSize(int width, int height); // Set window dimensions
RLAPI void SetWindowOpacity(float opacity); // Set window opacity [0.0f..1.0f] (only PLATFORM_DESKTOP) RLAPI void SetWindowOpacity(float opacity); // Set window opacity [0.0f..1.0f] (only PLATFORM_DESKTOP)
RLAPI void SetWindowFocused(void); // Set window focused (only PLATFORM_DESKTOP)
RLAPI void *GetWindowHandle(void); // Get native window handle RLAPI void *GetWindowHandle(void); // Get native window handle
RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenWidth(void); // Get current screen width
RLAPI int GetScreenHeight(void); // Get current screen height RLAPI int GetScreenHeight(void); // Get current screen height
@ -1381,6 +1382,7 @@ RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float f
RLAPI void DrawTextCodepoints(Font font, const int *codepoints, int count, Vector2 position, float fontSize, float spacing, Color tint); // Draw multiple character (codepoint) RLAPI void DrawTextCodepoints(Font font, const int *codepoints, int count, Vector2 position, float fontSize, float spacing, Color tint); // Draw multiple character (codepoint)
// Text font info functions // Text font info functions
RLAPI void SetTextLineSpacing(int spacing); // Set vertical line spacing when drawing with line-breaks
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 glyph index position in font for a codepoint (unicode character), fallback to '?' if not found RLAPI int GetGlyphIndex(Font font, int codepoint); // Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found
@ -1589,7 +1591,7 @@ RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback);
RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream
RLAPI void DetachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Detach audio stream processor from stream RLAPI void DetachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Detach audio stream processor from stream
RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline, receives the samples as <float>s
RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline
#if defined(__cplusplus) #if defined(__cplusplus)

View File

@ -314,7 +314,11 @@ RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2)
// NOTE: Angle is calculated from origin point (0, 0) // NOTE: Angle is calculated from origin point (0, 0)
RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) RMAPI float Vector2Angle(Vector2 v1, Vector2 v2)
{ {
float result = atan2f(v2.y - v1.y, v2.x - v1.x); float result = 0.0f;
float dot = v1.x*v2.x + v1.y*v2.y;
float det = v1.x*v2.y - v1.y*v2.x;
result = -atan2f(det, dot);
return result; return result;
} }
@ -326,17 +330,7 @@ RMAPI float Vector2LineAngle(Vector2 start, Vector2 end)
{ {
float result = 0.0f; float result = 0.0f;
float dot = start.x*end.x + start.y*end.y; // Dot product result = atan2f(end.y - start.y, end.x - start.x);
float dotClamp = (dot < -1.0f)? -1.0f : dot; // Clamp
if (dotClamp > 1.0f) dotClamp = 1.0f;
result = acosf(dotClamp);
// Alternative implementation, more costly
//float v1Length = sqrtf((start.x*start.x) + (start.y*start.y));
//float v2Length = sqrtf((end.x*end.x) + (end.y*end.y));
//float result = -acosf((start.x*end.x + start.y*end.y)/(v1Length*v2Length));
return result; return result;
} }
@ -1515,11 +1509,11 @@ RMAPI Matrix MatrixFrustum(double left, double right, double bottom, double top,
// Get perspective projection matrix // Get perspective projection matrix
// NOTE: Fovy angle must be provided in radians // NOTE: Fovy angle must be provided in radians
RMAPI Matrix MatrixPerspective(double fovy, double aspect, double near, double far) RMAPI Matrix MatrixPerspective(double fovY, double aspect, double nearPlane, double farPlane)
{ {
Matrix result = { 0 }; Matrix result = { 0 };
double top = near*tan(fovy*0.5); double top = nearPlane*tan(fovY*0.5);
double bottom = -top; double bottom = -top;
double right = top*aspect; double right = top*aspect;
double left = -right; double left = -right;
@ -1527,27 +1521,27 @@ RMAPI Matrix MatrixPerspective(double fovy, double aspect, double near, double f
// MatrixFrustum(-right, right, -top, top, near, far); // MatrixFrustum(-right, right, -top, top, near, far);
float rl = (float)(right - left); float rl = (float)(right - left);
float tb = (float)(top - bottom); float tb = (float)(top - bottom);
float fn = (float)(far - near); float fn = (float)(farPlane - nearPlane);
result.m0 = ((float)near*2.0f)/rl; result.m0 = ((float)nearPlane*2.0f)/rl;
result.m5 = ((float)near*2.0f)/tb; result.m5 = ((float)nearPlane*2.0f)/tb;
result.m8 = ((float)right + (float)left)/rl; result.m8 = ((float)right + (float)left)/rl;
result.m9 = ((float)top + (float)bottom)/tb; result.m9 = ((float)top + (float)bottom)/tb;
result.m10 = -((float)far + (float)near)/fn; result.m10 = -((float)farPlane + (float)nearPlane)/fn;
result.m11 = -1.0f; result.m11 = -1.0f;
result.m14 = -((float)far*(float)near*2.0f)/fn; result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/fn;
return result; return result;
} }
// Get orthographic projection matrix // Get orthographic projection matrix
RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far) RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, double nearPlane, double farPlane)
{ {
Matrix result = { 0 }; Matrix result = { 0 };
float rl = (float)(right - left); float rl = (float)(right - left);
float tb = (float)(top - bottom); float tb = (float)(top - bottom);
float fn = (float)(far - near); float fn = (float)(farPlane - nearPlane);
result.m0 = 2.0f/rl; result.m0 = 2.0f/rl;
result.m1 = 0.0f; result.m1 = 0.0f;
@ -1563,7 +1557,7 @@ RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, d
result.m11 = 0.0f; result.m11 = 0.0f;
result.m12 = -((float)left + (float)right)/rl; result.m12 = -((float)left + (float)right)/rl;
result.m13 = -((float)top + (float)bottom)/tb; result.m13 = -((float)top + (float)bottom)/tb;
result.m14 = -((float)far + (float)near)/fn; result.m14 = -((float)farPlane + (float)nearPlane)/fn;
result.m15 = 1.0f; result.m15 = 1.0f;
return result; return result;

View File

@ -3,12 +3,12 @@
* rcamera - Basic camera system with support for multiple camera modes * rcamera - Basic camera system with support for multiple camera modes
* *
* CONFIGURATION: * CONFIGURATION:
* #define CAMERA_IMPLEMENTATION * #define RCAMERA_IMPLEMENTATION
* Generates the implementation of the library into the included file. * Generates the implementation of the library into the included file.
* If not defined, the library is in header only mode and can be included in other headers * If not defined, the library is in header only mode and can be included in other headers
* or source files without problems. But only ONE file should hold the implementation. * or source files without problems. But only ONE file should hold the implementation.
* *
* #define CAMERA_STANDALONE * #define RCAMERA_STANDALONE
* If defined, the library can be used as standalone as a camera system but some * If defined, the library can be used as standalone as a camera system but some
* functions must be redefined to manage inputs accordingly. * functions must be redefined to manage inputs accordingly.
* *
@ -50,7 +50,7 @@
#define RLAPI // Functions defined as 'extern' by default (implicit specifiers) #define RLAPI // Functions defined as 'extern' by default (implicit specifiers)
#endif #endif
#if defined(CAMERA_STANDALONE) #if defined(RCAMERA_STANDALONE)
#define CAMERA_CULL_DISTANCE_NEAR 0.01 #define CAMERA_CULL_DISTANCE_NEAR 0.01
#define CAMERA_CULL_DISTANCE_FAR 1000.0 #define CAMERA_CULL_DISTANCE_FAR 1000.0
#else #else
@ -60,9 +60,9 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
// NOTE: Below types are required for CAMERA_STANDALONE usage // NOTE: Below types are required for standalone usage
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(CAMERA_STANDALONE) #if defined(RCAMERA_STANDALONE)
// Vector2, 2 components // Vector2, 2 components
typedef struct Vector2 { typedef struct Vector2 {
float x; // Vector x component float x; // Vector x component
@ -76,6 +76,14 @@
float z; // Vector z component float z; // Vector z component
} Vector3; } Vector3;
// Matrix, 4x4 components, column major, OpenGL style, right-handed
typedef struct Matrix {
float m0, m4, m8, m12; // Matrix first row (4 components)
float m1, m5, m9, m13; // Matrix second row (4 components)
float m2, m6, m10, m14; // Matrix third row (4 components)
float m3, m7, m11, m15; // Matrix fourth row (4 components)
} Matrix;
// Camera type, defines a camera position/orientation in 3d space // Camera type, defines a camera position/orientation in 3d space
typedef struct Camera3D { typedef struct Camera3D {
Vector3 position; // Camera position Vector3 position; // Camera position
@ -138,7 +146,7 @@ RLAPI Matrix GetCameraProjectionMatrix(Camera* camera, float aspect);
} }
#endif #endif
#endif // CAMERA_H #endif // RCAMERA_H
/*********************************************************************************** /***********************************************************************************
@ -147,7 +155,7 @@ RLAPI Matrix GetCameraProjectionMatrix(Camera* camera, float aspect);
* *
************************************************************************************/ ************************************************************************************/
#if defined(CAMERA_IMPLEMENTATION) #if defined(RCAMERA_IMPLEMENTATION)
#include "raymath.h" // Required for vector maths: #include "raymath.h" // Required for vector maths:
// Vector3Add() // Vector3Add()
@ -417,7 +425,7 @@ Matrix GetCameraProjectionMatrix(Camera *camera, float aspect)
return MatrixIdentity(); return MatrixIdentity();
} }
#ifndef CAMERA_STANDALONE #if !defined(RCAMERA_STANDALONE)
// Update camera position for selected mode // Update camera position for selected mode
// Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM // Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM
void UpdateCamera(Camera *camera, int mode) void UpdateCamera(Camera *camera, int mode)
@ -483,7 +491,7 @@ void UpdateCamera(Camera *camera, int mode)
if (IsKeyPressed(KEY_KP_ADD)) CameraMoveToTarget(camera, -2.0f); if (IsKeyPressed(KEY_KP_ADD)) CameraMoveToTarget(camera, -2.0f);
} }
} }
#endif // !CAMERA_STANDALONE #endif // !RCAMERA_STANDALONE
// Update camera movement, movement/rotation values should be provided by user // Update camera movement, movement/rotation values should be provided by user
void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom) void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom)
@ -516,4 +524,4 @@ void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float z
CameraMoveToTarget(camera, zoom); CameraMoveToTarget(camera, zoom);
} }
#endif // CAMERA_IMPLEMENTATION #endif // RCAMERA_IMPLEMENTATION

View File

@ -124,12 +124,12 @@
#include "raymath.h" // Vector3, Quaternion and Matrix functionality #include "raymath.h" // Vector3, Quaternion and Matrix functionality
#if defined(SUPPORT_GESTURES_SYSTEM) #if defined(SUPPORT_GESTURES_SYSTEM)
#define GESTURES_IMPLEMENTATION #define RGESTURES_IMPLEMENTATION
#include "rgestures.h" // Gestures detection functionality #include "rgestures.h" // Gestures detection functionality
#endif #endif
#if defined(SUPPORT_CAMERA_SYSTEM) #if defined(SUPPORT_CAMERA_SYSTEM)
#define CAMERA_IMPLEMENTATION #define RCAMERA_IMPLEMENTATION
#include "rcamera.h" // Camera system functionality #include "rcamera.h" // Camera system functionality
#endif #endif
@ -1705,6 +1705,14 @@ void SetWindowOpacity(float opacity)
#endif #endif
} }
// Set window focused
void SetWindowFocused(void)
{
#if defined(PLATFORM_DESKTOP)
glfwFocusWindow(CORE.Window.handle);
#endif
}
// Get current screen width // Get current screen width
int GetScreenWidth(void) int GetScreenWidth(void)
{ {
@ -3219,7 +3227,7 @@ const char *GetApplicationDirectory(void)
#if defined(_WIN32) #if defined(_WIN32)
int len = 0; int len = 0;
#if defined (UNICODE) #if defined(UNICODE)
unsigned short widePath[MAX_PATH]; unsigned short widePath[MAX_PATH];
len = GetModuleFileNameW(NULL, widePath, MAX_PATH); len = GetModuleFileNameW(NULL, widePath, MAX_PATH);
len = WideCharToMultiByte(0, 0, widePath, len, appDir, MAX_PATH, NULL, NULL); len = WideCharToMultiByte(0, 0, widePath, len, appDir, MAX_PATH, NULL, NULL);
@ -5585,8 +5593,14 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
gestureEvent.position[0].y /= (float)GetScreenHeight(); gestureEvent.position[0].y /= (float)GetScreenHeight();
// Gesture data is sent to gestures-system for processing // Gesture data is sent to gestures-system for processing
#if defined(PLATFORM_WEB)
// Prevent calling ProcessGestureEvent() when Emscripten is present and there's a touch gesture, so EmscriptenTouchCallback() can handle it itself
if (GetMouseX() != 0 || GetMouseY() != 0) ProcessGestureEvent(gestureEvent);
#else
ProcessGestureEvent(gestureEvent); ProcessGestureEvent(gestureEvent);
#endif #endif
#endif
} }
// GLFW3 Cursor Position Callback, runs on mouse move // GLFW3 Cursor Position Callback, runs on mouse move
@ -6123,10 +6137,17 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
{ {
gestureEvent.pointId[i] = CORE.Input.Touch.pointId[i]; gestureEvent.pointId[i] = CORE.Input.Touch.pointId[i];
gestureEvent.position[i] = CORE.Input.Touch.position[i]; gestureEvent.position[i] = CORE.Input.Touch.position[i];
// Normalize gestureEvent.position[i]
gestureEvent.position[i].x /= (float)GetScreenWidth();
gestureEvent.position[i].y /= (float)GetScreenHeight();
} }
// Gesture data is sent to gestures system for processing // Gesture data is sent to gestures system for processing
ProcessGestureEvent(gestureEvent); ProcessGestureEvent(gestureEvent);
// Reset the pointCount for web, if it was the last Touch End event
if (eventType == EMSCRIPTEN_EVENT_TOUCHEND && CORE.Input.Touch.pointCount == 1) CORE.Input.Touch.pointCount = 0;
#endif #endif
return 1; // The event was consumed by the callback handler return 1; // The event was consumed by the callback handler

View File

@ -3,12 +3,12 @@
* rgestures - Gestures system, gestures processing based on input events (touch/mouse) * rgestures - Gestures system, gestures processing based on input events (touch/mouse)
* *
* CONFIGURATION: * CONFIGURATION:
* #define GESTURES_IMPLEMENTATION * #define RGESTURES_IMPLEMENTATION
* Generates the implementation of the library into the included file. * Generates the implementation of the library into the included file.
* If not defined, the library is in header only mode and can be included in other headers * If not defined, the library is in header only mode and can be included in other headers
* or source files without problems. But only ONE file should hold the implementation. * or source files without problems. But only ONE file should hold the implementation.
* *
* #define GESTURES_STANDALONE * #define RGESTURES_STANDALONE
* If defined, the library can be used as standalone to process gesture events with * If defined, the library can be used as standalone to process gesture events with
* no external dependencies. * no external dependencies.
* *
@ -56,7 +56,7 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
// NOTE: Below types are required for GESTURES_STANDALONE usage // NOTE: Below types are required for standalone usage
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Boolean type // Boolean type
#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800) #if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
@ -73,7 +73,7 @@ typedef struct Vector2 {
} Vector2; } Vector2;
#endif #endif
#if defined(GESTURES_STANDALONE) #if defined(RGESTURES_STANDALONE)
// Gestures type // Gestures type
// NOTE: It could be used as flags to enable only some gestures // NOTE: It could be used as flags to enable only some gestures
typedef enum { typedef enum {
@ -122,12 +122,12 @@ extern "C" { // Prevents name mangling of functions
void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures
void UpdateGestures(void); // Update gestures detected (must be called every frame) void UpdateGestures(void); // Update gestures detected (must be called every frame)
#if defined(GESTURES_STANDALONE) #if defined(RGESTURES_STANDALONE)
void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags
bool IsGestureDetected(int gesture); // Check if a gesture have been detected bool IsGestureDetected(int gesture); // Check if a gesture have been detected
int GetGestureDetected(void); // Get latest detected gesture int GetGestureDetected(void); // Get latest detected gesture
float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds float GetGestureHoldDuration(void); // Get gesture hold time in seconds
Vector2 GetGestureDragVector(void); // Get gesture drag vector Vector2 GetGestureDragVector(void); // Get gesture drag vector
float GetGestureDragAngle(void); // Get gesture drag angle float GetGestureDragAngle(void); // Get gesture drag angle
Vector2 GetGesturePinchVector(void); // Get gesture pinch delta Vector2 GetGesturePinchVector(void); // Get gesture pinch delta
@ -138,17 +138,17 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang
} }
#endif #endif
#endif // GESTURES_H #endif // RGESTURES_H
/*********************************************************************************** /***********************************************************************************
* *
* GESTURES IMPLEMENTATION * RGESTURES IMPLEMENTATION
* *
************************************************************************************/ ************************************************************************************/
#if defined(GESTURES_IMPLEMENTATION) #if defined(RGESTURES_IMPLEMENTATION)
#if defined(GESTURES_STANDALONE) #if defined(RGESTURES_STANDALONE)
#if defined(_WIN32) #if defined(_WIN32)
#if defined(__cplusplus) #if defined(__cplusplus)
extern "C" { // Prevents name mangling of functions extern "C" { // Prevents name mangling of functions
@ -178,11 +178,12 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#define FORCE_TO_SWIPE 0.0005f // Swipe force, measured in normalized screen units/time #define FORCE_TO_SWIPE 0.2f // Swipe force, measured in normalized screen units/time
#define MINIMUM_DRAG 0.015f // Drag minimum force, measured in normalized screen units (0.0f to 1.0f) #define MINIMUM_DRAG 0.015f // Drag minimum force, measured in normalized screen units (0.0f to 1.0f)
#define DRAG_TIMEOUT 0.2f // Drag minimum time for web, measured in seconds
#define MINIMUM_PINCH 0.005f // Pinch minimum force, measured in normalized screen units (0.0f to 1.0f) #define MINIMUM_PINCH 0.005f // Pinch minimum force, measured in normalized screen units (0.0f to 1.0f)
#define TAP_TIMEOUT 300 // Tap minimum time, measured in milliseconds #define TAP_TIMEOUT 0.3f // Tap minimum time, measured in seconds
#define PINCH_TIMEOUT 300 // Pinch minimum time, measured in milliseconds #define PINCH_TIMEOUT 0.3f // Pinch minimum time, measured in seconds
#define DOUBLETAP_RANGE 0.03f // DoubleTap range, measured in normalized screen units (0.0f to 1.0f) #define DOUBLETAP_RANGE 0.03f // DoubleTap range, measured in normalized screen units (0.0f to 1.0f)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -203,11 +204,13 @@ typedef struct {
Vector2 downDragPosition; // Touch drag position Vector2 downDragPosition; // Touch drag position
Vector2 moveDownPositionA; // First touch down position on move Vector2 moveDownPositionA; // First touch down position on move
Vector2 moveDownPositionB; // Second touch down position on move Vector2 moveDownPositionB; // Second touch down position on move
Vector2 previousPositionA; // Previous position A to compare for pinch gestures
Vector2 previousPositionB; // Previous position B to compare for pinch gestures
int tapCounter; // TAP counter (one tap implies TOUCH_ACTION_DOWN and TOUCH_ACTION_UP actions) int tapCounter; // TAP counter (one tap implies TOUCH_ACTION_DOWN and TOUCH_ACTION_UP actions)
} Touch; } Touch;
struct { struct {
bool resetRequired; // HOLD reset to get first touch point again bool resetRequired; // HOLD reset to get first touch point again
double timeDuration; // HOLD duration in milliseconds double timeDuration; // HOLD duration in seconds
} Hold; } Hold;
struct { struct {
Vector2 vector; // DRAG vector (between initial and current position) Vector2 vector; // DRAG vector (between initial and current position)
@ -295,7 +298,8 @@ void ProcessGestureEvent(GestureEvent event)
} }
else if (event.touchAction == TOUCH_ACTION_UP) else if (event.touchAction == TOUCH_ACTION_UP)
{ {
if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.upPosition = event.position[0]; // A swipe can happen while the current gesture is drag, but (specially for web) also hold, so set upPosition for both cases
if (GESTURES.current == GESTURE_DRAG || GESTURES.current == GESTURE_HOLD) GESTURES.Touch.upPosition = event.position[0];
// NOTE: GESTURES.Drag.intensity dependent on the resolution of the screen // NOTE: GESTURES.Drag.intensity dependent on the resolution of the screen
GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
@ -310,9 +314,9 @@ void ProcessGestureEvent(GestureEvent event)
GESTURES.Drag.angle = 360.0f - rgVector2Angle(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); GESTURES.Drag.angle = 360.0f - rgVector2Angle(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
if ((GESTURES.Drag.angle < 30) || (GESTURES.Drag.angle > 330)) GESTURES.current = GESTURE_SWIPE_RIGHT; // Right if ((GESTURES.Drag.angle < 30) || (GESTURES.Drag.angle > 330)) GESTURES.current = GESTURE_SWIPE_RIGHT; // Right
else if ((GESTURES.Drag.angle > 30) && (GESTURES.Drag.angle < 120)) GESTURES.current = GESTURE_SWIPE_UP; // Up else if ((GESTURES.Drag.angle >= 30) && (GESTURES.Drag.angle <= 150)) GESTURES.current = GESTURE_SWIPE_UP; // Up
else if ((GESTURES.Drag.angle > 120) && (GESTURES.Drag.angle < 210)) GESTURES.current = GESTURE_SWIPE_LEFT; // Left else if ((GESTURES.Drag.angle > 150) && (GESTURES.Drag.angle < 210)) GESTURES.current = GESTURE_SWIPE_LEFT; // Left
else if ((GESTURES.Drag.angle > 210) && (GESTURES.Drag.angle < 300)) GESTURES.current = GESTURE_SWIPE_DOWN; // Down else if ((GESTURES.Drag.angle >= 210) && (GESTURES.Drag.angle <= 330)) GESTURES.current = GESTURE_SWIPE_DOWN; // Down
else GESTURES.current = GESTURE_NONE; else GESTURES.current = GESTURE_NONE;
} }
else else
@ -346,7 +350,12 @@ void ProcessGestureEvent(GestureEvent event)
GESTURES.Hold.resetRequired = false; GESTURES.Hold.resetRequired = false;
// Detect GESTURE_DRAG // Detect GESTURE_DRAG
#if defined(PLATFORM_WEB)
// An alternative check to detect gesture drag is necessary since moveDownPositionA on touch for web is always zero, causing the distance calculation to be inaccurate
if ((rgGetCurrentTime() - GESTURES.Touch.eventTime) > DRAG_TIMEOUT)
#else
if (rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_DRAG) if (rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_DRAG)
#endif
{ {
GESTURES.Touch.eventTime = rgGetCurrentTime(); GESTURES.Touch.eventTime = rgGetCurrentTime();
GESTURES.current = GESTURE_DRAG; GESTURES.current = GESTURE_DRAG;
@ -364,6 +373,9 @@ void ProcessGestureEvent(GestureEvent event)
GESTURES.Touch.downPositionA = event.position[0]; GESTURES.Touch.downPositionA = event.position[0];
GESTURES.Touch.downPositionB = event.position[1]; GESTURES.Touch.downPositionB = event.position[1];
GESTURES.Touch.previousPositionA = GESTURES.Touch.downPositionA;
GESTURES.Touch.previousPositionB = GESTURES.Touch.downPositionB;
//GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.downPositionB); //GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.downPositionB);
GESTURES.Pinch.vector.x = GESTURES.Touch.downPositionB.x - GESTURES.Touch.downPositionA.x; GESTURES.Pinch.vector.x = GESTURES.Touch.downPositionB.x - GESTURES.Touch.downPositionA.x;
@ -376,18 +388,15 @@ void ProcessGestureEvent(GestureEvent event)
{ {
GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB);
GESTURES.Touch.downPositionA = GESTURES.Touch.moveDownPositionA;
GESTURES.Touch.downPositionB = GESTURES.Touch.moveDownPositionB;
GESTURES.Touch.moveDownPositionA = event.position[0]; GESTURES.Touch.moveDownPositionA = event.position[0];
GESTURES.Touch.moveDownPositionB = event.position[1]; GESTURES.Touch.moveDownPositionB = event.position[1];
GESTURES.Pinch.vector.x = GESTURES.Touch.moveDownPositionB.x - GESTURES.Touch.moveDownPositionA.x; GESTURES.Pinch.vector.x = GESTURES.Touch.moveDownPositionB.x - GESTURES.Touch.moveDownPositionA.x;
GESTURES.Pinch.vector.y = GESTURES.Touch.moveDownPositionB.y - GESTURES.Touch.moveDownPositionA.y; GESTURES.Pinch.vector.y = GESTURES.Touch.moveDownPositionB.y - GESTURES.Touch.moveDownPositionA.y;
if ((rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_PINCH) || (rgVector2Distance(GESTURES.Touch.downPositionB, GESTURES.Touch.moveDownPositionB) >= MINIMUM_PINCH)) if ((rgVector2Distance(GESTURES.Touch.previousPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_PINCH) || (rgVector2Distance(GESTURES.Touch.previousPositionB, GESTURES.Touch.moveDownPositionB) >= MINIMUM_PINCH))
{ {
if ((rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB) - GESTURES.Pinch.distance) < 0) GESTURES.current = GESTURE_PINCH_IN; if ( rgVector2Distance(GESTURES.Touch.previousPositionA, GESTURES.Touch.previousPositionB) > rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB) ) GESTURES.current = GESTURE_PINCH_IN;
else GESTURES.current = GESTURE_PINCH_OUT; else GESTURES.current = GESTURE_PINCH_OUT;
} }
else else
@ -520,12 +529,12 @@ static float rgVector2Distance(Vector2 v1, Vector2 v2)
return result; return result;
} }
// Time measure returned are milliseconds // Time measure returned are seconds
static double rgGetCurrentTime(void) static double rgGetCurrentTime(void)
{ {
double time = 0; double time = 0;
#if !defined(GESTURES_STANDALONE) #if !defined(RGESTURES_STANDALONE)
time = GetTime(); time = GetTime();
#else #else
#if defined(_WIN32) #if defined(_WIN32)
@ -534,7 +543,7 @@ static double rgGetCurrentTime(void)
QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation! QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation!
QueryPerformanceCounter(&currentTime); QueryPerformanceCounter(&currentTime);
time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds time = (double)currentTime/clockFrequency; // Time in seconds
#endif #endif
#if defined(__linux__) #if defined(__linux__)
@ -543,7 +552,7 @@ static double rgGetCurrentTime(void)
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds
time = ((double)nowTime/1000000.0); // Time in miliseconds time = ((double)nowTime*1e-9); // Time in seconds
#endif #endif
#if defined(__APPLE__) #if defined(__APPLE__)
@ -559,11 +568,11 @@ static double rgGetCurrentTime(void)
mach_port_deallocate(mach_task_self(), cclock); mach_port_deallocate(mach_task_self(), cclock);
unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds
time = ((double)nowTime/1000000.0); // Time in miliseconds time = ((double)nowTime*1e-9); // Time in seconds
#endif #endif
#endif #endif
return time; return time;
} }
#endif // GESTURES_IMPLEMENTATION #endif // RGESTURES_IMPLEMENTATION

View File

@ -80,7 +80,7 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Global Variables Definition // Global Variables Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
Texture2D texShapes = { 1, 1, 1, 1, 7 }; // Texture used on shapes drawing (usually a white pixel) Texture2D texShapes = { 1, 1, 1, 1, 7 }; // Texture used on shapes drawing (white pixel loaded by rlgl)
Rectangle texShapesRec = { 0.0f, 0.0f, 1.0f, 1.0f }; // Texture source rectangle used on shapes drawing Rectangle texShapesRec = { 0.0f, 0.0f, 1.0f, 1.0f }; // Texture source rectangle used on shapes drawing
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -97,8 +97,19 @@ static float EaseCubicInOut(float t, float b, float c, float d); // Cubic eas
// defining a font char white rectangle would allow drawing everything in a single draw call // defining a font char white rectangle would allow drawing everything in a single draw call
void SetShapesTexture(Texture2D texture, Rectangle source) void SetShapesTexture(Texture2D texture, Rectangle source)
{ {
// Reset texture to default pixel if required
// WARNING: Shapes texture should be probably better validated,
// it can break the rendering of all shapes if missused
if ((texture.id == 0) || (source.width == 0) || (source.height == 0))
{
texShapes = (Texture2D){ 1, 1, 1, 1, 7 };
texShapesRec = (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f };
}
else
{
texShapes = texture; texShapes = texture;
texShapesRec = source; texShapesRec = source;
}
} }
// Draw a pixel // Draw a pixel
@ -382,14 +393,14 @@ void DrawCircleSector(Vector2 center, float radius, float startAngle, float endA
rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x, center.y); rlVertex2f(center.x, center.y);
rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength*2))*radius, center.y + sinf(DEG2RAD*(angle + stepLength*2))*radius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength*2))*radius, center.y + cosf(DEG2RAD*(angle + stepLength*2))*radius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
angle += (stepLength*2); angle += (stepLength*2);
} }
@ -402,11 +413,11 @@ void DrawCircleSector(Vector2 center, float radius, float startAngle, float endA
rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x, center.y); rlVertex2f(center.x, center.y);
rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x, center.y); rlVertex2f(center.x, center.y);
@ -421,8 +432,8 @@ void DrawCircleSector(Vector2 center, float radius, float startAngle, float endA
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x, center.y); rlVertex2f(center.x, center.y);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
angle += stepLength; angle += stepLength;
} }
@ -464,15 +475,15 @@ void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x, center.y); rlVertex2f(center.x, center.y);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
} }
for (int i = 0; i < segments; i++) for (int i = 0; i < segments; i++)
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
angle += stepLength; angle += stepLength;
} }
@ -481,7 +492,7 @@ void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x, center.y); rlVertex2f(center.x, center.y);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
} }
rlEnd(); rlEnd();
} }
@ -496,9 +507,9 @@ void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Co
rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlColor4ub(color1.r, color1.g, color1.b, color1.a);
rlVertex2f((float)centerX, (float)centerY); rlVertex2f((float)centerX, (float)centerY);
rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlColor4ub(color2.r, color2.g, color2.b, color2.a);
rlVertex2f((float)centerX + sinf(DEG2RAD*i)*radius, (float)centerY + cosf(DEG2RAD*i)*radius); rlVertex2f((float)centerX + cosf(DEG2RAD*(i + 10))*radius, (float)centerY + sinf(DEG2RAD*(i + 10))*radius);
rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlColor4ub(color2.r, color2.g, color2.b, color2.a);
rlVertex2f((float)centerX + sinf(DEG2RAD*(i + 10))*radius, (float)centerY + cosf(DEG2RAD*(i + 10))*radius); rlVertex2f((float)centerX + cosf(DEG2RAD*i)*radius, (float)centerY + sinf(DEG2RAD*i)*radius);
} }
rlEnd(); rlEnd();
} }
@ -519,8 +530,8 @@ void DrawCircleLines(int centerX, int centerY, float radius, Color color)
// NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360) // NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360)
for (int i = 0; i < 360; i += 10) for (int i = 0; i < 360; i += 10)
{ {
rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius); rlVertex2f(centerX + cosf(DEG2RAD*i)*radius, centerY + sinf(DEG2RAD*i)*radius);
rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius); rlVertex2f(centerX + cosf(DEG2RAD*(i + 10))*radius, centerY + sinf(DEG2RAD*(i + 10))*radius);
} }
rlEnd(); rlEnd();
} }
@ -533,8 +544,8 @@ void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color c
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f((float)centerX, (float)centerY); rlVertex2f((float)centerX, (float)centerY);
rlVertex2f((float)centerX + sinf(DEG2RAD*i)*radiusH, (float)centerY + cosf(DEG2RAD*i)*radiusV); rlVertex2f((float)centerX + cosf(DEG2RAD*(i + 10))*radiusH, (float)centerY + sinf(DEG2RAD*(i + 10))*radiusV);
rlVertex2f((float)centerX + sinf(DEG2RAD*(i + 10))*radiusH, (float)centerY + cosf(DEG2RAD*(i + 10))*radiusV); rlVertex2f((float)centerX + cosf(DEG2RAD*i)*radiusH, (float)centerY + sinf(DEG2RAD*i)*radiusV);
} }
rlEnd(); rlEnd();
} }
@ -546,8 +557,8 @@ void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Co
for (int i = 0; i < 360; i += 10) for (int i = 0; i < 360; i += 10)
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(centerX + sinf(DEG2RAD*i)*radiusH, centerY + cosf(DEG2RAD*i)*radiusV); rlVertex2f(centerX + cosf(DEG2RAD*(i + 10))*radiusH, centerY + sinf(DEG2RAD*(i + 10))*radiusV);
rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radiusH, centerY + cosf(DEG2RAD*(i + 10))*radiusV); rlVertex2f(centerX + cosf(DEG2RAD*i)*radiusH, centerY + sinf(DEG2RAD*i)*radiusV);
} }
rlEnd(); rlEnd();
} }
@ -605,17 +616,17 @@ void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startA
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
angle += stepLength; angle += stepLength;
} }
@ -628,13 +639,13 @@ void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startA
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
angle += stepLength; angle += stepLength;
} }
@ -691,19 +702,19 @@ void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float s
if (showCapLines) if (showCapLines)
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
} }
for (int i = 0; i < segments; i++) for (int i = 0; i < segments; i++)
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
angle += stepLength; angle += stepLength;
} }
@ -711,8 +722,8 @@ void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float s
if (showCapLines) if (showCapLines)
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
} }
rlEnd(); rlEnd();
} }
@ -971,7 +982,7 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
}; };
const Vector2 centers[4] = { point[8], point[9], point[10], point[11] }; const Vector2 centers[4] = { point[8], point[9], point[10], point[11] };
const float angles[4] = { 180.0f, 90.0f, 0.0f, 270.0f }; const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };
#if defined(SUPPORT_QUADS_DRAW_MODE) #if defined(SUPPORT_QUADS_DRAW_MODE)
rlSetTexture(texShapes.id); rlSetTexture(texShapes.id);
@ -989,12 +1000,16 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x, center.y); rlVertex2f(center.x, center.y);
rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength*2))*radius, center.y + cosf(DEG2RAD*(angle + stepLength*2))*radius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength*2))*radius, center.y + sinf(DEG2RAD*(angle + stepLength*2))*radius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
angle += (stepLength*2); angle += (stepLength*2);
} }
@ -1004,10 +1019,13 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x, center.y); rlVertex2f(center.x, center.y);
rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x, center.y); rlVertex2f(center.x, center.y);
} }
@ -1082,8 +1100,8 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x, center.y); rlVertex2f(center.x, center.y);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius);
angle += stepLength; angle += stepLength;
} }
} }
@ -1197,7 +1215,7 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, flo
{(float)(rec.x + rec.width) - innerRadius, (float)(rec.y + rec.height) - innerRadius}, {(float)rec.x + innerRadius, (float)(rec.y + rec.height) - innerRadius} // P18, P19 {(float)(rec.x + rec.width) - innerRadius, (float)(rec.y + rec.height) - innerRadius}, {(float)rec.x + innerRadius, (float)(rec.y + rec.height) - innerRadius} // P18, P19
}; };
const float angles[4] = { 180.0f, 90.0f, 0.0f, 270.0f }; const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };
if (lineThick > 1) if (lineThick > 1)
{ {
@ -1214,14 +1232,18 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, flo
for (int i = 0; i < segments; i++) for (int i = 0; i < segments; i++)
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
angle += stepLength; angle += stepLength;
} }
@ -1286,13 +1308,13 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, flo
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
angle += stepLength; angle += stepLength;
} }
@ -1350,8 +1372,8 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, flo
for (int i = 0; i < segments; i++) for (int i = 0; i < segments; i++)
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius); rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius); rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
angle += stepLength; angle += stepLength;
} }
} }
@ -1481,7 +1503,8 @@ void DrawTriangleStrip(Vector2 *points, int pointCount, Color color)
void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color) void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color)
{ {
if (sides < 3) sides = 3; if (sides < 3) sides = 3;
float centralAngle = rotation; float centralAngle = rotation*DEG2RAD;
float angleStep = 360.0f/(float)sides*DEG2RAD;
#if defined(SUPPORT_QUADS_DRAW_MODE) #if defined(SUPPORT_QUADS_DRAW_MODE)
rlSetTexture(texShapes.id); rlSetTexture(texShapes.id);
@ -1490,19 +1513,21 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col
for (int i = 0; i < sides; i++) for (int i = 0; i < sides; i++)
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
float nextAngle = centralAngle + angleStep;
rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height); rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x, center.y); rlVertex2f(center.x, center.y);
rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius); rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius); rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
centralAngle += 360.0f/(float)sides; centralAngle = nextAngle;
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius);
} }
rlEnd(); rlEnd();
rlSetTexture(0); rlSetTexture(0);
@ -1513,10 +1538,10 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x, center.y); rlVertex2f(center.x, center.y);
rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius); rlVertex2f(center.x + cosf(centralAngle + angleStep)*radius, center.y + sinf(centralAngle + angleStep)*radius);
rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
centralAngle += 360.0f/(float)sides; centralAngle += angleStep;
rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius);
} }
rlEnd(); rlEnd();
#endif #endif
@ -1526,16 +1551,18 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col
void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color) void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color)
{ {
if (sides < 3) sides = 3; if (sides < 3) sides = 3;
float centralAngle = rotation; float centralAngle = rotation*DEG2RAD;
float angleStep = 360.0f/(float)sides*DEG2RAD;
rlBegin(RL_LINES); rlBegin(RL_LINES);
for (int i = 0; i < sides; i++) for (int i = 0; i < sides; i++)
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius); rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
centralAngle += 360.0f/(float)sides; rlVertex2f(center.x + cosf(centralAngle + angleStep)*radius, center.y + sinf(centralAngle + angleStep)*radius);
rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius);
centralAngle += angleStep;
} }
rlEnd(); rlEnd();
} }
@ -1543,8 +1570,8 @@ void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Colo
void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color) void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color)
{ {
if (sides < 3) sides = 3; if (sides < 3) sides = 3;
float centralAngle = rotation; float centralAngle = rotation*DEG2RAD;
float exteriorAngle = 360.0f/(float)sides; float exteriorAngle = 360.0f/(float)sides*DEG2RAD;
float innerRadius = radius - (lineThick*cosf(DEG2RAD*exteriorAngle/2.0f)); float innerRadius = radius - (lineThick*cosf(DEG2RAD*exteriorAngle/2.0f));
#if defined(SUPPORT_QUADS_DRAW_MODE) #if defined(SUPPORT_QUADS_DRAW_MODE)
@ -1554,19 +1581,21 @@ void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, fl
for (int i = 0; i < sides; i++) for (int i = 0; i < sides; i++)
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
float nextAngle = centralAngle + exteriorAngle;
rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*innerRadius, center.y + cosf(DEG2RAD*centralAngle)*innerRadius);
rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); rlTexCoord2f(texShapesRec.x/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius); rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
centralAngle += exteriorAngle; rlTexCoord2f(texShapesRec.x/texShapes.width, texShapesRec.y/texShapes.height);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height); rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height); rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, (texShapesRec.y + texShapesRec.height)/texShapes.height);
rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*innerRadius, center.y + cosf(DEG2RAD*centralAngle)*innerRadius); rlVertex2f(center.x + cosf(nextAngle)*innerRadius, center.y + sinf(nextAngle)*innerRadius);
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
centralAngle = nextAngle;
} }
rlEnd(); rlEnd();
rlSetTexture(0); rlSetTexture(0);
@ -1577,13 +1606,13 @@ void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, fl
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
float nextAngle = centralAngle + exteriorAngle; float nextAngle = centralAngle + exteriorAngle;
rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*radius, center.y + cosf(DEG2RAD*centralAngle)*radius); rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*innerRadius, center.y + cosf(DEG2RAD*centralAngle)*innerRadius); rlVertex2f(center.x + cosf(centralAngle)*radius, center.y + sinf(centralAngle)*radius);
rlVertex2f(center.x + sinf(DEG2RAD*nextAngle)*radius, center.y + cosf(DEG2RAD*nextAngle)*radius); rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*centralAngle)*innerRadius, center.y + cosf(DEG2RAD*centralAngle)*innerRadius); rlVertex2f(center.x + cosf(centralAngle)*innerRadius, center.y + sinf(centralAngle)*innerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*nextAngle)*radius, center.y + cosf(DEG2RAD*nextAngle)*radius); rlVertex2f(center.x + cosf(nextAngle)*innerRadius, center.y + sinf(nextAngle)*innerRadius);
rlVertex2f(center.x + sinf(DEG2RAD*nextAngle)*innerRadius, center.y + cosf(DEG2RAD*nextAngle)*innerRadius); rlVertex2f(center.x + cosf(nextAngle)*radius, center.y + sinf(nextAngle)*radius);
centralAngle = nextAngle; centralAngle = nextAngle;
} }

View File

@ -6,14 +6,19 @@
* #define SUPPORT_MODULE_RTEXT * #define SUPPORT_MODULE_RTEXT
* rtext module is included in the build * rtext module is included in the build
* *
* #define SUPPORT_DEFAULT_FONT
* Load default raylib font on initialization to be used by DrawText() and MeasureText().
* If no default font loaded, DrawTextEx() and MeasureTextEx() are required.
*
* #define SUPPORT_FILEFORMAT_FNT * #define SUPPORT_FILEFORMAT_FNT
* #define SUPPORT_FILEFORMAT_TTF * #define SUPPORT_FILEFORMAT_TTF
* Selected desired fileformats to be supported for loading. Some of those formats are * Selected desired fileformats to be supported for loading. Some of those formats are
* supported by default, to remove support, just comment unrequired #define in this module * supported by default, to remove support, just comment unrequired #define in this module
* *
* #define SUPPORT_DEFAULT_FONT * #define SUPPORT_FONT_ATLAS_WHITE_REC
* Load default raylib font on initialization to be used by DrawText() and MeasureText(). * On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle
* If no default font loaded, DrawTextEx() and MeasureTextEx() are required. * at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow
* drawing text and shapes with a single draw call [SetShapesTexture()].
* *
* #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH * #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
* TextSplit() function static buffer max size * TextSplit() function static buffer max size
@ -113,6 +118,7 @@ static Font defaultFont = { 0 };
#if defined(SUPPORT_FILEFORMAT_FNT) #if defined(SUPPORT_FILEFORMAT_FNT)
static Font LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) static Font LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file)
#endif #endif
static int textLineSpacing = 15; // Text vertical line spacing in pixels
#if defined(SUPPORT_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
extern void LoadFontDefault(void); extern void LoadFontDefault(void);
@ -123,7 +129,6 @@ extern void UnloadFontDefault(void);
// Module Functions Definition // Module Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(SUPPORT_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
// Load raylib default font // Load raylib default font
extern void LoadFontDefault(void) extern void LoadFontDefault(void)
{ {
@ -699,9 +704,11 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int glyphC
for (int i = 0; i < glyphCount; i++) for (int i = 0; i < glyphCount; i++)
{ {
if (chars[i].image.width > maxGlyphWidth) maxGlyphWidth = chars[i].image.width; if (chars[i].image.width > maxGlyphWidth) maxGlyphWidth = chars[i].image.width;
totalWidth += chars[i].image.width + 2*padding; totalWidth += chars[i].image.width + 4*padding;
} }
//#define SUPPORT_FONT_ATLAS_SIZE_CONSERVATIVE
#if defined(SUPPORT_FONT_ATLAS_SIZE_CONSERVATIVE)
int rowCount = 0; int rowCount = 0;
int imageSize = 64; // Define minimum starting value to avoid unnecessary calculation steps for very small images int imageSize = 64; // Define minimum starting value to avoid unnecessary calculation steps for very small images
@ -714,6 +721,24 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int glyphC
atlas.width = imageSize; // Atlas bitmap width atlas.width = imageSize; // Atlas bitmap width
atlas.height = imageSize; // Atlas bitmap height atlas.height = imageSize; // Atlas bitmap height
#else
// No need for a so-conservative atlas generation
float totalArea = totalWidth*fontSize*1.2f;
float imageMinSize = sqrtf(totalArea);
int imageSize = (int)powf(2, ceilf(logf(imageMinSize)/logf(2)));
if (totalArea < ((imageSize*imageSize)/2))
{
atlas.width = imageSize; // Atlas bitmap width
atlas.height = imageSize/2; // Atlas bitmap height
}
else
{
atlas.width = imageSize; // Atlas bitmap width
atlas.height = imageSize; // Atlas bitmap height
}
#endif
atlas.data = (unsigned char *)RL_CALLOC(1, atlas.width*atlas.height); // Create a bitmap to store characters (8 bpp) atlas.data = (unsigned char *)RL_CALLOC(1, atlas.width*atlas.height); // Create a bitmap to store characters (8 bpp)
atlas.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; atlas.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
atlas.mipmaps = 1; atlas.mipmaps = 1;
@ -819,6 +844,19 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int glyphC
RL_FREE(context); RL_FREE(context);
} }
#if defined(SUPPORT_FONT_ATLAS_WHITE_REC)
// Add a 3x3 white rectangle at the bottom-right corner of the generated atlas,
// useful to use as the white texture to draw shapes with raylib, using this rectangle
// shapes and text can be backed into a single draw call: SetShapesTexture()
for (int i = 0, k = atlas.width*atlas.height - 1; i < 3; i++)
{
((unsigned char *)atlas.data)[k - 0] = 255;
((unsigned char *)atlas.data)[k - 1] = 255;
((unsigned char *)atlas.data)[k - 2] = 255;
k -= atlas.width;
}
#endif
// Convert image data from GRAYSCALE to GRAY_ALPHA // Convert image data from GRAYSCALE to GRAY_ALPHA
unsigned char *dataGrayAlpha = (unsigned char *)RL_MALLOC(atlas.width*atlas.height*sizeof(unsigned char)*2); // Two channels unsigned char *dataGrayAlpha = (unsigned char *)RL_MALLOC(atlas.width*atlas.height*sizeof(unsigned char)*2); // Two channels
@ -1071,9 +1109,8 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
if (codepoint == '\n') if (codepoint == '\n')
{ {
// NOTE: Fixed line spacing of 1.5 line-height // NOTE: Line spacing is a global variable, use SetTextLineSpacing() to setup
// TODO: Support custom line spacing defined by user textOffsetY += textLineSpacing;
textOffsetY += (int)((font.baseSize + font.baseSize/2.0f)*scaleFactor);
textOffsetX = 0.0f; textOffsetX = 0.0f;
} }
else else
@ -1143,9 +1180,8 @@ void DrawTextCodepoints(Font font, const int *codepoints, int count, Vector2 pos
if (codepoints[i] == '\n') if (codepoints[i] == '\n')
{ {
// NOTE: Fixed line spacing of 1.5 line-height // NOTE: Line spacing is a global variable, use SetTextLineSpacing() to setup
// TODO: Support custom line spacing defined by user textOffsetY += textLineSpacing;
textOffsetY += (int)((font.baseSize + font.baseSize/2.0f)*scaleFactor);
textOffsetX = 0.0f; textOffsetX = 0.0f;
} }
else else
@ -1161,6 +1197,12 @@ void DrawTextCodepoints(Font font, const int *codepoints, int count, Vector2 pos
} }
} }
// Set vertical line spacing when drawing with line-breaks
void SetTextLineSpacing(int spacing)
{
textLineSpacing = spacing;
}
// Measure string width for default font // Measure string width for default font
int MeasureText(const char *text, int fontSize) int MeasureText(const char *text, int fontSize)
{ {
@ -1219,7 +1261,9 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
if (tempTextWidth < textWidth) tempTextWidth = textWidth; if (tempTextWidth < textWidth) tempTextWidth = textWidth;
byteCounter = 0; byteCounter = 0;
textWidth = 0; textWidth = 0;
textHeight += ((float)font.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines
// NOTE: Line spacing is a global variable, use SetTextLineSpacing() to setup
textHeight += (float)textLineSpacing;
} }
if (tempByteCounter < byteCounter) tempByteCounter = byteCounter; if (tempByteCounter < byteCounter) tempByteCounter = byteCounter;
@ -1227,7 +1271,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
if (tempTextWidth < textWidth) tempTextWidth = textWidth; if (tempTextWidth < textWidth) tempTextWidth = textWidth;
textSize.x = tempTextWidth*scaleFactor + (float)((tempByteCounter - 1)*spacing); // Adds chars spacing to measure textSize.x = tempTextWidth*scaleFactor + (float)((tempByteCounter - 1)*spacing);
textSize.y = textHeight*scaleFactor; textSize.y = textHeight*scaleFactor;
return textSize; return textSize;
@ -1574,7 +1618,8 @@ int TextFindIndex(const char *text, const char *find)
} }
// Get upper case version of provided string // Get upper case version of provided string
// REQUIRES: toupper() // WARNING: Limited functionality, only basic characters set
// TODO: Support UTF-8 diacritics to upper-case, check codepoints
const char *TextToUpper(const char *text) const char *TextToUpper(const char *text)
{ {
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
@ -1582,17 +1627,10 @@ const char *TextToUpper(const char *text)
if (text != NULL) if (text != NULL)
{ {
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) for (int i = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[i] != '\0'); i++)
{ {
if (text[i] != '\0') if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32;
{ else buffer[i] = text[i];
buffer[i] = (char)toupper(text[i]);
//if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32;
// TODO: Support UTF-8 diacritics to upper-case
//if ((text[i] >= 'à') && (text[i] <= 'ý')) buffer[i] = text[i] - 32;
}
else { buffer[i] = '\0'; break; }
} }
} }
@ -1600,7 +1638,7 @@ const char *TextToUpper(const char *text)
} }
// Get lower case version of provided string // Get lower case version of provided string
// REQUIRES: tolower() // WARNING: Limited functionality, only basic characters set
const char *TextToLower(const char *text) const char *TextToLower(const char *text)
{ {
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
@ -1608,14 +1646,10 @@ const char *TextToLower(const char *text)
if (text != NULL) if (text != NULL)
{ {
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) for (int i = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[i] != '\0'); i++)
{ {
if (text[i] != '\0') if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32;
{ else buffer[i] = text[i];
buffer[i] = (char)tolower(text[i]);
//if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32;
}
else { buffer[i] = '\0'; break; }
} }
} }
@ -1623,7 +1657,7 @@ const char *TextToLower(const char *text)
} }
// Get Pascal case notation version of provided string // Get Pascal case notation version of provided string
// REQUIRES: toupper() // WARNING: Limited functionality, only basic characters set
const char *TextToPascal(const char *text) const char *TextToPascal(const char *text)
{ {
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
@ -1631,21 +1665,19 @@ const char *TextToPascal(const char *text)
if (text != NULL) if (text != NULL)
{ {
buffer[0] = (char)toupper(text[0]); // Upper case first character
if ((text[0] >= 'a') && (text[0] <= 'z')) buffer[0] = text[0] - 32;
for (int i = 1, j = 1; i < MAX_TEXT_BUFFER_LENGTH; i++, j++) // Check for next separator to upper case another character
{ for (int i = 1, j = 1; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++, j++)
if (text[j] != '\0')
{ {
if (text[j] != '_') buffer[i] = text[j]; if (text[j] != '_') buffer[i] = text[j];
else else
{ {
j++; j++;
buffer[i] = (char)toupper(text[j]); if ((text[j] >= 'a') && (text[j] <= 'z')) buffer[i] = text[j] - 32;
} }
} }
else { buffer[i] = '\0'; break; }
}
} }
return buffer; return buffer;

View File

@ -3290,8 +3290,7 @@ void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSiz
if (GetFontDefault().texture.id == 0) LoadFontDefault(); if (GetFontDefault().texture.id == 0) LoadFontDefault();
Vector2 position = { (float)posX, (float)posY }; Vector2 position = { (float)posX, (float)posY };
// NOTE: For default font, spacing is set to desired font size / default font size (10) ImageDrawTextEx(dst, GetFontDefault(), text, position, (float)fontSize, 1.0f, color); // WARNING: Module required: rtext
ImageDrawTextEx(dst, GetFontDefault(), text, position, (float)fontSize, (float)fontSize/10, color); // WARNING: Module required: rtext
#else #else
TRACELOG(LOG_WARNING, "IMAGE: ImageDrawText() requires module: rtext"); TRACELOG(LOG_WARNING, "IMAGE: ImageDrawText() requires module: rtext");
#endif #endif