Compare commits

...

27 Commits

Author SHA1 Message Date
Serhii Zasenko
f51204821a
Add vibration test button to core_input_gamepad (#5362) 2025-11-18 21:27:50 +01:00
Ray
a24e65d8e1
Update examples_testing_windows.md 2025-11-18 21:26:54 +01:00
Ray
f75682f5c9 Merge branch 'master' of https://github.com/raysan5/raylib 2025-11-18 21:26:33 +01:00
Ray
57e22d5fa0 Update rtext.c 2025-11-18 21:26:26 +01:00
Ray
1b6303b900
Update examples_testing_windows.md 2025-11-18 21:20:05 +01:00
Ray
83a167ca3f Update text_inline_styling.c 2025-11-18 21:19:55 +01:00
Ray
48496e2307 Update core_input_actions.c 2025-11-18 21:18:32 +01:00
Ray
e6ef99275a Update shapes_digital_clock.c 2025-11-18 21:14:48 +01:00
Ray
c7c6aaf156 Update examples_testing_windows.md 2025-11-18 21:12:25 +01:00
Ray
06958c91d0 Merge branch 'master' of https://github.com/raysan5/raylib 2025-11-18 20:59:55 +01:00
Ray
46ca641ec5 Update raygui to avoid warnings 2025-11-18 20:59:48 +01:00
Ray
f3393b8fd8 Update core_clipboard_text.c 2025-11-18 20:59:38 +01:00
Ray
8455f9d088 Update rexm.c 2025-11-18 20:59:33 +01:00
Ray
95d58ed988
Update examples_testing_windows.md 2025-11-18 20:52:05 +01:00
Ray
5da90172ac Update examples_testing_windows.md 2025-11-18 20:49:21 +01:00
Ray
6f4f4cc508 Update rexm.c 2025-11-18 20:44:23 +01:00
Ray
e062e3835e REVIEWED: examples: Several minor issues 2025-11-18 20:43:58 +01:00
Ray
dcc9e96148 Update rexm.c 2025-11-18 20:18:17 +01:00
Ray
6993bc7337 Update examples_testing_windows.md 2025-11-18 19:51:34 +01:00
Ray
a4a6812d68 REXM: REVIEWED: Testing report generation 2025-11-18 19:50:45 +01:00
Ray
9efe127f5d Update shapes_lines_drawing.c 2025-11-18 19:50:07 +01:00
Robin ❤️
4caba49658
[examples] Added: shapes_rlgl_color_wheel example (#5355)
* [examples] Added: `shapes_rlgl_triangle` example

* correct name

* formatting

* Revert "formatting"

This reverts commit f1d246a6482afb438d6371c469558729cbabf466.

* Revert "correct name"

This reverts commit 974985ed495d41323bd879e5ebcc21d80876db37.

* Revert "[examples] Added: `shapes_rlgl_triangle` example"

This reverts commit d053b9afa0a6f1d2c991f336db22397bb581742d.

* [examples] Added: `shapes_rlgl_color_wheel` example

* clarify color variable

* formatting

* formatting

* formatting

* formatting

* reduce redundancy

* moved color updating code to update
2025-11-18 16:31:43 +01:00
Ray
86e00bde65 Update rcore_desktop_sdl.c 2025-11-18 16:30:48 +01:00
Ray
95a8977e33 REXM: FIX: Web log redirect and download 2025-11-18 16:28:10 +01:00
Ray
f531ee2d8f Update rexm.c 2025-11-18 16:19:43 +01:00
MikiZX1
b18f547d8f
Update rcore_desktop_sdl.c, fix crash when strncpy tries to copy using NULL pointer (#5359)
When SDL_GameControllerNameForIndex returns null, the app crashes. This was addressed earlier in PR#4859 though the fix submitted on PR #4859 was only fixing the crashing and not addressing the root cause.
2025-11-18 16:19:07 +01:00
Serhii Zasenko
be9a24e68c
Fix controller not available right after win init (#5358)
- Fix IsGamepadAvailable() returns false for an available controller immediately after window initialization
2025-11-18 16:17:58 +01:00
20 changed files with 1130 additions and 583 deletions

View File

@ -41,7 +41,7 @@ int main(void)
"Copy and paste me!" "Copy and paste me!"
}; };
char *clipboardText = NULL; const char *clipboardText = NULL;
char inputBuffer[256] = "Hello from raylib!"; // Random initial string char inputBuffer[256] = "Hello from raylib!"; // Random initial string
// UI required variables // UI required variables
@ -144,7 +144,7 @@ int main(void)
GuiSetState(STATE_DISABLED); GuiSetState(STATE_DISABLED);
GuiLabel((Rectangle){ 50, 260, 700, 40 }, "Clipboard current text data:"); GuiLabel((Rectangle){ 50, 260, 700, 40 }, "Clipboard current text data:");
GuiSetStyle(TEXTBOX, TEXT_READONLY, 1); GuiSetStyle(TEXTBOX, TEXT_READONLY, 1);
GuiTextBox((Rectangle){ 50, 300, 700, 40 }, clipboardText, 256, false); GuiTextBox((Rectangle){ 50, 300, 700, 40 }, (char *)clipboardText, 256, false);
GuiSetStyle(TEXTBOX, TEXT_READONLY, 0); GuiSetStyle(TEXTBOX, TEXT_READONLY, 0);
GuiLabel((Rectangle){ 50, 360, 700, 40 }, "Try copying text from other applications and pasting here!"); GuiLabel((Rectangle){ 50, 360, 700, 40 }, "Try copying text from other applications and pasting here!");
GuiSetState(STATE_NORMAL); GuiSetState(STATE_NORMAL);

View File

@ -71,6 +71,7 @@ int main(void)
// Set default actions // Set default actions
char actionSet = 0; char actionSet = 0;
SetActionsDefault(); SetActionsDefault();
bool releaseAction = false;
Vector2 position = (Vector2){ 400.0f, 200.0f }; Vector2 position = (Vector2){ 400.0f, 200.0f };
Vector2 size = (Vector2){ 40.0f, 40.0f }; Vector2 size = (Vector2){ 40.0f, 40.0f };
@ -83,7 +84,8 @@ int main(void)
{ {
// Update // Update
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
gamepadIndex = 0; // set this to gamepad being checked gamepadIndex = 0; // Set gamepad being checked
if (IsActionDown(ACTION_UP)) position.y -= 2; if (IsActionDown(ACTION_UP)) position.y -= 2;
if (IsActionDown(ACTION_DOWN)) position.y += 2; if (IsActionDown(ACTION_DOWN)) position.y += 2;
if (IsActionDown(ACTION_LEFT)) position.x -= 2; if (IsActionDown(ACTION_LEFT)) position.x -= 2;
@ -93,6 +95,10 @@ int main(void)
position.x = (screenWidth-size.x)/2; position.x = (screenWidth-size.x)/2;
position.y = (screenHeight-size.y)/2; position.y = (screenHeight-size.y)/2;
} }
// Register release action for one frame
releaseAction = false;
if (IsActionReleased(ACTION_FIRE)) releaseAction = true;
// Switch control scheme by pressing TAB // Switch control scheme by pressing TAB
if (IsKeyPressed(KEY_TAB)) if (IsKeyPressed(KEY_TAB))
@ -109,7 +115,7 @@ int main(void)
ClearBackground(GRAY); ClearBackground(GRAY);
DrawRectangleV(position, size, RED); DrawRectangleV(position, size, releaseAction? BLUE : RED);
DrawText((actionSet == 0)? "Current input set: WASD (default)" : "Current input set: Cursor", 10, 10, 20, WHITE); DrawText((actionSet == 0)? "Current input set: WASD (default)" : "Current input set: Cursor", 10, 10, 20, WHITE);
DrawText("Use TAB key to toggles Actions keyset", 10, 50, 20, GREEN); DrawText("Use TAB key to toggles Actions keyset", 10, 50, 20, GREEN);

View File

@ -72,6 +72,8 @@ int main(void)
if (IsKeyPressed(KEY_LEFT) && gamepad > 0) gamepad--; if (IsKeyPressed(KEY_LEFT) && gamepad > 0) gamepad--;
if (IsKeyPressed(KEY_RIGHT)) gamepad++; if (IsKeyPressed(KEY_RIGHT)) gamepad++;
Vector2 mousePosition = GetMousePosition();
bool mousePressed = IsMouseButtonPressed(MOUSE_BUTTON_LEFT);
if (IsGamepadAvailable(gamepad)) if (IsGamepadAvailable(gamepad))
{ {
@ -262,6 +264,14 @@ int main(void)
DrawText(TextFormat("AXIS %i: %.02f", i, GetGamepadAxisMovement(gamepad, i)), 20, 70 + 20*i, 10, DARKGRAY); DrawText(TextFormat("AXIS %i: %.02f", i, GetGamepadAxisMovement(gamepad, i)), 20, 70 + 20*i, 10, DARKGRAY);
} }
Rectangle vibrateButton = (Rectangle){10, 70 + 20*GetGamepadAxisCount(gamepad) + 20, 75, 10};
if (mousePressed && CheckCollisionPointRec(mousePosition, vibrateButton)){
SetGamepadVibration(gamepad, 1.0, 1.0, 1.0);
}
DrawRectangleRec(vibrateButton, SKYBLUE);
DrawText("VIBRATE", vibrateButton.x + 14, vibrateButton.y + 1, 10, DARKGRAY);
if (GetGamepadButtonPressed() != GAMEPAD_BUTTON_UNKNOWN) DrawText(TextFormat("DETECTED BUTTON: %i", GetGamepadButtonPressed()), 10, 430, 10, RED); if (GetGamepadButtonPressed() != GAMEPAD_BUTTON_UNKNOWN) DrawText(TextFormat("DETECTED BUTTON: %i", GetGamepadButtonPressed()), 10, 430, 10, RED);
else DrawText("DETECTED BUTTON: NONE", 10, 430, 10, GRAY); else DrawText("DETECTED BUTTON: NONE", 10, 430, 10, GRAY);
} }

View File

@ -3026,9 +3026,9 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int
// NOTE: Requires static variables: frameCounter // NOTE: Requires static variables: frameCounter
int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode)
{ {
//#if !defined(RAYGUI_VALUEBOX_MAX_CHARS) #if !defined(RAYGUI_VALUEBOX_MAX_CHARS)
#define RAYGUI_VALUEBOX_MAX_CHARS 32 #define RAYGUI_VALUEBOX_MAX_CHARS 32
//#endif #endif
int result = 0; int result = 0;
GuiState state = guiState; GuiState state = guiState;
@ -3087,7 +3087,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
} }
// Add new digit to text value // Add new digit to text value
if ((keyCount < RAYGUI_VALUEBOX_MAX_CHARS) && (GuiGetTextWidth(textValue) < bounds.width)) if ((keyCount >= 0) && (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) && (GuiGetTextWidth(textValue) < bounds.width))
{ {
int key = GetCharPressed(); int key = GetCharPressed();

View File

@ -67,7 +67,7 @@ int main(void)
models[i] = LoadModel(voxFileNames[i]); models[i] = LoadModel(voxFileNames[i]);
double t1 = GetTime()*1000.0; double t1 = GetTime()*1000.0;
TraceLog(LOG_WARNING, TextFormat("[%s] File loaded in %.3f ms", voxFileNames[i], t1 - t0)); TraceLog(LOG_INFO, TextFormat("[%s] Model file loaded in %.3f ms", voxFileNames[i], t1 - t0));
// Compute model translation matrix to center model on draw position (0, 0 , 0) // Compute model translation matrix to center model on draw position (0, 0 , 0)
BoundingBox bb = GetModelBoundingBox(models[i]); BoundingBox bb = GetModelBoundingBox(models[i]);
@ -80,6 +80,8 @@ int main(void)
} }
int currentModel = 0; int currentModel = 0;
Vector3 modelpos = { 0 };
Vector3 camerarot = { 0 };
// Load voxel shader // Load voxel shader
Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/voxel_lighting.vs", GLSL_VERSION), Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/voxel_lighting.vs", GLSL_VERSION),
@ -98,11 +100,7 @@ int main(void)
// Assign out lighting shader to model // Assign out lighting shader to model
for (int i = 0; i < MAX_VOX_FILES; i++) for (int i = 0; i < MAX_VOX_FILES; i++)
{ {
Model m = models[i]; for (int j = 0; j < models[i].materialCount; j++) models[i].materials[j].shader = shader;
for (int j = 0; j < m.materialCount; j++)
{
m.materials[j].shader = shader;
}
} }
// Create lights // Create lights
@ -112,12 +110,8 @@ int main(void)
lights[2] = CreateLight(LIGHT_POINT, (Vector3) { -20, 20, 20 }, Vector3Zero(), GRAY, shader); lights[2] = CreateLight(LIGHT_POINT, (Vector3) { -20, 20, 20 }, Vector3Zero(), GRAY, shader);
lights[3] = CreateLight(LIGHT_POINT, (Vector3) { 20, -20, -20 }, Vector3Zero(), GRAY, shader); lights[3] = CreateLight(LIGHT_POINT, (Vector3) { 20, -20, -20 }, Vector3Zero(), GRAY, shader);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
Vector3 modelpos = { 0 };
Vector3 camerarot = { 0 };
// Main game loop // Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key while (!WindowShouldClose()) // Detect window close button or ESC key
@ -137,15 +131,11 @@ int main(void)
} }
UpdateCameraPro(&camera, UpdateCameraPro(&camera,
(Vector3) { (Vector3){ (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))*0.1f - (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))*0.1f, // Move forward-backward
(IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))*0.1f - // Move forward-backward (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT))*0.1f - (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))*0.1f, // Move right-left
(IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))*0.1f, 0.0f }, // Move up-down
(IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT))*0.1f - // Move right-left camerarot, // Camera rotation
(IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))*0.1f, GetMouseWheelMove()*-2.0f); // Move to target (zoom)
0.0f // Move up-down
},
camerarot,
GetMouseWheelMove()*-2.0f); // Move to target (zoom)
// Cycle between models on mouse click // Cycle between models on mouse click
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) currentModel = (currentModel + 1) % MAX_VOX_FILES; if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) currentModel = (currentModel + 1) % MAX_VOX_FILES;
@ -156,36 +146,34 @@ int main(void)
// Update light values (actually, only enable/disable them) // Update light values (actually, only enable/disable them)
for (int i = 0; i < MAX_LIGHTS; i++) UpdateLightValues(shader, lights[i]); for (int i = 0; i < MAX_LIGHTS; i++) UpdateLightValues(shader, lights[i]);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Draw // Draw
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
BeginDrawing(); BeginDrawing();
ClearBackground(RAYWHITE); ClearBackground(RAYWHITE);
// Draw 3D model // Draw 3D model
BeginMode3D(camera); BeginMode3D(camera);
DrawModel(models[currentModel], modelpos, 1.0f, WHITE);
DrawGrid(10, 1.0);
DrawModel(models[currentModel], modelpos, 1.0f, WHITE); // Draw spheres to show where the lights are
DrawGrid(10, 1.0); for (int i = 0; i < MAX_LIGHTS; i++)
{
if (lights[i].enabled) DrawSphereEx(lights[i].position, 0.2f, 8, 8, lights[i].color);
else DrawSphereWires(lights[i].position, 0.2f, 8, 8, ColorAlpha(lights[i].color, 0.3f));
}
EndMode3D();
// Draw spheres to show where the lights are // Display info
for (int i = 0; i < MAX_LIGHTS; i++) DrawRectangle(10, 40, 340, 70, Fade(SKYBLUE, 0.5f));
{ DrawRectangleLines(10, 40, 340, 70, Fade(DARKBLUE, 0.5f));
if (lights[i].enabled) DrawSphereEx(lights[i].position, 0.2f, 8, 8, lights[i].color); DrawText("- MOUSE LEFT BUTTON: CYCLE VOX MODELS", 20, 50, 10, BLUE);
else DrawSphereWires(lights[i].position, 0.2f, 8, 8, ColorAlpha(lights[i].color, 0.3f)); DrawText("- MOUSE MIDDLE BUTTON: ZOOM OR ROTATE CAMERA", 20, 70, 10, BLUE);
} DrawText("- UP-DOWN-LEFT-RIGHT KEYS: MOVE CAMERA", 20, 90, 10, BLUE);
DrawText(TextFormat("Model file: %s", GetFileName(voxFileNames[currentModel])), 10, 10, 20, GRAY);
EndMode3D();
// Display info
DrawRectangle(10, 400, 340, 60, Fade(SKYBLUE, 0.5f));
DrawRectangleLines(10, 400, 340, 60, Fade(DARKBLUE, 0.5f));
DrawText("MOUSE LEFT BUTTON to CYCLE VOX MODELS", 40, 410, 10, BLUE);
DrawText("MOUSE MIDDLE BUTTON to ZOOM OR ROTATE CAMERA", 40, 420, 10, BLUE);
DrawText("UP-DOWN-LEFT-RIGHT KEYS to MOVE CAMERA", 40, 430, 10, BLUE);
DrawText(TextFormat("File: %s", GetFileName(voxFileNames[currentModel])), 10, 10, 20, GRAY);
EndDrawing(); EndDrawing();
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -201,5 +189,3 @@ int main(void)
return 0; return 0;
} }

View File

@ -57,7 +57,7 @@ int main(void)
Mesh mesh = GenMeshPoints(numPoints); Mesh mesh = GenMeshPoints(numPoints);
Model model = LoadModelFromMesh(mesh); Model model = LoadModelFromMesh(mesh);
//SetTargetFPS(60); SetTargetFPS(60);
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
// Main game loop // Main game loop
@ -92,15 +92,12 @@ int main(void)
// Draw // Draw
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
BeginDrawing(); BeginDrawing();
ClearBackground(BLACK); ClearBackground(BLACK);
BeginMode3D(camera); BeginMode3D(camera);
// The new method only uploads the points once to the GPU // The new method only uploads the points once to the GPU
if (useDrawModelPoints) if (useDrawModelPoints) DrawModelPoints(model, position, 1.0f, WHITE);
{
DrawModelPoints(model, position, 1.0f, WHITE);
}
else else
{ {
// The old method must continually draw the "points" (lines) // The old method must continually draw the "points" (lines)
@ -124,17 +121,16 @@ int main(void)
// Draw a unit sphere for reference // Draw a unit sphere for reference
DrawSphereWires(position, 1.0f, 10, 10, YELLOW); DrawSphereWires(position, 1.0f, 10, 10, YELLOW);
EndMode3D(); EndMode3D();
// Draw UI text // Draw UI text
DrawText(TextFormat("Point Count: %d", numPoints), 20, screenHeight - 50, 40, WHITE); DrawText(TextFormat("Point Count: %d", numPoints), 10, screenHeight - 50, 40, WHITE);
DrawText("Up - increase points", 20, 70, 20, WHITE); DrawText("UP - Increase points", 10, 40, 20, WHITE);
DrawText("Down - decrease points", 20, 100, 20, WHITE); DrawText("DOWN - Decrease points", 10, 70, 20, WHITE);
DrawText("Space - drawing function", 20, 130, 20, WHITE); DrawText("SPACE - Drawing function", 10, 100, 20, WHITE);
if (useDrawModelPoints) DrawText("Using: DrawModelPoints()", 20, 160, 20, GREEN); if (useDrawModelPoints) DrawText("Using: DrawModelPoints()", 10, 130, 20, GREEN);
else DrawText("Using: DrawPoint3D()", 20, 160, 20, RED); else DrawText("Using: DrawPoint3D()", 10, 130, 20, RED);
DrawFPS(10, 10); DrawFPS(10, 10);

File diff suppressed because it is too large Load Diff

View File

@ -33,7 +33,7 @@
#define GLSL_VERSION 100 #define GLSL_VERSION 100
#endif #endif
#define MAP_SIZE 10 #define MAP_SIZE 16
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Program main entry point // Program main entry point
@ -88,8 +88,6 @@ int main(void)
RenderTexture lightmap = LoadRenderTexture(MAP_SIZE, MAP_SIZE); RenderTexture lightmap = LoadRenderTexture(MAP_SIZE, MAP_SIZE);
SetTextureFilter(lightmap.texture, TEXTURE_FILTER_TRILINEAR);
Material material = LoadMaterialDefault(); Material material = LoadMaterialDefault();
material.shader = shader; material.shader = shader;
material.maps[MATERIAL_MAP_ALBEDO].texture = texture; material.maps[MATERIAL_MAP_ALBEDO].texture = texture;
@ -103,29 +101,33 @@ int main(void)
DrawTexturePro( DrawTexturePro(
light, light,
(Rectangle){ 0, 0, (float)light.width, (float)light.height }, (Rectangle){ 0, 0, (float)light.width, (float)light.height },
(Rectangle){ 0, 0, 20, 20 }, (Rectangle){ 0, 0, 2.0f*MAP_SIZE, 2.0f*MAP_SIZE },
(Vector2){ 10.0, 10.0 }, (Vector2){ (float)MAP_SIZE, (float)MAP_SIZE },
0.0, 0.0,
RED RED
); );
DrawTexturePro( DrawTexturePro(
light, light,
(Rectangle){ 0, 0, (float)light.width, (float)light.height }, (Rectangle){ 0, 0, (float)light.width, (float)light.height },
(Rectangle){ 8, 4, 20, 20 }, (Rectangle){ (float)MAP_SIZE*0.8f, (float)MAP_SIZE/2.0f, 2.0f*MAP_SIZE, 2.0f*MAP_SIZE },
(Vector2){ 10.0, 10.0 }, (Vector2){ (float)MAP_SIZE, (float)MAP_SIZE },
0.0, 0.0,
BLUE BLUE
); );
DrawTexturePro( DrawTexturePro(
light, light,
(Rectangle){ 0, 0, (float)light.width, (float)light.height }, (Rectangle){ 0, 0, (float)light.width, (float)light.height },
(Rectangle){ 8, 8, 10, 10 }, (Rectangle){ (float)MAP_SIZE*0.8f, (float)MAP_SIZE*0.8f, (float)MAP_SIZE, (float)MAP_SIZE },
(Vector2){ 5.0, 5.0 }, (Vector2){ (float)MAP_SIZE/2.0f, (float)MAP_SIZE/2.0f },
0.0, 0.0,
GREEN GREEN
); );
BeginBlendMode(BLEND_ALPHA); BeginBlendMode(BLEND_ALPHA);
EndTextureMode(); EndTextureMode();
// NOTE: To enable trilinear filtering we need mipmaps available for texture
GenTextureMipmaps(&lightmap.texture);
SetTextureFilter(lightmap.texture, TEXTURE_FILTER_TRILINEAR);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
@ -141,24 +143,20 @@ int main(void)
// Draw // Draw
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
BeginDrawing(); BeginDrawing();
ClearBackground(RAYWHITE); ClearBackground(RAYWHITE);
BeginMode3D(camera); BeginMode3D(camera);
DrawMesh(mesh, material, MatrixIdentity()); DrawMesh(mesh, material, MatrixIdentity());
EndMode3D(); EndMode3D();
DrawFPS(10, 10); DrawTexturePro(lightmap.texture, (Rectangle){ 0, 0, -MAP_SIZE, -MAP_SIZE },
DrawTexturePro(
lightmap.texture,
(Rectangle){ 0, 0, -MAP_SIZE, -MAP_SIZE },
(Rectangle){ (float)GetRenderWidth() - MAP_SIZE*8 - 10, 10, (float)MAP_SIZE*8, (float)MAP_SIZE*8 }, (Rectangle){ (float)GetRenderWidth() - MAP_SIZE*8 - 10, 10, (float)MAP_SIZE*8, (float)MAP_SIZE*8 },
(Vector2){ 0.0, 0.0 }, (Vector2){ 0.0, 0.0 }, 0.0, WHITE);
0.0,
WHITE);
DrawText("lightmap", GetRenderWidth() - 66, 16 + MAP_SIZE*8, 10, GRAY); DrawText(TextFormat("LIGHTMAP: %ix%i pixels", MAP_SIZE, MAP_SIZE), GetRenderWidth() - 130, 20 + MAP_SIZE*8, 10, GREEN);
DrawText("10x10 pixels", GetRenderWidth() - 76, 30 + MAP_SIZE*8, 10, GRAY);
DrawFPS(10, 10);
EndDrawing(); EndDrawing();
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------

View File

@ -77,7 +77,7 @@
* *
* static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)]; * static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)];
* *
* guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB * guiStyle size is by default: 16*(16 + 8) = 384 int = 384*4 bytes = 1536 bytes = 1.5 KB
* *
* Note that the first set of BASE properties (by default guiStyle[0..15]) belong to the generic style * Note that the first set of BASE properties (by default guiStyle[0..15]) belong to the generic style
* used for all controls, when any of those base values is set, it is automatically populated to all * used for all controls, when any of those base values is set, it is automatically populated to all
@ -141,7 +141,7 @@
* Draw text bounds rectangles for debug * Draw text bounds rectangles for debug
* *
* VERSIONS HISTORY: * VERSIONS HISTORY:
* 5.0-dev (2025) Current dev version... * 5.0 (xx-Nov-2025) ADDED: Support up to 32 controls (v500)
* ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes * ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes
* ADDED: GuiValueBoxFloat() * ADDED: GuiValueBoxFloat()
* ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP * ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP
@ -271,7 +271,7 @@
* 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria * 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria
* *
* DEPENDENCIES: * DEPENDENCIES:
* raylib 5.0 - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing * raylib 5.6-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing
* *
* STANDALONE MODE: * STANDALONE MODE:
* By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled * By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled
@ -1010,28 +1010,28 @@ typedef enum {
ICON_SLICING = 231, ICON_SLICING = 231,
ICON_MANUAL_CONTROL = 232, ICON_MANUAL_CONTROL = 232,
ICON_COLLISION = 233, ICON_COLLISION = 233,
ICON_234 = 234, ICON_CIRCLE_ADD = 234,
ICON_235 = 235, ICON_CIRCLE_ADD_FILL = 235,
ICON_236 = 236, ICON_CIRCLE_WARNING = 236,
ICON_237 = 237, ICON_CIRCLE_WARNING_FILL = 237,
ICON_238 = 238, ICON_BOX_MORE = 238,
ICON_239 = 239, ICON_BOX_MORE_FILL = 239,
ICON_240 = 240, ICON_BOX_MINUS = 240,
ICON_241 = 241, ICON_BOX_MINUS_FILL = 241,
ICON_242 = 242, ICON_UNION = 242,
ICON_243 = 243, ICON_INTERSECTION = 243,
ICON_244 = 244, ICON_DIFFERENCE = 244,
ICON_245 = 245, ICON_SPHERE = 245,
ICON_246 = 246, ICON_CYLINDER = 246,
ICON_247 = 247, ICON_CONE = 247,
ICON_248 = 248, ICON_ELLIPSOID = 248,
ICON_249 = 249, ICON_CAPSULE = 249,
ICON_250 = 250, ICON_250 = 250,
ICON_251 = 251, ICON_251 = 251,
ICON_252 = 252, ICON_252 = 252,
ICON_253 = 253, ICON_253 = 253,
ICON_254 = 254, ICON_254 = 254,
ICON_255 = 255, ICON_255 = 255
} GuiIconName; } GuiIconName;
#endif #endif
@ -1078,7 +1078,7 @@ typedef enum {
// Check if two rectangles are equal, used to validate a slider bounds as an id // Check if two rectangles are equal, used to validate a slider bounds as an id
#ifndef CHECK_BOUNDS_ID #ifndef CHECK_BOUNDS_ID
#define CHECK_BOUNDS_ID(src, dst) ((src.x == dst.x) && (src.y == dst.y) && (src.width == dst.width) && (src.height == dst.height)) #define CHECK_BOUNDS_ID(src, dst) (((int)src.x == (int)dst.x) && ((int)src.y == (int)dst.y) && ((int)src.width == (int)dst.width) && ((int)src.height == (int)dst.height))
#endif #endif
#if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS) #if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS)
@ -1341,22 +1341,22 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] =
0x7fe00000, 0x402e4020, 0x43ce5e0a, 0x40504078, 0x438e4078, 0x402e5e0a, 0x7fe04020, 0x00000000, // ICON_SLICING 0x7fe00000, 0x402e4020, 0x43ce5e0a, 0x40504078, 0x438e4078, 0x402e5e0a, 0x7fe04020, 0x00000000, // ICON_SLICING
0x00000000, 0x40027ffe, 0x47c24002, 0x55425d42, 0x55725542, 0x50125552, 0x10105016, 0x00001ff0, // ICON_MANUAL_CONTROL 0x00000000, 0x40027ffe, 0x47c24002, 0x55425d42, 0x55725542, 0x50125552, 0x10105016, 0x00001ff0, // ICON_MANUAL_CONTROL
0x7ffe0000, 0x43c24002, 0x48124422, 0x500a500a, 0x500a500a, 0x44224812, 0x400243c2, 0x00007ffe, // ICON_COLLISION 0x7ffe0000, 0x43c24002, 0x48124422, 0x500a500a, 0x500a500a, 0x44224812, 0x400243c2, 0x00007ffe, // ICON_COLLISION
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_234 0x03c00000, 0x10080c30, 0x21842184, 0x4ff24182, 0x41824ff2, 0x21842184, 0x0c301008, 0x000003c0, // ICON_CIRCLE_ADD
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_235 0x03c00000, 0x1ff80ff0, 0x3e7c3e7c, 0x700e7e7e, 0x7e7e700e, 0x3e7c3e7c, 0x0ff01ff8, 0x000003c0, // ICON_CIRCLE_ADD_FILL
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_236 0x03c00000, 0x10080c30, 0x21842184, 0x41824182, 0x40024182, 0x21842184, 0x0c301008, 0x000003c0, // ICON_CIRCLE_WARNING
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_237 0x03c00000, 0x1ff80ff0, 0x3e7c3e7c, 0x7e7e7e7e, 0x7ffe7e7e, 0x3e7c3e7c, 0x0ff01ff8, 0x000003c0, // ICON_CIRCLE_WARNING_FILL
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_238 0x00000000, 0x10041ffc, 0x10841004, 0x13e41084, 0x10841084, 0x10041004, 0x00001ffc, 0x00000000, // ICON_BOX_MORE
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_239 0x00000000, 0x1ffc1ffc, 0x1f7c1ffc, 0x1c1c1f7c, 0x1f7c1f7c, 0x1ffc1ffc, 0x00001ffc, 0x00000000, // ICON_BOX_MORE_FILL
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_240 0x00000000, 0x1ffc1ffc, 0x1ffc1ffc, 0x1c1c1ffc, 0x1ffc1ffc, 0x1ffc1ffc, 0x00001ffc, 0x00000000, // ICON_BOX_MINUS
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_241 0x00000000, 0x10041ffc, 0x10041004, 0x13e41004, 0x10041004, 0x10041004, 0x00001ffc, 0x00000000, // ICON_BOX_MINUS_FILL
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_242 0x07fe0000, 0x055606aa, 0x7ff606aa, 0x55766eba, 0x55766eaa, 0x55606ffe, 0x55606aa0, 0x00007fe0, // ICON_UNION
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_243 0x07fe0000, 0x04020402, 0x7fe20402, 0x456246a2, 0x456246a2, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_INTERSECTION
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_244 0x07fe0000, 0x055606aa, 0x7ff606aa, 0x4436442a, 0x4436442a, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_DIFFERENCE
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_245 0x03c00000, 0x10080c30, 0x20042004, 0x60064002, 0x47e2581a, 0x20042004, 0x0c301008, 0x000003c0, // ICON_SPHERE
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_246 0x03e00000, 0x08080410, 0x0c180808, 0x08080be8, 0x08080808, 0x08080808, 0x04100808, 0x000003e0, // ICON_CYLINDER
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_247 0x00800000, 0x01400140, 0x02200220, 0x04100410, 0x08080808, 0x1c1c13e4, 0x08081004, 0x000007f0, // ICON_CONE
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_248 0x00000000, 0x07e00000, 0x20841918, 0x40824082, 0x40824082, 0x19182084, 0x000007e0, 0x00000000, // ICON_ELLIPSOID
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_249 0x00000000, 0x00000000, 0x20041ff8, 0x40024002, 0x40024002, 0x1ff82004, 0x00000000, 0x00000000, // ICON_CAPSULE
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252
@ -1743,7 +1743,7 @@ int GuiPanel(Rectangle bounds, const char *text)
// NOTE: Using GuiToggle() for the TABS // NOTE: Using GuiToggle() for the TABS
int GuiTabBar(Rectangle bounds, const char **text, int count, int *active) int GuiTabBar(Rectangle bounds, const char **text, int count, int *active)
{ {
#define RAYGUI_TABBAR_ITEM_WIDTH 160 #define RAYGUI_TABBAR_ITEM_WIDTH 148
int result = -1; int result = -1;
//GuiState state = guiState; //GuiState state = guiState;
@ -1776,12 +1776,12 @@ int GuiTabBar(Rectangle bounds, const char **text, int count, int *active)
if (i == (*active)) if (i == (*active))
{ {
toggle = true; toggle = true;
GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle); GuiToggle(tabBounds, text[i], &toggle);
} }
else else
{ {
toggle = false; toggle = false;
GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle); GuiToggle(tabBounds, text[i], &toggle);
if (toggle) *active = i; if (toggle) *active = i;
} }
@ -2590,7 +2590,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
int pasteLength = 0; int pasteLength = 0;
int pasteCodepoint; int pasteCodepoint;
int pasteCodepointSize; int pasteCodepointSize;
// Count how many codepoints to copy, stopping at the first unwanted control character // Count how many codepoints to copy, stopping at the first unwanted control character
while (true) while (true)
{ {
@ -2599,7 +2599,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
if (!(multiline && (pasteCodepoint == (int)'\n')) && !(pasteCodepoint >= 32)) break; if (!(multiline && (pasteCodepoint == (int)'\n')) && !(pasteCodepoint >= 32)) break;
pasteLength += pasteCodepointSize; pasteLength += pasteCodepointSize;
} }
if (pasteLength > 0) if (pasteLength > 0)
{ {
// Move forward data from cursor position // Move forward data from cursor position
@ -2662,7 +2662,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
while (offset < textLength) while (offset < textLength)
{ {
if (!isspace(nextCodepoint & 0xff)) break; if (!isspace(nextCodepoint & 0xff)) break;
offset += nextCodepointSize; offset += nextCodepointSize;
accCodepointSize += nextCodepointSize; accCodepointSize += nextCodepointSize;
nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
@ -2673,11 +2673,11 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
textLength -= accCodepointSize; textLength -= accCodepointSize;
} }
else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && autoCursorShouldTrigger))) else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && autoCursorShouldTrigger)))
{ {
// Delete single codepoint from text, after current cursor position // Delete single codepoint from text, after current cursor position
int nextCodepointSize = 0; int nextCodepointSize = 0;
GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
@ -2704,7 +2704,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
offset -= prevCodepointSize; offset -= prevCodepointSize;
accCodepointSize += prevCodepointSize; accCodepointSize += prevCodepointSize;
} }
// Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace) // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace)
// Not using isalnum() since it only works on ASCII characters // Not using isalnum() since it only works on ASCII characters
bool puctuation = ispunct(prevCodepoint & 0xff); bool puctuation = ispunct(prevCodepoint & 0xff);
@ -2723,11 +2723,11 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
textLength -= accCodepointSize; textLength -= accCodepointSize;
textBoxCursorIndex -= accCodepointSize; textBoxCursorIndex -= accCodepointSize;
} }
else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && autoCursorShouldTrigger))) else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && autoCursorShouldTrigger)))
{ {
// Delete single codepoint from text, before current cursor position // Delete single codepoint from text, before current cursor position
int prevCodepointSize = 0; int prevCodepointSize = 0;
GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
@ -3033,7 +3033,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
int result = 0; int result = 0;
GuiState state = guiState; GuiState state = guiState;
char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0"; char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = { 0 };
snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value); snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value);
Rectangle textBounds = { 0 }; Rectangle textBounds = { 0 };
@ -3051,7 +3051,6 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
{ {
Vector2 mousePoint = GetMousePosition(); Vector2 mousePoint = GetMousePosition();
bool valueHasChanged = false; bool valueHasChanged = false;
if (editMode) if (editMode)
@ -3070,7 +3069,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
keyCount--; keyCount--;
valueHasChanged = true; valueHasChanged = true;
} }
else if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS -1) else if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
{ {
if (keyCount == 0) if (keyCount == 0)
{ {
@ -3087,30 +3086,26 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
} }
} }
// Only allow keys in range [48..57] // Add new digit to text value
if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) if ((keyCount >= 0) && (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) && (GuiGetTextWidth(textValue) < bounds.width))
{ {
if (GuiGetTextWidth(textValue) < bounds.width) int key = GetCharPressed();
// Only allow keys in range [48..57]
if ((key >= 48) && (key <= 57))
{ {
int key = GetCharPressed(); textValue[keyCount] = (char)key;
if ((key >= 48) && (key <= 57)) keyCount++;
{ valueHasChanged = true;
textValue[keyCount] = (char)key;
keyCount++;
valueHasChanged = true;
}
} }
} }
// Delete text // Delete text
if (keyCount > 0) if ((keyCount > 0) && IsKeyPressed(KEY_BACKSPACE))
{ {
if (IsKeyPressed(KEY_BACKSPACE)) keyCount--;
{ textValue[keyCount] = '\0';
keyCount--; valueHasChanged = true;
textValue[keyCount] = '\0';
valueHasChanged = true;
}
} }
if (valueHasChanged) *value = TextToInteger(textValue); if (valueHasChanged) *value = TextToInteger(textValue);
@ -3224,9 +3219,9 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float
textValue[1] = '\0'; textValue[1] = '\0';
keyCount++; keyCount++;
} }
for (int i = keyCount; i > -1; i--) textValue[i + 1] = textValue[i]; for (int i = keyCount; i > -1; i--) textValue[i + 1] = textValue[i];
textValue[0] = '-'; textValue[0] = '-';
keyCount++; keyCount++;
valueHasChanged = true; valueHasChanged = true;

View File

@ -284,11 +284,13 @@ static void DrawDisplaySegment(Vector2 center, int length, int thick, bool verti
if (!vertical) if (!vertical)
{ {
// Horizontal segment points // Horizontal segment points
// 3___________________________5 /*
// / \ 3___________________________5
// /1 x 6\ / \
// \ / /1 x 6\
// \2___________________________4/ \ /
\2___________________________4/
*/
Vector2 segmentPointsH[6] = { Vector2 segmentPointsH[6] = {
(Vector2){ center.x - length/2.0f - thick/2.0f, center.y }, // Point 1 (Vector2){ center.x - length/2.0f - thick/2.0f, center.y }, // Point 1
(Vector2){ center.x - length/2.0f, center.y + thick/2.0f }, // Point 2 (Vector2){ center.x - length/2.0f, center.y + thick/2.0f }, // Point 2

View File

@ -51,6 +51,8 @@ int main(void)
BeginTextureMode(canvas); BeginTextureMode(canvas);
ClearBackground(backgroundColor); ClearBackground(backgroundColor);
EndTextureMode(); EndTextureMode();
SetTargetFPS(60);
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
// Main game loop // Main game loop
@ -59,10 +61,7 @@ int main(void)
// Update // Update
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Disable the hint text once the user clicks // Disable the hint text once the user clicks
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && startText) if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && startText) startText = false;
{
startText = false;
}
// Clear the canvas when the user middle-clicks // Clear the canvas when the user middle-clicks
if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE)) if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE))
@ -79,7 +78,7 @@ int main(void)
if (leftButtonDown || rightButtonDown) if (leftButtonDown || rightButtonDown)
{ {
// The color for the line // The color for the line
Color drawColor; Color drawColor = WHITE;
if (leftButtonDown) if (leftButtonDown)
{ {
@ -88,10 +87,7 @@ int main(void)
// While the hue is >=360, subtract it to bring it down into the range 0-360 // While the hue is >=360, subtract it to bring it down into the range 0-360
// This is more visually accurate than resetting to zero // This is more visually accurate than resetting to zero
while (lineHue >= 360.0f) while (lineHue >= 360.0f) lineHue -= 360.0f;
{
lineHue -= 360.0f;
}
// Create the final color // Create the final color
drawColor = ColorFromHSV(lineHue, 1.0f, 1.0f); drawColor = ColorFromHSV(lineHue, 1.0f, 1.0f);
@ -104,10 +100,12 @@ int main(void)
// Draw the line onto the canvas // Draw the line onto the canvas
BeginTextureMode(canvas); BeginTextureMode(canvas);
// Circles act as "caps", smoothing corners // Circles act as "caps", smoothing corners
DrawCircleV(mousePositionPrevious, lineThickness/2.0f, drawColor); DrawCircleV(mousePositionPrevious, lineThickness/2.0f, drawColor);
DrawCircleV(GetMousePosition(), lineThickness/2.0f, drawColor); DrawCircleV(GetMousePosition(), lineThickness/2.0f, drawColor);
DrawLineEx(mousePositionPrevious, GetMousePosition(), lineThickness, drawColor); DrawLineEx(mousePositionPrevious, GetMousePosition(), lineThickness, drawColor);
EndTextureMode(); EndTextureMode();
} }

View File

@ -0,0 +1,280 @@
/*******************************************************************************************
*
* raylib [shapes] example - rlgl color wheel
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
*
* Example contributed by Robin (@RobinsAviary) 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) 2025-2025 Robin (@RobinsAviary)
*
********************************************************************************************/
#include "raylib.h"
#include "rlgl.h"
#include "raymath.h"
#include <stdlib.h>
#include <stdio.h>
#define RAYGUI_IMPLEMENTATION
#include "raygui.h"
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
// The minimum/maximum points the circle can have
const unsigned int pointsMin = 3;
const unsigned int pointsMax = 256;
// The current number of points and the radius of the circle
unsigned int triangleCount = 64;
float pointScale = 150.0f;
// Slider value, literally maps to value in HSV
float value = 1.0f;
// The center of the screen
Vector2 center = { (float)screenWidth/2.0f, (float)screenHeight/2.0f };
// The location of the color wheel
Vector2 circlePosition = center;
// The currently selected color
Color color = { 255, 255, 255, 255 };
// Indicates if the slider is being clicked
bool sliderClicked = false;
// Indicates if the current color going to be updated, as well as the handle position
bool settingColor = false;
// How the color wheel will be rendered
unsigned int renderType = RL_TRIANGLES;
// Enable anti-aliasing
SetConfigFlags(FLAG_MSAA_4X_HINT);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - rlgl color wheel");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
triangleCount += (unsigned int)GetMouseWheelMove();
triangleCount = (unsigned int)Clamp((float)triangleCount, (float)pointsMin, (float)pointsMax);
Rectangle sliderRectangle = { 42.0f, 16.0f + 64.0f + 45.0f, 64.0f, 16.0f };
Vector2 mousePosition = GetMousePosition();
// Checks if the user is hovering over the value slider
bool sliderHover = (mousePosition.x >= sliderRectangle.x && mousePosition.y >= sliderRectangle.y && mousePosition.x < sliderRectangle.x + sliderRectangle.width && mousePosition.y < sliderRectangle.y + sliderRectangle.height);
// Copy color as hex
if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_C))
{
if (IsKeyPressed(KEY_C))
{
SetClipboardText(TextFormat("#%02X%02X%02X", color.r, color.g, color.b));
}
}
// Scale up the color wheel, adjusting the handle visually
if (IsKeyDown(KEY_UP))
{
pointScale *= 1.025f;
if (pointScale > (float)screenHeight/2.0f)
{
pointScale = (float)screenHeight/2.0f;
}
else
{
circlePosition = Vector2Add(Vector2Multiply(Vector2Subtract(circlePosition, center), (Vector2){ 1.025f, 1.025f }), center);
}
}
// Scale down the wheel, adjusting the handle visually
if (IsKeyDown(KEY_DOWN))
{
pointScale *= 0.975f;
if (pointScale < 32.0f)
{
pointScale = 32.0f;
}
else
{
circlePosition = Vector2Add(Vector2Multiply(Vector2Subtract(circlePosition, center), (Vector2){ 0.975f, 0.975f }), center);
}
float distance = Vector2Distance(center, circlePosition)/pointScale;
float angle = ((Vector2Angle((Vector2){ 0.0f, -pointScale }, Vector2Subtract(center, circlePosition))/PI + 1.0f) / 2.0f);
if (distance > 1.0f)
{
circlePosition = Vector2Add((Vector2){ sinf(angle*(PI * 2.0f)) * pointScale, -cosf(angle*(PI*2.0f))*pointScale }, center);
}
}
// Checks if the user clicked on the color wheel
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && Vector2Distance(GetMousePosition(), center) <= pointScale + 10.0f)
{
settingColor = true;
}
// Update flag when mouse button is released
if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) settingColor = false;
// Check if the user clicked/released the slider for the color's value
if (sliderHover && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) sliderClicked = true;
if (sliderClicked && IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) sliderClicked = false;
// Update render mode accordingly
if (IsKeyPressed(KEY_SPACE)) renderType = RL_LINES;
if (IsKeyReleased(KEY_SPACE)) renderType = RL_TRIANGLES;
// If the slider or the wheel was clicked, update the current color
if (settingColor || sliderClicked)
{
if (settingColor) {
circlePosition = GetMousePosition();
}
float distance = Vector2Distance(center, circlePosition) / pointScale;
float angle = ((Vector2Angle((Vector2){ 0.0f, -pointScale }, Vector2Subtract(center, circlePosition))/PI + 1.0f)/2.0f);
if (settingColor && distance > 1.0f) {
circlePosition = Vector2Add((Vector2){ sinf(angle*(PI*2.0f))*pointScale, -cosf(angle*(PI* 2.0f))*pointScale }, center);
}
float angle360 = angle*360.0f;
float valueActual = Clamp(distance, 0.0f, 1.0f);
color = ColorLerp((Color){ (int)(value*255.0f), (int)(value*255.0f), (int)(value*255.0f), 255 }, ColorFromHSV(angle360, Clamp(distance, 0.0f, 1.0f), 1.0f), valueActual);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
// Begin rendering color wheel
rlBegin(renderType);
for (unsigned int i = 0; i < triangleCount; i++)
{
float angleOffset = ((PI*2.0f)/(float)triangleCount);
float angle = angleOffset*(float)i;
float angleOffsetCalculated = ((float)i + 1)*angleOffset;
Vector2 scale = (Vector2){ pointScale, pointScale };
Vector2 offset = Vector2Multiply((Vector2){ sinf(angle), -cosf(angle) }, scale);
Vector2 offset2 = Vector2Multiply((Vector2){ sinf(angleOffsetCalculated), -cosf(angleOffsetCalculated) }, scale);
Vector2 position = Vector2Add(center, offset);
Vector2 position2 = Vector2Add(center, offset2);
float angleNonRadian = (angle/(2.0f*PI))*360.0f;
float angleNonRadianOffset = (angleOffset/(2.0f*PI))*360.0f;
Color currentColor = ColorFromHSV(angleNonRadian, 1.0f, 1.0f);
Color offsetColor = ColorFromHSV(angleNonRadian + angleNonRadianOffset, 1.0f, 1.0f);
// Input vertices differently depending on mode
if (renderType == RL_TRIANGLES)
{
// RL_TRIANGLES expects three vertices per triangle
rlColor4ub(currentColor.r, currentColor.g, currentColor.b, currentColor.a);
rlVertex2f(position.x, position.y);
rlColor4f(value, value, value, 1.0f);
rlVertex2f(center.x, center.y);
rlColor4ub(offsetColor.r, offsetColor.g, offsetColor.b, offsetColor.a);
rlVertex2f(position2.x, position2.y);
}
else if (renderType == RL_LINES)
{
// RL_LINES expects two vertices per line
rlColor4ub(currentColor.r, currentColor.g, currentColor.b, currentColor.a);
rlVertex2f(position.x, position.y);
rlColor4ub(WHITE.r, WHITE.g, WHITE.b, WHITE.a);
rlVertex2f(center.x, center.y);
rlVertex2f(center.x, center.y);
rlColor4ub(offsetColor.r, offsetColor.g, offsetColor.b, offsetColor.a);
rlVertex2f(position2.x, position2.y);
rlVertex2f(position2.x, position2.y);
rlColor4ub(currentColor.r, currentColor.g, currentColor.b, currentColor.a);
rlVertex2f(position.x, position.y);
}
}
rlEnd();
// Make the handle slightly more visible overtop darker colors
Color handleColor = BLACK;
if (Vector2Distance(center, circlePosition)/pointScale <= 0.5f && value <= 0.5f)
{
handleColor = DARKGRAY;
}
// Draw the color handle
DrawCircleLinesV(circlePosition, 4.0f, handleColor);
// Draw the color in a preview, with a darkened outline.
DrawRectangleV((Vector2){ 8.0f, 8.0f }, (Vector2){ 64.0f, 64.0f }, color);
DrawRectangleLinesEx((Rectangle){ 8.0f, 8.0f, 64.0f, 64.0f }, 2.0f, ColorLerp(color, BLACK, 0.5f));
// Draw current color as hex and decimal
DrawText(TextFormat("#%02X%02X%02X\n(%d, %d, %d)", color.r, color.g, color.b, color.r, color.g, color.b), 8, 8 + 64 + 8, 20, DARKGRAY);
// Update the visuals for the copying text
Color copyColor = DARKGRAY;
unsigned int offset = 0;
if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_C))
{
copyColor = DARKGREEN;
offset = 4;
}
// Draw the copying text
DrawText("press ctrl+c to copy!", 8, 425 - offset, 20, copyColor);
// Display the number of rendered triangles
DrawText(TextFormat("triangle count: %d", triangleCount), 8, 395, 20, DARKGRAY);
// Slider to change color's value
GuiSliderBar(sliderRectangle, "value: ", "", &value, 0.0f, 1.0f);
// Draw FPS next to outlined color preview
DrawFPS(64 + 16, 8);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -210,7 +210,7 @@ static Vector2 MeasureTextStyled(Font font, const char *text, float fontSize, fl
if ((font.texture.id == 0) || (text == NULL) || (text[0] == '\0')) return textSize; // Security check if ((font.texture.id == 0) || (text == NULL) || (text[0] == '\0')) return textSize; // Security check
int textLen = TextLength(text); // Get size in bytes of text int textLen = TextLength(text); // Get size in bytes of text
float textLineSpacing = fontSize*1.5f; //float textLineSpacing = fontSize*1.5f; // Not used...
float textWidth = 0.0f; float textWidth = 0.0f;
float textHeight = fontSize; float textHeight = fontSize;

View File

@ -40,7 +40,7 @@ int main(void)
// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
Texture texPattern = LoadTexture("resources/patterns.png"); Texture texPattern = LoadTexture("resources/patterns.png");
SetTextureFilter(texPattern, TEXTURE_FILTER_TRILINEAR); // Makes the texture smoother when upscaled SetTextureFilter(texPattern, TEXTURE_FILTER_BILINEAR); // Makes the texture smoother when upscaled
// Coordinates for all patterns inside the texture // Coordinates for all patterns inside the texture
const Rectangle recPattern[] = { const Rectangle recPattern[] = {
@ -110,19 +110,17 @@ int main(void)
} }
} }
// Handle keys // Handle keys: change scale
// Change scale
if (IsKeyPressed(KEY_UP)) scale += 0.25f; if (IsKeyPressed(KEY_UP)) scale += 0.25f;
if (IsKeyPressed(KEY_DOWN)) scale -= 0.25f; if (IsKeyPressed(KEY_DOWN)) scale -= 0.25f;
if (scale > 10.0f) scale = 10.0f; if (scale > 10.0f) scale = 10.0f;
else if ( scale <= 0.0f) scale = 0.25f; else if ( scale <= 0.0f) scale = 0.25f;
// Change rotation // Handle keys: change rotation
if (IsKeyPressed(KEY_LEFT)) rotation -= 25.0f; if (IsKeyPressed(KEY_LEFT)) rotation -= 25.0f;
if (IsKeyPressed(KEY_RIGHT)) rotation += 25.0f; if (IsKeyPressed(KEY_RIGHT)) rotation += 25.0f;
// Reset // Handle keys: reset
if (IsKeyPressed(KEY_SPACE)) { rotation = 0.0f; scale = 1.0f; } if (IsKeyPressed(KEY_SPACE)) { rotation = 0.0f; scale = 1.0f; }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -165,7 +163,7 @@ int main(void)
// De-Initialization // De-Initialization
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
UnloadTexture(texPattern); // Unload texture UnloadTexture(texPattern); // Unload texture
CloseWindow(); // Close window and OpenGL context CloseWindow(); // Close window and OpenGL context
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------

View File

@ -1749,7 +1749,12 @@ int InitPlatform(void)
{ {
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH, // WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
// we can get a not-NULL terminated string, so, we only copy up to (MAX_GAMEPAD_NAME_LENGTH - 1) // we can get a not-NULL terminated string, so, we only copy up to (MAX_GAMEPAD_NAME_LENGTH - 1)
if (glfwJoystickPresent(i)) strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1); if (glfwJoystickPresent(i))
{
CORE.Input.Gamepad.ready[i] = true;
CORE.Input.Gamepad.axisCount[i] = GLFW_GAMEPAD_AXIS_LAST + 1;
strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1);
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------

View File

@ -1723,12 +1723,11 @@ void PollInputEvents(void)
CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f; CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f; CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
memset(CORE.Input.Gamepad.name[nextAvailableSlot], 0, MAX_GAMEPAD_NAME_LENGTH); memset(CORE.Input.Gamepad.name[nextAvailableSlot], 0, MAX_GAMEPAD_NAME_LENGTH);
strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], SDL_GameControllerNameForIndex(nextAvailableSlot), MAX_GAMEPAD_NAME_LENGTH - 1); const char *controllerName = SDL_GameControllerNameForIndex(nextAvailableSlot);
} if (controllerName != NULL) strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], controllerName, MAX_GAMEPAD_NAME_LENGTH - 1);
else else strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], "noname", 6);
{
TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
} }
else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
} }
} break; } break;
case SDL_JOYDEVICEREMOVED: case SDL_JOYDEVICEREMOVED:

View File

@ -724,7 +724,8 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
stbtt_GetCodepointHMetrics(&fontInfo, cp, &glyphs[k].advanceX, NULL); stbtt_GetCodepointHMetrics(&fontInfo, cp, &glyphs[k].advanceX, NULL);
glyphs[k].advanceX = (int)((float)glyphs[k].advanceX*scaleFactor); glyphs[k].advanceX = (int)((float)glyphs[k].advanceX*scaleFactor);
if (cpHeight > fontSize) TRACELOG(LOG_WARNING, "FONT: [0x%04x] Glyph height is bigger than requested font size: %i > %i", cp, cpHeight, (int)fontSize); // WARNING: If requested SDF font, sdf-glyph height is definitely bigger than fontSize due to FONT_SDF_CHAR_PADDING
if ((type != FONT_SDF) && (cpHeight > fontSize)) TRACELOG(LOG_WARNING, "FONT: [0x%04x] Glyph height is bigger than requested font size: %i > %i", cp, cpHeight, (int)fontSize);
// Load glyph image // Load glyph image
glyphs[k].image.width = cpWidth; glyphs[k].image.width = cpWidth;

View File

@ -4,7 +4,8 @@
``` ```
Example automated testing elements validated: Example automated testing elements validated:
- [WARN] : WARNING messages count - [CWARN] : Compilation WARNING messages
- [LWARN] : Log WARNING messages count
- [INIT] : Initialization - [INIT] : Initialization
- [CLOSE] : Closing - [CLOSE] : Closing
- [ASSETS] : Assets loading - [ASSETS] : Assets loading
@ -13,8 +14,9 @@ Example automated testing elements validated:
- [FONT] : Font default initialization - [FONT] : Font default initialization
- [TIMER] : Timer initialization - [TIMER] : Timer initialization
``` ```
| **EXAMPLE NAME** | [WARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] | | **EXAMPLE NAME** | [CWARN] | [LWARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] |
|:---------------------------------|:------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:| |:---------------------------------|:-------:|:-------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:|
| core_custom_logging | 0 | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | | text_font_loading | 0 | 10 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_custom_frame_control | 0 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | | text_codepoints_loading | 0 | 1 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| models_animation_playing | 0 | 1 | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |

View File

@ -415,12 +415,17 @@ int main(int argc, char *argv[])
else else
{ {
// Support building/testing not only individual examples but multiple: ALL/<category> // Support building/testing not only individual examples but multiple: ALL/<category>
rlExampleInfo *exBuildListInfo = LoadExampleData(argv[2], false, &exBuildListCount); int exBuildListInfoCount = 0;
rlExampleInfo *exBuildListInfo = LoadExampleData(argv[2], false, &exBuildListInfoCount);
for (int i = 0; i < exBuildListCount; i++) for (int i = 0; i < exBuildListInfoCount; i++)
{ {
exBuildList[i] = (char *)RL_CALLOC(256, sizeof(char)); if (!TextIsEqual(exBuildListInfo[i].category, "others"))
strcpy(exBuildList[i], exBuildListInfo[i].name); {
exBuildList[exBuildListCount] = (char *)RL_CALLOC(256, sizeof(char));
strcpy(exBuildList[exBuildListCount], exBuildListInfo[i].name);
exBuildListCount++;
}
} }
UnloadExampleData(exBuildListInfo); UnloadExampleData(exBuildListInfo);
@ -1266,8 +1271,8 @@ int main(int argc, char *argv[])
_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin"); _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name)); system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
#else #else
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exInfo->filter); LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exInfo->name);
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->filter)); system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
#endif #endif
// Update generated .html metadata // Update generated .html metadata
@ -1479,6 +1484,11 @@ int main(int argc, char *argv[])
memset(exCategory, 0, 32); memset(exCategory, 0, 32);
strncpy(exCategory, exName, TextFindIndex(exName, "_")); strncpy(exCategory, exName, TextFindIndex(exName, "_"));
// Skip some examples from building
if ((strcmp(exName, "core_custom_logging") == 0) ||
(strcmp(exName, "core_window_should_close") == 0) ||
(strcmp(exName, "core_custom_frame_control") == 0)) continue;
LOG("INFO: [%i/%i] Testing example: [%s]\n", i + 1, exBuildListCount, exName); LOG("INFO: [%i/%i] Testing example: [%s]\n", i + 1, exBuildListCount, exName);
// Steps to follow // Steps to follow
@ -1500,16 +1510,17 @@ int main(int argc, char *argv[])
TextFormat("%s/%s/%s.original.c", exBasePath, exCategory, exName)); TextFormat("%s/%s/%s.original.c", exBasePath, exCategory, exName));
char *srcText = LoadFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName)); char *srcText = LoadFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
#define BUILD_TESTING_WEB //#define BUILD_TESTING_WEB
#if defined(BUILD_TESTING_WEB) #if defined(BUILD_TESTING_WEB)
static const char *mainReplaceText = static const char *mainReplaceText =
"#include <stdio.h>\n" "#include <stdio.h>\n"
"#include <string.h>\n" "#include <string.h>\n"
"#include <stdlib.h>\n" "#include <stdlib.h>\n"
"#include <emscripten/emscripten.h>\n\n" "#include <emscripten/emscripten.h>\n\n"
"static char logText[1024] = {0};\n" "static char logText[4096] = {0};\n"
"static int logTextOffset = 0;\n\n" "static int logTextOffset = 0;\n\n"
"void CustomTraceLog(int msgType, const char *text, va_list args)\n{\n" "void CustomTraceLog(int msgType, const char *text, va_list args)\n{\n"
" if (logTextOffset < 3800)\n {\n"
" switch (msgType)\n {\n" " switch (msgType)\n {\n"
" case LOG_INFO: logTextOffset += sprintf(logText + logTextOffset, \"INFO: \"); break;\n" " case LOG_INFO: logTextOffset += sprintf(logText + logTextOffset, \"INFO: \"); break;\n"
" case LOG_ERROR: logTextOffset += sprintf(logText + logTextOffset, \"ERROR: \"); break;\n" " case LOG_ERROR: logTextOffset += sprintf(logText + logTextOffset, \"ERROR: \"); break;\n"
@ -1517,7 +1528,7 @@ int main(int argc, char *argv[])
" case LOG_DEBUG: logTextOffset += sprintf(logText + logTextOffset, \"DEBUG: \"); break;\n" " case LOG_DEBUG: logTextOffset += sprintf(logText + logTextOffset, \"DEBUG: \"); break;\n"
" default: break;\n }\n" " default: break;\n }\n"
" logTextOffset += vsprintf(logText + logTextOffset, text, args);\n" " logTextOffset += vsprintf(logText + logTextOffset, text, args);\n"
" logTextOffset += sprintf(logText + logTextOffset, \"\\n\");\n}\n\n" " logTextOffset += sprintf(logText + logTextOffset, \"\\n\");\n}\n}\n\n"
"int main(int argc, char *argv[])\n{\n" "int main(int argc, char *argv[])\n{\n"
" SetTraceLogCallback(CustomTraceLog);\n" " SetTraceLogCallback(CustomTraceLog);\n"
" int requestedTestFrames = 0;\n" " int requestedTestFrames = 0;\n"
@ -1525,20 +1536,20 @@ int main(int argc, char *argv[])
" if ((argc > 1) && (argc == 3) && (strcmp(argv[1], \"--frames\") != 0)) requestedTestFrames = atoi(argv[2]);\n"; " if ((argc > 1) && (argc == 3) && (strcmp(argv[1], \"--frames\") != 0)) requestedTestFrames = atoi(argv[2]);\n";
static const char *returnReplaceText = static const char *returnReplaceText =
" char outputLogFile[256] = { 0 };\n" " SaveFileText(\"outputLogFileName\", logText);\n"
" TextCopy(outputLogFile, GetFileNameWithoutExt(argv[0]));\n" " emscripten_run_script(\"saveFileFromMEMFSToDisk('outputLogFileName','outputLogFileName')\");\n\n"
" SaveFileText(outputLogFile, logText);\n"
" emscripten_run_script(TextFormat(\"saveFileFromMEMFSToDisk('%s','%s')\", outputLogFile, GetFileName(outputLogFile)));\n\n"
" return 0"; " return 0";
char *returnReplaceTextUpdated = TextReplace(returnReplaceText, "outputLogFileName", TextFormat("%s.log", exName));
char *srcTextUpdated[4] = { 0 }; char *srcTextUpdated[4] = { 0 };
srcTextUpdated[0] = TextReplace(srcText, "int main(void)\n{", mainReplaceText); srcTextUpdated[0] = TextReplace(srcText, "int main(void)\n{", mainReplaceText);
srcTextUpdated[1] = TextReplace(srcTextUpdated[0], "WindowShouldClose()", "WindowShouldClose() && (testFramesCount < requestedTestFrames)"); srcTextUpdated[1] = TextReplace(srcTextUpdated[0], "WindowShouldClose()", "WindowShouldClose() && (testFramesCount < requestedTestFrames)");
srcTextUpdated[2] = TextReplace(srcTextUpdated[1], "EndDrawing();", "EndDrawing(); testFramesCount++;"); srcTextUpdated[2] = TextReplace(srcTextUpdated[1], "EndDrawing();", "EndDrawing(); testFramesCount++;");
srcTextUpdated[3] = TextReplace(srcTextUpdated[2], " return 0", returnReplaceText); srcTextUpdated[3] = TextReplace(srcTextUpdated[2], " return 0", returnReplaceTextUpdated);
MemFree(returnReplaceTextUpdated);
UnloadFileText(srcText); UnloadFileText(srcText);
//SaveFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName), srcTextUpdated[3]); SaveFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName), srcTextUpdated[3]);
for (int i = 0; i < 4; i++) { MemFree(srcTextUpdated[i]); srcTextUpdated[i] = NULL; } for (int i = 0; i < 4; i++) { MemFree(srcTextUpdated[i]); srcTextUpdated[i] = NULL; }
// Build example for PLATFORM_WEB // Build example for PLATFORM_WEB
@ -1548,7 +1559,7 @@ int main(int argc, char *argv[])
// Build: raylib.com/examples/<category>/<category>_example_name.js // Build: raylib.com/examples/<category>/<category>_example_name.js
#if defined(_WIN32) #if defined(_WIN32)
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exName); LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exName);
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName)); system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B > %s/%s/logs/%s.build.log 2>&1", exBasePath, exCategory, exName));
#else #else
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exName); LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exName);
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName)); system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
@ -1560,9 +1571,11 @@ int main(int argc, char *argv[])
// STEP 3: Run example on browser // STEP 3: Run example on browser
ChangeDirectory(TextFormat("%s/%s", exBasePath, exCategory)); ChangeDirectory(TextFormat("%s/%s", exBasePath, exCategory));
system("start python -m http.server 8080"); system("start python -m http.server 8080"); // TODO: Init localhost just once!
system(TextFormat("start explorer \"http:\\localhost:8080/%s.html", exName)); system(TextFormat("start explorer \"http:\\localhost:8080/%s.html", exName));
// NOTE: Example .log is automatically downloaded into system Downloads directory on browser-example exectution
#else // BUILD_TESTING_DESKTOP #else // BUILD_TESTING_DESKTOP
static const char *mainReplaceText = static const char *mainReplaceText =
@ -1620,6 +1633,7 @@ int main(int argc, char *argv[])
for (int k = 0, index = 0; k < exTestBuildLogLinesCount; k++) for (int k = 0, index = 0; k < exTestBuildLogLinesCount; k++)
{ {
// Checking compilation warnings generated
if (TextFindIndex(exTestBuildLogLines[k], "warning:") >= 0) testing[i].buildwarns++; if (TextFindIndex(exTestBuildLogLines[k], "warning:") >= 0) testing[i].buildwarns++;
} }
@ -1663,7 +1677,8 @@ int main(int argc, char *argv[])
//----------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------
/* /*
Columns: Columns:
- [WARN] : WARNING messages count - [CWARN] : Compilation WARNING messages
- [LWARN] : Log WARNING messages count
- [INIT] : Initialization - [INIT] : Initialization
- [CLOSE] : Closing - [CLOSE] : Closing
- [ASSETS] : Assets loading - [ASSETS] : Assets loading
@ -1672,9 +1687,9 @@ int main(int argc, char *argv[])
- [FONT] : Font default initialization - [FONT] : Font default initialization
- [TIMER] : Timer initialization - [TIMER] : Timer initialization
| **EXAMPLE NAME** | [WARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] | | **EXAMPLE NAME** | [CWARN] | [LWARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] |
|:---------------------------------|:------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:| |:---------------------------------|:-------:|:-------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:|
| core_basic window | 0 | | | | | | | | | core_basic window | 0 | 0 | | | | | | | |
*/ */
LOG("INFO: [examples_testing.md] Generating examples testing report...\n"); LOG("INFO: [examples_testing.md] Generating examples testing report...\n");
@ -1685,7 +1700,8 @@ int main(int argc, char *argv[])
repIndex += sprintf(report + repIndex, "## Tested Platform: Windows\n\n"); repIndex += sprintf(report + repIndex, "## Tested Platform: Windows\n\n");
repIndex += sprintf(report + repIndex, "```\nExample automated testing elements validated:\n"); repIndex += sprintf(report + repIndex, "```\nExample automated testing elements validated:\n");
repIndex += sprintf(report + repIndex, " - [WARN] : WARNING messages count\n"); repIndex += sprintf(report + repIndex, " - [CWARN] : Compilation WARNING messages\n");
repIndex += sprintf(report + repIndex, " - [LWARN] : Log WARNING messages count\n");
repIndex += sprintf(report + repIndex, " - [INIT] : Initialization\n"); repIndex += sprintf(report + repIndex, " - [INIT] : Initialization\n");
repIndex += sprintf(report + repIndex, " - [CLOSE] : Closing\n"); repIndex += sprintf(report + repIndex, " - [CLOSE] : Closing\n");
repIndex += sprintf(report + repIndex, " - [ASSETS] : Assets loading\n"); repIndex += sprintf(report + repIndex, " - [ASSETS] : Assets loading\n");
@ -1694,8 +1710,8 @@ int main(int argc, char *argv[])
repIndex += sprintf(report + repIndex, " - [FONT] : Font default initialization\n"); repIndex += sprintf(report + repIndex, " - [FONT] : Font default initialization\n");
repIndex += sprintf(report + repIndex, " - [TIMER] : Timer initialization\n```\n"); repIndex += sprintf(report + repIndex, " - [TIMER] : Timer initialization\n```\n");
repIndex += sprintf(report + repIndex, "| **EXAMPLE NAME** | [WARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] |\n"); repIndex += sprintf(report + repIndex, "| **EXAMPLE NAME** | [CWARN] | [LWARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] |\n");
repIndex += sprintf(report + repIndex, "|:---------------------------------|:------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:|\n"); repIndex += sprintf(report + repIndex, "|:---------------------------------|:-------:|:-------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:|\n");
/* /*
TESTING_FAIL_INIT = 1 << 0, // Initialization (InitWindow()) -> "INFO: DISPLAY: Device initialized successfully" TESTING_FAIL_INIT = 1 << 0, // Initialization (InitWindow()) -> "INFO: DISPLAY: Device initialized successfully"
@ -1708,23 +1724,41 @@ int main(int argc, char *argv[])
*/ */
for (int i = 0; i < exBuildListCount; i++) for (int i = 0; i < exBuildListCount; i++)
{ {
if (testing[i].status > 0) if ((testing[i].buildwarns > 0) || (testing[i].warnings > 0) || (testing[i].status > 0))
{ {
repIndex += sprintf(report + repIndex, "| %-32s | %i | %s | %s | %s | %s | %s | %s | %s |\n", repIndex += sprintf(report + repIndex, "| %-32s | %i | %i | %s | %s | %s | %s | %s | %s | %s |\n",
exBuildList[i], testing[i].warnings, exBuildList[i],
(testing[i].status & TESTING_FAIL_INIT)? "" : "", testing[i].buildwarns,
(testing[i].status & TESTING_FAIL_CLOSE)? "" : "", testing[i].warnings,
(testing[i].status & TESTING_FAIL_ASSETS)? "" : "", (testing[i].status & TESTING_FAIL_INIT)? "" : "",
(testing[i].status & TESTING_FAIL_RLGL)? "" : "", (testing[i].status & TESTING_FAIL_CLOSE)? "" : "",
(testing[i].status & TESTING_FAIL_PLATFORM)? "" : "", (testing[i].status & TESTING_FAIL_ASSETS)? "" : "",
(testing[i].status & TESTING_FAIL_FONT)? "" : "", (testing[i].status & TESTING_FAIL_RLGL)? "" : "",
(testing[i].status & TESTING_FAIL_TIMER)? "" : ""); (testing[i].status & TESTING_FAIL_PLATFORM)? "" : "",
(testing[i].status & TESTING_FAIL_FONT)? "" : "",
(testing[i].status & TESTING_FAIL_TIMER)? "" : "");
} }
} }
repIndex += sprintf(report + repIndex, "\n"); repIndex += sprintf(report + repIndex, "\n");
SaveFileText(TextFormat("%s/../tools/rexm/reports/%s", exBasePath, "examples_testing_windows.md"), report); #if defined(PLATFORM_DRM)
const char *osName = "drm";
#elif defined(PLATFORM_WEB)
const char *osName = "web";
#elif defined(PLATFORM_DESKTOP)
#if defined(_WIN32)
const char *osName = "windows";
#elif defined(__linux__)
const char *osName = "linux";
#elif defined(__FreeBSD__)
const char *osName = "freebsd";
#elif defined(__APPLE__)
const char *osName = "macos";
#endif // Desktop OSs
#endif
SaveFileText(TextFormat("%s/../tools/rexm/reports/examples_testing_%s.md", exBasePath, osName), report);
RL_FREE(report); RL_FREE(report);
//----------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------