14 Commits

Author SHA1 Message Date
Ray
d1b535c7b8 Merge branch 'master' of https://github.com/raysan5/raylib 2025-08-14 21:23:08 +02:00
Ray
ed06cdbbe4 Update examples_report.md 2025-08-14 21:22:57 +02:00
Ray
81615a91a6 Merge pull request #5111 from didas72/master
Adds more filters for conditional build of GetWindowHandle with GLFW
2025-08-14 21:13:27 +02:00
Ray
6252d92f79 Update rexm.c 2025-08-14 21:11:30 +02:00
Ray
a65bdd6cca REXM: Reviewed automatic validation and update -WIP- 2025-08-14 21:07:36 +02:00
Ray
afdc7972d6 REXM: Automatic validation and update of examples 2025-08-14 21:07:10 +02:00
3ef5ee878c Adjusted formatting to comply with contribution guidelines 2025-08-14 19:58:22 +01:00
Ray
28b804a6ba REXM: Validate examples list against existing examples in repo 2025-08-14 20:38:27 +02:00
Ray
7037f131dc REVIEWED: example: core_3d_fps_controller 2025-08-14 20:37:52 +02:00
Ray
a9970484f3 Remove trailing spaces 2025-08-14 20:37:18 +02:00
Ray
be974bb67e Update CONVENTIONS.md 2025-08-14 20:36:08 +02:00
eae1296b08 Fixed bad macro logic 2025-08-14 18:56:31 +01:00
59c979a59d Added suggestions by planetis-m 2025-08-14 18:46:45 +01:00
93f86fa074 fixes #5110
Adds more filters for conditional build of GetWindowHandle with glfw
2025-08-14 14:30:29 +01:00
15 changed files with 380 additions and 294 deletions

View File

@ -11,7 +11,7 @@ Local variables | lowerCase | `Vector2 playerPosition = { 0 };`
Global variables | lowerCase | `bool windowReady = false;` Global variables | lowerCase | `bool windowReady = false;`
Constants | lowerCase | `const int maxValue = 8;` Constants | lowerCase | `const int maxValue = 8;`
Pointers | MyType *pointer | `Texture2D *array = NULL;` Pointers | MyType *pointer | `Texture2D *array = NULL;`
float values | always x.xf | `float gravity = 10.0f` float values | always x.xf | `float gravity = 10.0f` (avoid `10.f`)
Operators | value1*value2 | `int product = value*6;` Operators | value1*value2 | `int product = value*6;`
Operators | value1/value2 | `int division = value/4;` Operators | value1/value2 | `int division = value/4;`
Operators | value1 + value2 | `int sum = value + 10;` Operators | value1 + value2 | `int sum = value + 10;`
@ -72,19 +72,19 @@ void SomeFunction()
**If proposing new functions, please try to use a clear naming for function-name and functions-parameters, in case of doubt, open an issue for discussion.** **If proposing new functions, please try to use a clear naming for function-name and functions-parameters, in case of doubt, open an issue for discussion.**
## Files and Directories Naming Conventions ## Files and Directories Naming Conventions
- Directories will be named using `snake_case`: `resources/models`, `resources/fonts` - Directories will be named using `snake_case`: `resources/models`, `resources/fonts`
- Files will be named using `snake_case`: `main_title.png`, `cubicmap.png`, `sound.wav` - Files will be named using `snake_case`: `main_title.png`, `cubicmap.png`, `sound.wav`
_NOTE: Avoid any space or special character in the files/dir naming!_ _NOTE: Avoid any space or special character in the files/dir naming!_
## Games/Examples Directories Organization Conventions ## Games/Examples Directories Organization Conventions
- Data files should be organized by context and usage in the game, think about the loading requirements for data and put all the resources that need to be loaded at the same time together. - Data files should be organized by context and usage in the game, think about the loading requirements for data and put all the resources that need to be loaded at the same time together.
- Use descriptive names for the files, it would be perfect if just reading the name of the file, it was possible to know what is that file and where fits in the game. - Use descriptive names for the files, it would be perfect if just reading the name of the file, it was possible to know what is that file and where fits in the game.
- Here is an example, note that some resources require to be loaded all at once while other require to be loaded only at initialization (gui, font). - Here is an example, note that some resources require to be loaded all at once while other require to be loaded only at initialization (gui, font).
``` ```
resources/audio/fx/long_jump.wav resources/audio/fx/long_jump.wav
resources/audio/music/main_theme.ogg resources/audio/music/main_theme.ogg

View File

@ -704,8 +704,7 @@ core/core_3d_camera_split_screen: core/core_3d_camera_split_screen.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
core/core_3d_fps_controller: core/core_3d_fps_controller.c core/core_3d_fps_controller: core/core_3d_fps_controller.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
--preload-file core/resources/huh_jump.wav@resources/huh_jump.wav
core/core_3d_picking: core/core_3d_picking.c core/core_3d_picking: core/core_3d_picking.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)

View File

@ -16,9 +16,9 @@ You may find it easier to use than other toolchains, especially when it comes to
- `zig build [module]` to compile all examples for a module (e.g. `zig build core`) - `zig build [module]` to compile all examples for a module (e.g. `zig build core`)
- `zig build [example]` to compile _and run_ a particular example (e.g. `zig build core_basic_window`) - `zig build [example]` to compile _and run_ a particular example (e.g. `zig build core_basic_window`)
## EXAMPLES COLLECTION [TOTAL: 160] ## EXAMPLES COLLECTION [TOTAL: 161]
### category: core [36] ### category: core [37]
Examples using raylib[core](../src/rcore.c) platform functionality like window creation, inputs, drawing modes and system functionality. Examples using raylib[core](../src/rcore.c) platform functionality like window creation, inputs, drawing modes and system functionality.
@ -40,6 +40,7 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c
| [core_3d_camera_free](core/core_3d_camera_free.c) | <img src="core/core_3d_camera_free.png" alt="core_3d_camera_free" width="80"> | ⭐☆☆☆ | 1.3 | 1.3 | [Ramon Santamaria](https://github.com/raysan5) | | [core_3d_camera_free](core/core_3d_camera_free.c) | <img src="core/core_3d_camera_free.png" alt="core_3d_camera_free" width="80"> | ⭐☆☆☆ | 1.3 | 1.3 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_3d_camera_first_person](core/core_3d_camera_first_person.c) | <img src="core/core_3d_camera_first_person.png" alt="core_3d_camera_first_person" width="80"> | ⭐⭐☆☆ | 1.3 | 1.3 | [Ramon Santamaria](https://github.com/raysan5) | | [core_3d_camera_first_person](core/core_3d_camera_first_person.c) | <img src="core/core_3d_camera_first_person.png" alt="core_3d_camera_first_person" width="80"> | ⭐⭐☆☆ | 1.3 | 1.3 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_3d_camera_split_screen](core/core_3d_camera_split_screen.c) | <img src="core/core_3d_camera_split_screen.png" alt="core_3d_camera_split_screen" width="80"> | ⭐⭐⭐☆ | 3.7 | 4.0 | [Jeffery Myers](https://github.com/JeffM2501) | | [core_3d_camera_split_screen](core/core_3d_camera_split_screen.c) | <img src="core/core_3d_camera_split_screen.png" alt="core_3d_camera_split_screen" width="80"> | ⭐⭐⭐☆ | 3.7 | 4.0 | [Jeffery Myers](https://github.com/JeffM2501) |
| [core_3d_fps_controller](core/core_3d_fps_controller.c) | <img src="core/core_3d_fps_controller.png" alt="core_3d_fps_controller" width="80"> | ⭐⭐⭐☆ | 5.5 | 5.5 | [Agnis Aldins](https://github.com/nezvers) |
| [core_3d_picking](core/core_3d_picking.c) | <img src="core/core_3d_picking.png" alt="core_3d_picking" width="80"> | ⭐⭐☆☆ | 1.3 | 4.0 | [Ramon Santamaria](https://github.com/raysan5) | | [core_3d_picking](core/core_3d_picking.c) | <img src="core/core_3d_picking.png" alt="core_3d_picking" width="80"> | ⭐⭐☆☆ | 1.3 | 4.0 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_world_screen](core/core_world_screen.c) | <img src="core/core_world_screen.png" alt="core_world_screen" width="80"> | ⭐⭐☆☆ | 1.3 | 1.4 | [Ramon Santamaria](https://github.com/raysan5) | | [core_world_screen](core/core_world_screen.c) | <img src="core/core_world_screen.png" alt="core_world_screen" width="80"> | ⭐⭐☆☆ | 1.3 | 1.4 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_custom_logging](core/core_custom_logging.c) | <img src="core/core_custom_logging.png" alt="core_custom_logging" width="80"> | ⭐⭐⭐☆ | 2.5 | 2.5 | [Pablo Marcos Oltra](https://github.com/pamarcos) | | [core_custom_logging](core/core_custom_logging.c) | <img src="core/core_custom_logging.png" alt="core_custom_logging" width="80"> | ⭐⭐⭐☆ | 2.5 | 2.5 | [Pablo Marcos Oltra](https://github.com/pamarcos) |

View File

@ -1,10 +1,10 @@
/******************************************************************************************* /*******************************************************************************************
* *
* raylib [core] example - Input Gestures for Web * raylib [core] example - 3d first-person camera controller
* *
* Example complexity rating: [★★★☆] 3/4 * Example complexity rating: [★★★☆] 3/4
* *
* Example originally created with raylib 5.5 * Example originally created with raylib 5.5, last time updated with raylib 5.5
* *
* Example contributed by Agnis Aldins (@nezvers) and reviewed by Ramon Santamaria (@raysan5) * Example contributed by Agnis Aldins (@nezvers) and reviewed by Ramon Santamaria (@raysan5)
* *
@ -16,65 +16,60 @@
********************************************************************************************/ ********************************************************************************************/
#include "raylib.h" #include "raylib.h"
#include "raymath.h" #include "raymath.h"
#include "rcamera.h" #include "rcamera.h"
#if defined(PLATFORM_WEB) //----------------------------------------------------------------------------------
#include <emscripten/emscripten.h> // Defines and Macros
#endif //----------------------------------------------------------------------------------
// Movement constants
#define GRAVITY 32.0f
#define MAX_SPEED 20.0f
#define CROUCH_SPEED 5.0f
#define JUMP_FORCE 12.0f
#define MAX_ACCEL 150.0f
// Grounded drag
#define FRICTION 0.86f
// Increasing air drag, increases strafing speed
#define AIR_DRAG 0.98f
// Responsiveness for turning movement direction to looked direction
#define CONTROL 15.0f
#define CROUCH_HEIGHT 0.0f
#define STAND_HEIGHT 1.0f
#define BOTTOM_HEIGHT 0.5f
#if defined(PLATFORM_DESKTOP) #define NORMALIZE_INPUT 0
#define GLSL_VERSION 330
#else // PLATFORM_ANDROID, PLATFORM_WEB
#define GLSL_VERSION 100
#endif
/* Movement constants */
#define GRAVITY 32.f
#define MAX_SPEED 20.f
#define CROUCH_SPEED 5.f
#define JUMP_FORCE 12.f
#define MAX_ACCEL 150.f
/* Grounded drag */
#define FRICTION 0.86f
/* Increasing air drag, increases strafing speed */
#define AIR_DRAG 0.98f
/* Responsiveness for turning movement direction to looked direction */
#define CONTROL 15.f
#define CROUCH_HEIGHT 0.f
#define STAND_HEIGHT 1.f
#define BOTTOM_HEIGHT 0.5f
#define NORMALIZE_INPUT 0
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Body structure
typedef struct { typedef struct {
Vector3 position; Vector3 position;
Vector3 velocity; Vector3 velocity;
Vector3 dir; Vector3 dir;
bool isGrounded; bool isGrounded;
Sound soundJump; } Body;
}Body;
const int screenWidth = 800; //----------------------------------------------------------------------------------
const int screenHeight = 450; // Global Variables Definition
Vector2 sensitivity = { 0.001f, 0.001f }; //----------------------------------------------------------------------------------
static Vector2 sensitivity = { 0.001f, 0.001f };
Body player; static Body player = { 0 };
Camera camera; static Vector2 lookRotation = { 0 };
Vector2 lookRotation = { 0 }; static float headTimer = 0.0f;
float headTimer; static float walkLerp = 0.0f;
float walkLerp; static float headLerp = STAND_HEIGHT;
float headLerp; static Vector2 lean = { 0 };
Vector2 lean;
void UpdateDrawFrame(void); // Update and Draw one frame //----------------------------------------------------------------------------------
// Module functions declaration
void DrawLevel(); //----------------------------------------------------------------------------------
static void DrawLevel(void);
void UpdateCameraAngle(); static void UpdateCameraAngle(Camera *camera);
static void UpdateBody(Body *body, float rot, char side, char forward, bool jumpPressed, bool crouchHold);
void UpdateBody(Body* body, float rot, char side, char forward, bool jumpPressed, bool crouchHold);
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Program main entry point // Program main entry point
@ -83,213 +78,186 @@ int main(void)
{ {
// Initialization // Initialization
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "Raylib Quake-like controller"); const int screenWidth = 800;
InitAudioDevice(); const int screenHeight = 450;
player = (Body){ Vector3Zero(), Vector3Zero(), Vector3Zero(), false, LoadSound("resources/huh_jump.wav")}; InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d first-person camera controller");
camera = (Camera){ 0 };
camera.fovy = 60.f; // Camera field-of-view Y
camera.projection = CAMERA_PERSPECTIVE; // Camera projection type
lookRotation = Vector2Zero(); // Initialize camera variables
headTimer = 0.f; // NOTE: UpdateCameraAngle() takes care of the rest
walkLerp = 0.f; Camera camera = { 0 };
headLerp = STAND_HEIGHT; camera.fovy = 60.0f;
lean = Vector2Zero(); camera.projection = CAMERA_PERSPECTIVE;
camera.position = (Vector3){
player.position.x,
player.position.y + (BOTTOM_HEIGHT + headLerp),
player.position.z,
};
UpdateCameraAngle();
DisableCursor(); // Limit cursor to relative movement inside the window
#if defined(PLATFORM_WEB)
emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
#else
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
UpdateDrawFrame();
}
#endif
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadSound(player.soundJump);
CloseAudioDevice();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
void UpdateDrawFrame(void)
{
// Update
//----------------------------------------------------------------------------------
Vector2 mouse_delta = GetMouseDelta();
lookRotation.x -= mouse_delta.x * sensitivity.x;
lookRotation.y += mouse_delta.y * sensitivity.y;
char sideway = (IsKeyDown(KEY_D) - IsKeyDown(KEY_A));
char forward = (IsKeyDown(KEY_W) - IsKeyDown(KEY_S));
bool crouching = IsKeyDown(KEY_LEFT_CONTROL);
UpdateBody(&player, lookRotation.x, sideway, forward, IsKeyPressed(KEY_SPACE), crouching);
float delta = GetFrameTime();
headLerp = Lerp(headLerp, (crouching ? CROUCH_HEIGHT : STAND_HEIGHT), 20.f * delta);
camera.position = (Vector3){ camera.position = (Vector3){
player.position.x, player.position.x,
player.position.y + (BOTTOM_HEIGHT + headLerp), player.position.y + (BOTTOM_HEIGHT + headLerp),
player.position.z, player.position.z,
}; };
if (player.isGrounded && (forward != 0 || sideway != 0)) { UpdateCameraAngle(&camera); // Update camera parameters
headTimer += delta * 3.f;
walkLerp = Lerp(walkLerp, 1.f, 10.f * delta); DisableCursor(); // Limit cursor to relative movement inside the window
camera.fovy = Lerp(camera.fovy, 55.f, 5.f * delta);
} SetTargetFPS(60); // Set our game to run at 60 frames-per-second
else { //--------------------------------------------------------------------------------------
walkLerp = Lerp(walkLerp, 0.f, 10.f * delta);
camera.fovy = Lerp(camera.fovy, 60.f, 5.f * delta); // Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
Vector2 mouse_delta = GetMouseDelta();
lookRotation.x -= mouse_delta.x*sensitivity.x;
lookRotation.y += mouse_delta.y*sensitivity.y;
char sideway = (IsKeyDown(KEY_D) - IsKeyDown(KEY_A));
char forward = (IsKeyDown(KEY_W) - IsKeyDown(KEY_S));
bool crouching = IsKeyDown(KEY_LEFT_CONTROL);
UpdateBody(&player, lookRotation.x, sideway, forward, IsKeyPressed(KEY_SPACE), crouching);
float delta = GetFrameTime();
headLerp = Lerp(headLerp, (crouching ? CROUCH_HEIGHT : STAND_HEIGHT), 20.0f*delta);
camera.position = (Vector3){
player.position.x,
player.position.y + (BOTTOM_HEIGHT + headLerp),
player.position.z,
};
if (player.isGrounded && ((forward != 0) || (sideway != 0)))
{
headTimer += delta*3.0f;
walkLerp = Lerp(walkLerp, 1.0f, 10.0f*delta);
camera.fovy = Lerp(camera.fovy, 55.0f, 5.0f*delta);
}
else
{
walkLerp = Lerp(walkLerp, 0.0f, 10.0f*delta);
camera.fovy = Lerp(camera.fovy, 60.0f, 5.0f*delta);
}
lean.x = Lerp(lean.x, sideway*0.02f, 10.0f*delta);
lean.y = Lerp(lean.y, forward*0.015f, 10.0f*delta);
UpdateCameraAngle(&camera);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginMode3D(camera);
DrawLevel();
EndMode3D();
// Draw info box
DrawRectangle(5, 5, 330, 75, Fade(SKYBLUE, 0.5f));
DrawRectangleLines(5, 5, 330, 75, BLUE);
DrawText("Camera controls:", 15, 15, 10, BLACK);
DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, BLACK);
DrawText("- Look around: arrow keys or mouse", 15, 45, 10, BLACK);
DrawText(TextFormat("- Velocity Len: (%06.3f)", Vector2Length((Vector2){ player.velocity.x, player.velocity.z })), 15, 60, 10, BLACK);
EndDrawing();
//----------------------------------------------------------------------------------
} }
lean.x = Lerp(lean.x, sideway * 0.02f, 10.f * delta); // De-Initialization
lean.y = Lerp(lean.y, forward * 0.015f, 10.f * delta); //--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
UpdateCameraAngle(); return 0;
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginMode3D(camera);
DrawLevel();
EndMode3D();
// Draw info box
DrawRectangle(5, 5, 330, 100, Fade(SKYBLUE, 0.5f));
DrawRectangleLines(5, 5, 330, 100, BLUE);
DrawText("Camera controls:", 15, 15, 10, BLACK);
DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, BLACK);
DrawText("- Look around: arrow keys or mouse", 15, 45, 10, BLACK);
DrawText(TextFormat("- Velocity Len: (%06.3f)", Vector2Length((Vector2) { player.velocity.x, player.velocity.z })), 15, 60, 10, BLACK);
EndDrawing();
//----------------------------------------------------------------------------------
} }
void UpdateBody(Body* body, float rot, char side, char forward, bool jumpPressed, bool crouchHold) //----------------------------------------------------------------------------------
// Module functions definition
//----------------------------------------------------------------------------------
void UpdateBody(Body* body, float rot, char side, char forward, bool jumpPressed, bool crouchHold)
{ {
Vector2 input = (Vector2){ (float)side, (float)-forward }; Vector2 input = (Vector2){ (float)side, (float)-forward };
#if defined(NORMALIZE_INPUT) #if defined(NORMALIZE_INPUT)
// Slow down diagonal movement // Slow down diagonal movement
if (side != 0 & forward != 0) if ((side != 0) && (forward != 0)) input = Vector2Normalize(input);
{
input = Vector2Normalize(input);
}
#endif #endif
float delta = GetFrameTime(); float delta = GetFrameTime();
if (!body->isGrounded) if (!body->isGrounded) body->velocity.y -= GRAVITY*delta;
{
body->velocity.y -= GRAVITY * delta; if (body->isGrounded && jumpPressed)
}
if (body->isGrounded && jumpPressed)
{ {
body->velocity.y = JUMP_FORCE; body->velocity.y = JUMP_FORCE;
body->isGrounded = false; body->isGrounded = false;
SetSoundPitch(body->soundJump, 1.f + (GetRandomValue(-100, 100) * 0.001));
PlaySound(body->soundJump); // Sound can be played at this moment
//SetSoundPitch(fxJump, 1.0f + (GetRandomValue(-100, 100)*0.001));
//PlaySound(fxJump);
} }
Vector3 front_vec = (Vector3){ sin(rot), 0.f, cos(rot) }; Vector3 front = (Vector3){ sin(rot), 0.f, cos(rot) };
Vector3 right_vec = (Vector3){ cos(-rot), 0.f, sin(-rot) }; Vector3 right = (Vector3){ cos(-rot), 0.f, sin(-rot) };
Vector3 desired_dir = (Vector3){ Vector3 desiredDir = (Vector3){ input.x*right.x + input.y*front.x, 0.0f, input.x*right.z + input.y*front.z, };
input.x * right_vec.x + input.y * front_vec.x, body->dir = Vector3Lerp(body->dir, desiredDir, CONTROL*delta);
0.f,
input.x * right_vec.z + input.y * front_vec.z,
};
body->dir = Vector3Lerp(body->dir, desired_dir, CONTROL * delta); float decel = (body->isGrounded ? FRICTION : AIR_DRAG);
Vector3 hvel = (Vector3){ body->velocity.x*decel, 0.0f, body->velocity.z*decel };
float decel = body->isGrounded ? FRICTION : AIR_DRAG; float hvelLength = Vector3Length(hvel); // Magnitude
Vector3 hvel = (Vector3){ if (hvelLength < (MAX_SPEED*0.01f)) hvel = (Vector3){ 0 };
body->velocity.x * decel,
0.f,
body->velocity.z * decel
};
float hvel_length = Vector3Length(hvel); // a.k.a. magnitude // This is what creates strafing
if (hvel_length < MAX_SPEED * 0.01f) {
hvel = (Vector3){ 0 };
}
/* This is what creates strafing */
float speed = Vector3DotProduct(hvel, body->dir); float speed = Vector3DotProduct(hvel, body->dir);
/* // Whenever the amount of acceleration to add is clamped by the maximum acceleration constant,
Whenever the amount of acceleration to add is clamped by the maximum acceleration constant, // a Player can make the speed faster by bringing the direction closer to horizontal velocity angle
a Player can make the speed faster by bringing the direction closer to horizontal velocity angle // More info here: https://youtu.be/v3zT3Z5apaM?t=165
More info here: https://youtu.be/v3zT3Z5apaM?t=165 float maxSpeed = (crouchHold? CROUCH_SPEED : MAX_SPEED);
*/ float accel = Clamp(maxSpeed - speed, 0.f, MAX_ACCEL*delta);
float max_speed = crouchHold ? CROUCH_SPEED : MAX_SPEED; hvel.x += body->dir.x*accel;
float accel = Clamp(max_speed - speed, 0.f, MAX_ACCEL * delta); hvel.z += body->dir.z*accel;
hvel.x += body->dir.x * accel;
hvel.z += body->dir.z * accel;
body->velocity.x = hvel.x; body->velocity.x = hvel.x;
body->velocity.z = hvel.z; body->velocity.z = hvel.z;
body->position.x += body->velocity.x * delta; body->position.x += body->velocity.x*delta;
body->position.y += body->velocity.y * delta; body->position.y += body->velocity.y*delta;
body->position.z += body->velocity.z * delta; body->position.z += body->velocity.z*delta;
/* Fancy collision system against "THE FLOOR" */ // Fancy collision system against the floor
if (body->position.y <= 0.f) if (body->position.y <= 0.0f)
{ {
body->position.y = 0.f; body->position.y = 0.0f;
body->velocity.y = 0.f; body->velocity.y = 0.0f;
body->isGrounded = true; // <= enables jumping body->isGrounded = true; // Enable jumping
} }
} }
void UpdateCameraAngle() // Update camera
static void UpdateCameraAngle(Camera *camera)
{ {
const Vector3 up = (Vector3){ 0.f, 1.f, 0.f }; const Vector3 up = (Vector3){ 0.0f, 1.0f, 0.0f };
const Vector3 targetOffset = (Vector3){ 0.f, 0.f, -1.f }; const Vector3 targetOffset = (Vector3){ 0.0f, 0.0f, -1.0f };
/* Left & Right */ // Left and right
Vector3 yaw = Vector3RotateByAxisAngle(targetOffset, up, lookRotation.x); Vector3 yaw = Vector3RotateByAxisAngle(targetOffset, up, lookRotation.x);
// Clamp view up // Clamp view up
float maxAngleUp = Vector3Angle(up, yaw); float maxAngleUp = Vector3Angle(up, yaw);
maxAngleUp -= 0.001f; // avoid numerical errors maxAngleUp -= 0.001f; // Avoid numerical errors
if ( -(lookRotation.y) > maxAngleUp) { lookRotation.y = -maxAngleUp; } if ( -(lookRotation.y) > maxAngleUp) { lookRotation.y = -maxAngleUp; }
// Clamp view down // Clamp view down
float maxAngleDown = Vector3Angle(Vector3Negate(up), yaw); float maxAngleDown = Vector3Angle(Vector3Negate(up), yaw);
maxAngleDown *= -1.0f; // downwards angle is negative maxAngleDown *= -1.0f; // Downwards angle is negative
maxAngleDown += 0.001f; // avoid numerical errors maxAngleDown += 0.001f; // Avoid numerical errors
if ( -(lookRotation.y) < maxAngleDown) { lookRotation.y = -maxAngleDown; } if ( -(lookRotation.y) < maxAngleDown) { lookRotation.y = -maxAngleDown; }
/* Up & Down */ // Up and down
Vector3 right = Vector3Normalize(Vector3CrossProduct(yaw, up)); Vector3 right = Vector3Normalize(Vector3CrossProduct(yaw, up));
// Rotate view vector around right axis // Rotate view vector around right axis
@ -297,49 +265,48 @@ void UpdateCameraAngle()
// Head animation // Head animation
// Rotate up direction around forward axis // Rotate up direction around forward axis
float _sin = sin(headTimer * PI); float headSin = sin(headTimer*PI);
float _cos = cos(headTimer * PI); float headCos = cos(headTimer*PI);
const float stepRotation = 0.01f; const float stepRotation = 0.01f;
camera.up = Vector3RotateByAxisAngle(up, pitch, _sin * stepRotation + lean.x); camera->up = Vector3RotateByAxisAngle(up, pitch, headSin*stepRotation + lean.x);
/* BOB */ // Camera BOB
const float bobSide = 0.1f; const float bobSide = 0.1f;
const float bobUp = 0.15f; const float bobUp = 0.15f;
Vector3 bobbing = Vector3Scale(right, _sin * bobSide); Vector3 bobbing = Vector3Scale(right, headSin*bobSide);
bobbing.y = fabsf(_cos * bobUp); bobbing.y = fabsf(headCos*bobUp);
camera.position = Vector3Add(camera.position, Vector3Scale(bobbing, walkLerp));
camera.target = Vector3Add(camera.position, pitch); camera->position = Vector3Add(camera->position, Vector3Scale(bobbing, walkLerp));
camera->target = Vector3Add(camera->position, pitch);
} }
// Draw game level
void DrawLevel() static void DrawLevel(void)
{ {
const int floorExtent = 25; const int floorExtent = 25;
const float tileSize = 5.f; const float tileSize = 5.0f;
const Color tileColor1 = (Color){ 150, 200, 200, 255 }; const Color tileColor1 = (Color){ 150, 200, 200, 255 };
// Floor tiles // Floor tiles
for (int y = -floorExtent; y < floorExtent; y++) for (int y = -floorExtent; y < floorExtent; y++)
{ {
for (int x = -floorExtent; x < floorExtent; x++) for (int x = -floorExtent; x < floorExtent; x++)
{ {
if ((y & 1) && (x & 1)) if ((y & 1) && (x & 1))
{ {
DrawPlane((Vector3) { x * tileSize, 0.f, y * tileSize}, DrawPlane((Vector3){ x*tileSize, 0.0f, y*tileSize}, (Vector2){ tileSize, tileSize }, tileColor1);
(Vector2) {tileSize, tileSize}, tileColor1);
} }
else if(!(y & 1) && !(x & 1)) else if (!(y & 1) && !(x & 1))
{ {
DrawPlane((Vector3) { x * tileSize, 0.f, y * tileSize}, DrawPlane((Vector3){ x*tileSize, 0.0f, y*tileSize}, (Vector2){ tileSize, tileSize }, LIGHTGRAY);
(Vector2) {tileSize, tileSize}, LIGHTGRAY);
} }
} }
} }
const Vector3 towerSize = (Vector3){ 16.f, 32.f, 16.f }; const Vector3 towerSize = (Vector3){ 16.0f, 32.0f, 16.0f };
const Color towerColor = (Color){ 150, 200, 200, 255 }; const Color towerColor = (Color){ 150, 200, 200, 255 };
Vector3 towerPos = (Vector3){ 16.f, 16.f, 16.f }; Vector3 towerPos = (Vector3){ 16.0f, 16.0f, 16.0f };
DrawCubeV(towerPos, towerSize, towerColor); DrawCubeV(towerPos, towerSize, towerColor);
DrawCubeWiresV(towerPos, towerSize, DARKBLUE); DrawCubeWiresV(towerPos, towerSize, DARKBLUE);
@ -356,5 +323,5 @@ void DrawLevel()
DrawCubeWiresV(towerPos, towerSize, DARKBLUE); DrawCubeWiresV(towerPos, towerSize, DARKBLUE);
// Red sun // Red sun
DrawSphere((Vector3) { 300.f, 300.f, 0.f }, 100.f, (Color) { 255, 0, 0, 255 }); DrawSphere((Vector3){ 300.0f, 300.0f, 0.0f }, 100.0f, (Color){ 255, 0, 0, 255 });
} }

Binary file not shown.

View File

@ -3,7 +3,7 @@
# examples must be provided as: <example_category>;<example_name>;<example_stars>;<raylib_created_version>;<raylib_last_update_version>;"<example_author_name>";<author_github_user> # examples must be provided as: <example_category>;<example_name>;<example_stars>;<raylib_created_version>;<raylib_last_update_version>;"<example_author_name>";<author_github_user>
# #
# This list is used as the main reference by [rexm] tool for examples collection validation and management # This list is used as the main reference by [rexm] tool for examples collection validation and management
# New examples must be added to this list and any possible rename must be made on this list first # New examples must be added to this list and any possible rename must be made on this list first
# #
# WARNING: List is not ordered by example name but by the display order on web # WARNING: List is not ordered by example name but by the display order on web
# #

View File

@ -51,7 +51,7 @@
</ProjectConfiguration> </ProjectConfiguration>
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{0981CA98-E4A5-4DF1-987F-A41D09131EFC}</ProjectGuid> <ProjectGuid>{6B1A933E-71B8-4C1F-9E79-02D98830E671}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>shaders_normalmap</RootNamespace> <RootNamespace>shaders_normalmap</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>

View File

@ -335,6 +335,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_input_virtual_controls
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_3d_fps_controller", "examples\core_3d_fps_controller.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_3d_fps_controller", "examples\core_3d_fps_controller.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_normalmap", "examples\shaders_normalmap.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug.DLL|ARM64 = Debug.DLL|ARM64 Debug.DLL|ARM64 = Debug.DLL|ARM64
@ -4107,6 +4109,30 @@ Global
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x64.Build.0 = Release|x64 {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x64.Build.0 = Release|x64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.ActiveCfg = Release|Win32 {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.ActiveCfg = Release|Win32
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.Build.0 = Release|Win32 {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.Build.0 = Release|Win32
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|ARM64.ActiveCfg = Debug|ARM64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|ARM64.Build.0 = Debug|ARM64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x64.ActiveCfg = Debug|x64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x64.Build.0 = Debug|x64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x86.ActiveCfg = Debug|Win32
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x86.Build.0 = Debug|Win32
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x64.Build.0 = Release.DLL|x64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x86.Build.0 = Release.DLL|Win32
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|ARM64.ActiveCfg = Release|ARM64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|ARM64.Build.0 = Release|ARM64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x64.ActiveCfg = Release|x64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x64.Build.0 = Release|x64
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.ActiveCfg = Release|Win32
{6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -4276,6 +4302,7 @@ Global
{9CD8BCAD-F212-4BCC-BA98-899743CE3279} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} {9CD8BCAD-F212-4BCC-BA98-899743CE3279} = {CC132A4D-D081-4C26-BFB9-AB11984054F8}
{0981CA28-E4A5-4DF1-987F-A41D09131EFC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {0981CA28-E4A5-4DF1-987F-A41D09131EFC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
{6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
{6B1A933E-71B8-4C1F-9E79-02D98830E671} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29}

View File

@ -74,14 +74,27 @@
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX #include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
//#define GLFW_EXPOSE_NATIVE_WAYLAND #if defined(_GLFW_X11) || defined(_GLFW_WAYLAND)
#define GLFW_EXPOSE_NATIVE_X11 // Set appropriate expose macros based on available backends
#define Font X11Font // Hack to fix 'Font' name collision #if defined(_GLFW_X11)
#define GLFW_EXPOSE_NATIVE_X11
#define Font X11Font // Hack to fix 'Font' name collision
// The definition and references to the X11 Font type will be replaced by 'X11Font' // The definition and references to the X11 Font type will be replaced by 'X11Font'
// Works as long as the current file consistently references any X11 Font as X11Font // Works as long as the current file consistently references any X11 Font as X11Font
// Since it is never referenced (as of writting), this does not pose an issue // Since it is never referenced (as of writting), this does not pose an issue
#include "GLFW/glfw3native.h" // Required for: glfwGetX11Window() #endif
#undef Font // Revert hack and allow normal raylib Font usage
#if defined(_GLFW_WAYLAND)
#define GLFW_EXPOSE_NATIVE_WAYLAND
#endif
#include "GLFW/glfw3native.h" // Include native header only once, regardless of how many backends are defined
// Required for: glfwGetX11Window() and glfwGetWaylandWindow()
#if defined(_GLFW_X11) // Clean up X11-specific hacks
#undef Font // Revert hack and allow normal raylib Font usage
#endif
#endif
#endif #endif
#if defined(__APPLE__) #if defined(__APPLE__)
#include <unistd.h> // Required for: usleep() #include <unistd.h> // Required for: usleep()
@ -710,7 +723,7 @@ void SetWindowFocused(void)
glfwFocusWindow(platform.handle); glfwFocusWindow(platform.handle);
} }
#if defined(__linux__) #if defined(__linux__) && defined(_GLFW_X11)
// Local storage for the window handle returned by glfwGetX11Window // Local storage for the window handle returned by glfwGetX11Window
// This is needed as X11 handles are integers and may not fit inside a pointer depending on platform // This is needed as X11 handles are integers and may not fit inside a pointer depending on platform
// Storing the handle locally and returning a pointer in GetWindowHandle allows the code to work regardless of pointer width // Storing the handle locally and returning a pointer in GetWindowHandle allows the code to work regardless of pointer width
@ -724,10 +737,27 @@ void *GetWindowHandle(void)
return glfwGetWin32Window(platform.handle); return glfwGetWin32Window(platform.handle);
#endif #endif
#if defined(__linux__) #if defined(__linux__)
// Store the window handle localy and return a pointer to the variable instead #if defined(_GLFW_WAYLAND)
// Reasoning detailed in the declaration of X11WindowHandle #if defined(_GLFW_X11)
X11WindowHandle = glfwGetX11Window(platform.handle); int platformID = glfwGetPlatform();
return &X11WindowHandle; if (platformID == GLFW_PLATFORM_WAYLAND)
{
return glfwGetWaylandWindow(platform.handle);
}
else
{
X11WindowHandle = glfwGetX11Window(platform.handle);
return &X11WindowHandle;
}
#else
return glfwGetWaylandWindow(platform.handle);
#endif
#elif defined(_GLFW_X11)
// Store the window handle localy and return a pointer to the variable instead
// Reasoning detailed in the declaration of X11WindowHandle
X11WindowHandle = glfwGetX11Window(platform.handle);
return &X11WindowHandle;
#endif
#endif #endif
#if defined(__APPLE__) #if defined(__APPLE__)
// NOTE: Returned handle is: (objc_object *) // NOTE: Returned handle is: (objc_object *)
@ -1365,7 +1395,7 @@ int InitPlatform(void)
// Window flags requested before initialization to be applied after initialization // Window flags requested before initialization to be applied after initialization
unsigned int requestedWindowFlags = CORE.Window.flags; unsigned int requestedWindowFlags = CORE.Window.flags;
// Check window creation flags // Check window creation flags
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) CORE.Window.fullscreen = true; if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) CORE.Window.fullscreen = true;
@ -1663,7 +1693,7 @@ int InitPlatform(void)
int monitorHeight = 0; int monitorHeight = 0;
glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight); glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight);
// Here CORE.Window.render.width/height should be used instead of // Here CORE.Window.render.width/height should be used instead of
// CORE.Window.screen.width/height to center the window correctly when the high dpi flag is enabled // CORE.Window.screen.width/height to center the window correctly when the high dpi flag is enabled
int posX = monitorX + (monitorWidth - (int)CORE.Window.render.width)/2; int posX = monitorX + (monitorWidth - (int)CORE.Window.render.width)/2;
int posY = monitorY + (monitorHeight - (int)CORE.Window.render.height)/2; int posY = monitorY + (monitorHeight - (int)CORE.Window.render.height)/2;
@ -1675,7 +1705,7 @@ int InitPlatform(void)
CORE.Window.position.x = posX; CORE.Window.position.x = posX;
CORE.Window.position.y = posY; CORE.Window.position.y = posY;
} }
// Apply window flags requested previous to initialization // Apply window flags requested previous to initialization
SetWindowState(requestedWindowFlags); SetWindowState(requestedWindowFlags);

View File

@ -1103,7 +1103,7 @@ Vector2 GetWindowScaleDPI(void)
TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform"); TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
#else #else
scale.x = SDL_GetWindowDisplayScale(platform.window); scale.x = SDL_GetWindowDisplayScale(platform.window);
scale.y = scale.x; scale.y = scale.x;
#endif #endif
return scale; return scale;

View File

@ -1355,7 +1355,7 @@ int InitPlatform(void)
emscripten_set_blur_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback); emscripten_set_blur_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback);
emscripten_set_focus_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback); emscripten_set_focus_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback);
emscripten_set_visibilitychange_callback(NULL, 1, EmscriptenVisibilityChangeCallback); emscripten_set_visibilitychange_callback(NULL, 1, EmscriptenVisibilityChangeCallback);
// WARNING: Below resize code was breaking fullscreen mode for sample games and examples, it needs review // WARNING: Below resize code was breaking fullscreen mode for sample games and examples, it needs review
// Check fullscreen change events(note this is done on the window since most browsers don't support this on #canvas) // Check fullscreen change events(note this is done on the window since most browsers don't support this on #canvas)
// emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback); // emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
@ -1623,7 +1623,7 @@ static void MouseEnterCallback(GLFWwindow *window, int enter)
static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyboardEvent, void *userData) static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyboardEvent, void *userData)
{ {
// WARNING: Keyboard inputs already processed through GLFW callback // WARNING: Keyboard inputs already processed through GLFW callback
return 1; // The event was consumed by the callback handler return 1; // The event was consumed by the callback handler
} }
*/ */

View File

@ -1963,25 +1963,25 @@ bool IsFileExtension(const char *fileName, const char *ext)
if ((fileExt[i] >= 'A') && (fileExt[i] <= 'Z')) fileExtLower[i] = fileExt[i] + 32; if ((fileExt[i] >= 'A') && (fileExt[i] <= 'Z')) fileExtLower[i] = fileExt[i] + 32;
else fileExtLower[i] = fileExt[i]; else fileExtLower[i] = fileExt[i];
} }
int extCount = 1; int extCount = 1;
int extLen = (int)strlen(ext); int extLen = (int)strlen(ext);
char *extList = (char *)RL_CALLOC(extLen + 1, 1); char *extList = (char *)RL_CALLOC(extLen + 1, 1);
char *extListPtrs[MAX_FILE_EXTENSIONS] = { 0 }; char *extListPtrs[MAX_FILE_EXTENSIONS] = { 0 };
strcpy(extList, ext); strcpy(extList, ext);
extListPtrs[0] = extList; extListPtrs[0] = extList;
for (int i = 0; i < extLen; i++) for (int i = 0; i < extLen; i++)
{ {
// Convert to lower-case if extension is upper-case // Convert to lower-case if extension is upper-case
if ((extList[i] >= 'A') && (extList[i] <= 'Z')) extList[i] += 32; if ((extList[i] >= 'A') && (extList[i] <= 'Z')) extList[i] += 32;
// Get pointer to next extension and add null-terminator // Get pointer to next extension and add null-terminator
if ((extList[i] == ';') && (extCount < (MAX_FILE_EXTENSIONS - 1))) if ((extList[i] == ';') && (extCount < (MAX_FILE_EXTENSIONS - 1)))
{ {
extList[i] = '\0'; extList[i] = '\0';
extListPtrs[extCount] = extList + i + 1; extListPtrs[extCount] = extList + i + 1;
extCount++; extCount++;
} }
} }
@ -1991,7 +1991,7 @@ bool IsFileExtension(const char *fileName, const char *ext)
// does not start with the '.' // does not start with the '.'
fileExtLowerPtr = fileExtLower; fileExtLowerPtr = fileExtLower;
if (extListPtrs[i][0] != '.') fileExtLowerPtr++; if (extListPtrs[i][0] != '.') fileExtLowerPtr++;
if (strcmp(fileExtLowerPtr, extListPtrs[i]) == 0) if (strcmp(fileExtLowerPtr, extListPtrs[i]) == 0)
{ {
result = true; result = true;
@ -2053,7 +2053,7 @@ int GetFileLength(const char *fileName)
// WARNING: We just get the ptr but not the extension as a separate string // WARNING: We just get the ptr but not the extension as a separate string
const char *GetFileExtension(const char *fileName) const char *GetFileExtension(const char *fileName)
{ {
const char *dot = strrchr(fileName, '.'); const char *dot = strrchr(fileName, '.');
if (!dot || (dot == fileName)) return NULL; if (!dot || (dot == fileName)) return NULL;

View File

@ -2573,7 +2573,7 @@ void rlLoadExtensions(void *loader)
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
RLGL.loader = (rlglLoadProc)loader; RLGL.loader = (rlglLoadProc)loader;
// NOTE: Anisotropy levels capability is an extension // NOTE: Anisotropy levels capability is an extension
#ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT #ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF

View File

@ -35,6 +35,7 @@ Example elements validated:
| core_3d_camera_free | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_3d_camera_free | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_3d_camera_first_person | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_3d_camera_first_person | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_3d_camera_split_screen | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_3d_camera_split_screen | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_3d_fps_controller | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_3d_picking | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_3d_picking | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_world_screen | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_world_screen | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_custom_logging | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_custom_logging | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@ -54,7 +55,7 @@ Example elements validated:
| core_basic_window_web | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ❌ | | core_basic_window_web | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ❌ |
| core_input_gestures_web | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | | core_input_gestures_web | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ |
| core_automation_events | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | core_automation_events | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_high_dpi | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | core_high_dpi | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| shapes_basic_shapes | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_basic_shapes | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_bouncing_ball | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_bouncing_ball | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_colors_palette | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_colors_palette | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@ -73,8 +74,8 @@ Example elements validated:
| shapes_top_down_lights | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_top_down_lights | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_rectangle_advanced | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_rectangle_advanced | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_splines_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_splines_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_digital_clock | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | shapes_digital_clock | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| shapes_double_pendulum | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | shapes_double_pendulum | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| textures_logo_raylib | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_logo_raylib | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_srcrec_dstrec | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_srcrec_dstrec | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_image_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_image_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@ -91,7 +92,7 @@ Example elements validated:
| textures_sprite_button | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_sprite_button | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_sprite_explosion | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_sprite_explosion | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_bunnymark | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_bunnymark | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_mouse_painting | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | textures_mouse_painting | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| textures_blend_modes | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_blend_modes | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_draw_tiled | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_draw_tiled | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_polygon | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_polygon | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@ -153,7 +154,7 @@ Example elements validated:
| shaders_hot_reloading | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_hot_reloading | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_mesh_instancing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_mesh_instancing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_multi_sample2d | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_multi_sample2d | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_normalmap | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | ✔ | ✔ | | | shaders_normalmap | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | ✔ | ✔ | |
| shaders_spotlight | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_spotlight | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_deferred_render | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_deferred_render | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_hybrid_render | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_hybrid_render | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@ -163,8 +164,8 @@ Example elements validated:
| shaders_write_depth | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_write_depth | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_basic_pbr | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_basic_pbr | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_lightmap | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_lightmap | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_rounded_rectangle | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | shaders_rounded_rectangle | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| shaders_view_depth | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | shaders_view_depth | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| audio_module_playing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_module_playing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| audio_music_stream | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_music_stream | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| audio_raw_stream | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_raw_stream | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@ -172,10 +173,10 @@ Example elements validated:
| audio_mixed_processor | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_mixed_processor | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| audio_stream_effects | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_stream_effects | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| audio_sound_multi | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_sound_multi | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| audio_sound_positioning | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | audio_sound_positioning | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| rlgl_standalone | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | | ✔ | ✔ | ✔ | | ❌ | | rlgl_standalone | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | | ✔ | ✔ | ✔ | | ❌ |
| rlgl_compute_shader | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | | ✔ | ✔ | ✔ | | ❌ | | rlgl_compute_shader | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | | ✔ | ✔ | ✔ | | ❌ |
| easings_testbed | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | | ✔ | ✔ | ✔ | | ❌ | | easings_testbed | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | | ✔ | ✔ | ✔ | | ❌ |
| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ❌ | ✔ | | ✔ | ❌ | ✔ | | ❌ | | raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ❌ | ✔ | | ✔ | ❌ | ✔ | | ❌ |
| embedded_files_loading | ✔ | ❌ | ❌ | ✔ | ✔ | ❌ | ✔ | | ✔ | ✔ | ✔ | | ❌ | | embedded_files_loading | ✔ | ❌ | ❌ | ✔ | ✔ | ❌ | ✔ | | ✔ | ✔ | ✔ | | ❌ |
| raymath_vector_angle | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | | ✔ | ❌ | ✔ | | ❌ | | raymath_vector_angle | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | | ✔ | ❌ | ✔ | | ❌ |

View File

@ -749,6 +749,53 @@ int main(int argc, char *argv[])
// TODO: Log more details about the validation process // TODO: Log more details about the validation process
// Scan available example .c files and add to collection missing ones
// NOTE: Source of truth is what we have in the examples directories (on validation/update)
FilePathList list = LoadDirectoryFilesEx(exBasePath, ".c", true);
const char *exList = LoadFileText(exCollectionFilePath);
char *exListUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1);
bool listUpdated = false;
int exListLen = strlen(exList);
strcpy(exListUpdated, exList);
for (int i = 0; i < list.count; i++)
{
if ((strcmp("examples_template", GetFileNameWithoutExt(list.paths[i])) != 0) && // HACK: Skip "examples_template"
(TextFindIndex(exList, GetFileNameWithoutExt(list.paths[i])) == -1))
{
// Add example to the examples collection list
// WARNING: Added to the end of the list, order must be set by users and
// defines placement on raylib webpage
rlExampleInfo *exInfo = LoadExampleInfo(list.paths[i]);
// Get example difficulty stars
char starsText[16] = { 0 };
for (int i = 0; i < 4; i++)
{
// NOTE: Every UTF-8 star are 3 bytes
if (i < exInfo->stars) strcpy(starsText + 3*i, "⭐️");
else strcpy(starsText + 3*i, "");
}
exListLen += sprintf(exListUpdated + exListLen,
TextFormat("%s;%s;%s;%.1f;%.1f;\"%s\";@%s\n",
exInfo->category, exInfo->name, starsText, exInfo->verCreated,
exInfo->verUpdated, exInfo->author, exInfo->authorGitHub));
listUpdated = true;
UnloadExampleInfo(exInfo);
}
}
if (listUpdated) SaveFileText(exCollectionFilePath, exListUpdated);
UnloadFileText(exList);
RL_FREE(exListUpdated);
UnloadDirectoryFiles(list);
// Check all examples in collection [examples_list.txt] -> Source of truth! // Check all examples in collection [examples_list.txt] -> Source of truth!
int exCollectionCount = 0; int exCollectionCount = 0;
rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, "ALL", false, &exCollectionCount); rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, "ALL", false, &exCollectionCount);
@ -875,11 +922,18 @@ int main(int argc, char *argv[])
else else
{ {
// NOTE: Some issues can not be automatically fixed, only logged // NOTE: Some issues can not be automatically fixed, only logged
//if (exInfo->status & VALID_MISSING_PNG) LOG("WARNING: [%s] Missing screenshot file\n", exInfo->name); if (exInfo->status & VALID_MISSING_PNG) LOG("WARNING: [%s] Missing screenshot file\n", exInfo->name);
//if (exInfo->status & VALID_INVALID_PNG) LOG("WARNING: [%s] Invalid screenshot file (using template)\n", exInfo->name); if (exInfo->status & VALID_INVALID_PNG) LOG("WARNING: [%s] Invalid screenshot file (using template)\n", exInfo->name);
//if (exInfo->status & VALID_MISSING_RESOURCES) LOG("WARNING: [%s] Missing resources detected\n", exInfo->name); if (exInfo->status & VALID_MISSING_RESOURCES) LOG("WARNING: [%s] Missing resources detected\n", exInfo->name);
//if (exInfo->status & VALID_INCONSISTENT_INFO) LOG("WARNING: [%s] Inconsistent example header info\n", exInfo->name); if (exInfo->status & VALID_INCONSISTENT_INFO) LOG("WARNING: [%s] Inconsistent example header info\n", exInfo->name);
//if (exInfo->status & VALID_INVALID_CATEGORY) LOG("WARNING: [%s] Invalid example category\n", exInfo->name); if (exInfo->status & VALID_INVALID_CATEGORY) LOG("WARNING: [%s] Invalid example category\n", exInfo->name);
// NOTE: Some examples should be excluded from VS2022 solution because
// they have specific platform/linkage requirements:
if ((strcmp(exInfo->name, "core_basic_window_web") == 0) ||
(strcmp(exInfo->name, "core_input_gestures_web") == 0) ||
(strcmp(exInfo->name, "raylib_opengl_interop") == 0) ||
(strcmp(exInfo->name, "raymath_vector_angle") == 0)) continue;
// Review: Add: raylib/projects/VS2022/examples/<category>_example_name.vcxproj // Review: Add: raylib/projects/VS2022/examples/<category>_example_name.vcxproj
// Review: Add: raylib/projects/VS2022/raylib.sln // Review: Add: raylib/projects/VS2022/raylib.sln
@ -893,7 +947,7 @@ int main(int argc, char *argv[])
FileTextReplace(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name), FileTextReplace(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name),
"..\\..\\examples\\core", TextFormat("..\\..\\examples\\%s", exInfo->category)); "..\\..\\examples\\core", TextFormat("..\\..\\examples\\%s", exInfo->category));
exInfo->status |= VALID_MISSING_VCXPROJ; exInfo->status &= ~VALID_MISSING_VCXPROJ;
} }
// Add project (.vcxproj) to raylib solution (.sln) // Add project (.vcxproj) to raylib solution (.sln)
@ -902,7 +956,7 @@ int main(int argc, char *argv[])
AddVSProjectToSolution(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name), AddVSProjectToSolution(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name),
exVSProjectSolutionFile, exInfo->category); exVSProjectSolutionFile, exInfo->category);
exInfo->status |= VALID_NOT_IN_VCXSOL; exInfo->status &= ~VALID_NOT_IN_VCXSOL;
} }
// Review: Add/Remove: raylib.com/examples/<category>/<category>_example_name.html // Review: Add/Remove: raylib.com/examples/<category>/<category>_example_name.html
@ -910,7 +964,8 @@ int main(int argc, char *argv[])
// Review: Add/Remove: raylib.com/examples/<category>/<category>_example_name.wasm // Review: Add/Remove: raylib.com/examples/<category>/<category>_example_name.wasm
// Review: Add/Remove: raylib.com/examples/<category>/<category>_example_name.js // Review: Add/Remove: raylib.com/examples/<category>/<category>_example_name.js
// Solves: VALID_MISSING_WEB_OUTPUT // Solves: VALID_MISSING_WEB_OUTPUT
if (exInfo->status & VALID_MISSING_WEB_OUTPUT) if ((strcmp(exInfo->category, "others") != 0) && // Skipping "others" category
exInfo->status & VALID_MISSING_WEB_OUTPUT)
{ {
system(TextFormat("%s/build_example_web.bat %s/%s", exBasePath, exInfo->category, exInfo->name)); system(TextFormat("%s/build_example_web.bat %s/%s", exBasePath, exInfo->category, exInfo->name));
@ -924,7 +979,7 @@ int main(int argc, char *argv[])
FileCopy(TextFormat("%s/%s/%s.js", exBasePath, exInfo->category, exInfo->name), FileCopy(TextFormat("%s/%s/%s.js", exBasePath, exInfo->category, exInfo->name),
TextFormat("%s/%s/%s.js", exWebPath, exInfo->category, exInfo->name)); TextFormat("%s/%s/%s.js", exWebPath, exInfo->category, exInfo->name));
exInfo->status |= VALID_MISSING_WEB_OUTPUT; exInfo->status &= ~VALID_MISSING_WEB_OUTPUT;
} }
} }
} }
@ -934,10 +989,10 @@ int main(int argc, char *argv[])
UpdateRequiredFiles(); UpdateRequiredFiles();
for (int i = 0; i < exCollectionCount; i++) for (int i = 0; i < exCollectionCount; i++)
{ {
exCollection[i].status |= VALID_NOT_IN_MAKEFILE; exCollection[i].status &= ~VALID_NOT_IN_MAKEFILE;
exCollection[i].status |= VALID_NOT_IN_MAKEFILE_WEB; exCollection[i].status &= ~VALID_NOT_IN_MAKEFILE_WEB;
exCollection[i].status |= VALID_NOT_IN_README; exCollection[i].status &= ~VALID_NOT_IN_README;
exCollection[i].status |= VALID_NOT_IN_JS; exCollection[i].status &= ~VALID_NOT_IN_JS;
} }
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------
} }
@ -1566,12 +1621,13 @@ static void UnloadTextLines(char **lines)
RL_FREE(lines); RL_FREE(lines);
} }
// Get example info from file header // Get example info from example file header
// NOTE: Expecting the example to follow raylib_example_template.c
rlExampleInfo *LoadExampleInfo(const char *exFileName) rlExampleInfo *LoadExampleInfo(const char *exFileName)
{ {
rlExampleInfo *exInfo = (rlExampleInfo *)RL_CALLOC(1, sizeof(rlExampleInfo)); rlExampleInfo *exInfo = (rlExampleInfo *)RL_CALLOC(1, sizeof(rlExampleInfo));
if (IsFileExtension(exFileName, ".c")) if (FileExists(exFileName) && IsFileExtension(exFileName, ".c"))
{ {
strcpy(exInfo->name, GetFileNameWithoutExt(exFileName)); strcpy(exInfo->name, GetFileNameWithoutExt(exFileName));
strncpy(exInfo->category, exInfo->name, TextFindIndex(exInfo->name, "_")); strncpy(exInfo->category, exInfo->name, TextFindIndex(exInfo->name, "_"));
@ -1747,16 +1803,21 @@ static char **ScanExampleResources(const char *filePath, int *resPathCount)
strncpy(buffer, start, len); strncpy(buffer, start, len);
buffer[len] = '\0'; buffer[len] = '\0';
// TODO: Make sure buffer is a path (and not a Tracelog() text)
// Check for known extensions // Check for known extensions
for (int i = 0; i < extCount; i++) for (int i = 0; i < extCount; i++)
{ {
// TODO: WARNING: IsFileExtension() expects a NULL terminated fileName,
// but in this case buffer can contain any kind of string,
// including not paths strings, for example TraceLog() string
if (IsFileExtension(buffer, exts[i])) if (IsFileExtension(buffer, exts[i]))
{ {
// Avoid duplicates // Avoid duplicates
bool found = false; bool found = false;
for (int j = 0; j < resCounter; j++) for (int j = 0; j < resCounter; j++)
{ {
if (TextIsEqual(paths[j], buffer)) { found = true; break; } if (strcmp(paths[j], buffer) == 0) { found = true; break; }
} }
if (!found && (resCounter < REXM_MAX_RESOURCE_PATHS)) if (!found && (resCounter < REXM_MAX_RESOURCE_PATHS))