diff --git a/.gitignore b/.gitignore index 49e296e73..a1ca6c009 100644 --- a/.gitignore +++ b/.gitignore @@ -53,17 +53,6 @@ packages/ *.bc *.so -# Ignore all examples files -examples/* -# Unignore all examples files with extension -!examples/*.c -!examples/*.png -# Unignore examples Makefile -!examples/Makefile -!examples/Makefile.Android -!examples/raylib_compile_execute.bat -!examples/raylib_makefile_example.bat - # Ignore files build by xcode *.mode*v* *.pbxuser @@ -93,9 +82,6 @@ compile_commands.json CTestTestfile.cmake build -# Unignore These makefiles... -!examples/CMakeLists.txt - # Ignore GNU global tags GPATH GRTAGS diff --git a/BINDINGS.md b/BINDINGS.md index 886b8e67c..1c66f495c 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -64,6 +64,7 @@ Here it is a list with the ones I'm aware of: | raylib-factor | 3.5 | [Factor](https://factorcode.org/) | https://github.com/ArnautDaniel/raylib-factor | | gforth-raylib | 3.5 | [Gforth](https://gforth.org/) | https://github.com/ArnautDaniel/gforth-raylib | | raylib-haxe | 2.4 | [Haxe](https://haxe.org/) | https://github.com/ibilon/raylib-haxe | +| hxRaylib | 3.7 | [Haxe](https://haxe.org/) | https://github.com/ForeignSasquatch/hxRaylib | | ringraylib | 2.6 | [Ring](http://ring-lang.sourceforge.net/) | https://github.com/ringpackages/ringraylib | | cl-raylib | 3.0 | [Common Lisp](https://common-lisp.net/) | https://github.com/longlene/cl-raylib | | raylib-scm | 2.5 | [Chicken Scheme](https://www.call-cc.org/) | https://github.com/yashrk/raylib-scm | diff --git a/examples/core/core_2d_camera_smooth_pixelperfect.c b/examples/core/core_2d_camera_smooth_pixelperfect.c index ae40cdfc1..75ffe262a 100644 --- a/examples/core/core_2d_camera_smooth_pixelperfect.c +++ b/examples/core/core_2d_camera_smooth_pixelperfect.c @@ -5,15 +5,16 @@ * This example has been created using raylib 3.7 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Example contributed by Giancamillo Alessandroni ([discord]NotManyIdeas#9972 - [github]NotManyIdeasDev) and +* Example contributed by Giancamillo Alessandroni (@NotManyIdeasDev) and * reviewed by Ramon Santamaria (@raysan5) * -* Copyright (c) 2021 Giancamillo Alessandroni (NotManyIdeas#9972) and Ramon Santamaria (@raysan5) +* Copyright (c) 2021 Giancamillo Alessandroni (@NotManyIdeasDev) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ #include "raylib.h" -#include + +#include // Required for: sinf(), cosf() int main(void) { @@ -22,33 +23,32 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - const int virualScreenWidth = 160; + const int virtualScreenWidth = 160; const int virtualScreenHeight = 90; - const float virtualRatio = (float)screenWidth/(float)virualScreenWidth; + const float virtualRatio = (float)screenWidth/(float)virtualScreenWidth; InitWindow(screenWidth, screenHeight, "raylib [core] example - smooth pixel-perfect camera"); - Camera2D worldSpaceCamera = { 0 }; // Game world camera + Camera2D worldSpaceCamera = { 0 }; // Game world camera worldSpaceCamera.zoom = 1.0f; - Camera2D screenSpaceCamera = { 0 }; //Smoothing camera + Camera2D screenSpaceCamera = { 0 }; // Smoothing camera screenSpaceCamera.zoom = 1.0f; - RenderTexture2D renderTexture = LoadRenderTexture(virualScreenWidth, virtualScreenHeight); //This is where we'll draw all our objects. + RenderTexture2D target = LoadRenderTexture(virtualScreenWidth, virtualScreenHeight); // This is where we'll draw all our objects. - Rectangle firstRectangle = { 70.0f, 35.0f, 20.0f, 20.0f }; - Rectangle secondRectangle = { 90.0f, 55.0f, 30.0f, 10.0f }; - Rectangle thirdRectangle = { 80.0f, 65.0f, 15.0f, 25.0f }; + Rectangle rec01 = { 70.0f, 35.0f, 20.0f, 20.0f }; + Rectangle rec02 = { 90.0f, 55.0f, 30.0f, 10.0f }; + Rectangle rec03 = { 80.0f, 65.0f, 15.0f, 25.0f }; - //The renderTexture's height is flipped (in the source Rectangle), due to OpenGL reasons. - Rectangle renderTextureSource = { 0.0f, 0.0f, (float)renderTexture.texture.width, (float)-renderTexture.texture.height }; - Rectangle renderTextureDest = { -virtualRatio, -virtualRatio, screenWidth + (virtualRatio*2), screenHeight + (virtualRatio*2) }; + // The target's height is flipped (in the source Rectangle), due to OpenGL reasons + Rectangle sourceRec = { 0.0f, 0.0f, (float)target.texture.width, -(float)target.texture.height }; + Rectangle destRec = { -virtualRatio, -virtualRatio, screenWidth + (virtualRatio*2), screenHeight + (virtualRatio*2) }; Vector2 origin = { 0.0f, 0.0f }; float rotation = 0.0f; - float degreesPerSecond = 60.0f; float cameraX = 0.0f; float cameraY = 0.0f; @@ -61,16 +61,16 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - rotation += degreesPerSecond*GetFrameTime(); // Rotate the rectangles. + rotation += 60.0f*GetFrameTime(); // Rotate the rectangles, 60 degrees per second - // Make the camera move to demonstrate the effect. + // Make the camera move to demonstrate the effect cameraX = (sinf(GetTime())*50.0f) - 10.0f; cameraY = cosf(GetTime())*30.0f; - // Set the camera's target to the values computed above. + // Set the camera's target to the values computed above screenSpaceCamera.target = (Vector2){ cameraX, cameraY }; - //Round worldSpace coordinates, keep decimals into screenSpace coordinates. + // Round worldSpace coordinates, keep decimals into screenSpace coordinates worldSpaceCamera.target.x = (int)screenSpaceCamera.target.x; screenSpaceCamera.target.x -= worldSpaceCamera.target.x; screenSpaceCamera.target.x *= virtualRatio; @@ -83,47 +83,35 @@ int main(void) // Draw //---------------------------------------------------------------------------------- - BeginDrawing(); - ClearBackground(RED); // This is for debug purposes. If you see red, then you've probably done something wrong. - - BeginTextureMode(renderTexture); - BeginMode2D(worldSpaceCamera); - ClearBackground(RAYWHITE); // This is the color you should see as background color. - - // Draw the rectangles - DrawRectanglePro(firstRectangle, origin, rotation, BLACK); - DrawRectanglePro(secondRectangle, origin, -rotation, RED); - DrawRectanglePro(thirdRectangle, origin, rotation + 45.0f, BLUE); - - EndMode2D(); + BeginTextureMode(target); + ClearBackground(RAYWHITE); + + BeginMode2D(worldSpaceCamera); + DrawRectanglePro(rec01, origin, rotation, BLACK); + DrawRectanglePro(rec02, origin, -rotation, RED); + DrawRectanglePro(rec03, origin, rotation + 45.0f, BLUE); + EndMode2D(); EndTextureMode(); + + BeginDrawing(); + ClearBackground(RED); - BeginMode2D(screenSpaceCamera); + BeginMode2D(screenSpaceCamera); + DrawTexturePro(target.texture, sourceRec, destRec, origin, 0.0f, WHITE); + EndMode2D(); - // Draw the render texture with an offset of 1 worldSpace unit/pixel, so that the content behind the renderTexture is not shown. - DrawTexturePro( - renderTexture.texture, - renderTextureSource, - renderTextureDest, - origin, - 0.0f, - WHITE - ); - - EndMode2D(); - - //Debug info - DrawText("Screen resolution: 800x450", 5, 0, 20, DARKBLUE); - DrawText("World resolution: 160x90", 5, 20, 20, DARKGREEN); - DrawFPS(screenWidth - 75, 0); + DrawText(TextFormat("Screen resolution: %ix%i", screenWidth, screenHeight), 10, 10, 20, DARKBLUE); + DrawText(TextFormat("World resolution: %ix%i", virtualScreenWidth, virtualScreenHeight), 10, 40, 20, DARKGREEN); + DrawFPS(GetScreenWidth() - 95, 10); EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- - UnloadRenderTexture(renderTexture); // RenderTexture unloading - CloseWindow(); // Close window and OpenGL context + UnloadRenderTexture(target); // Unload render texture + + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; diff --git a/examples/core/core_2d_camera_smooth_pixelperfect.png b/examples/core/core_2d_camera_smooth_pixelperfect.png index aeac79446..ba8d89b7c 100644 Binary files a/examples/core/core_2d_camera_smooth_pixelperfect.png and b/examples/core/core_2d_camera_smooth_pixelperfect.png differ diff --git a/examples/core/core_custom_frame_control.c b/examples/core/core_custom_frame_control.c new file mode 100644 index 000000000..a3306d13b --- /dev/null +++ b/examples/core/core_custom_frame_control.c @@ -0,0 +1,125 @@ +/******************************************************************************************* +* +* raylib [core] example - custom frame control +* +* WARNING: This is an example for advance users willing to have full control over +* the frame processes. By default, EndDrawing() calls the following processes: +* 1. Draw remaining batch data: rlDrawRenderBatchActive() +* 2. SwapScreenBuffer() +* 3. Frame time control: WaitTime() +* 4. PollInputEvents() +* +* To avoid steps 2, 3 and 4, flag SUPPORT_CUSTOM_FRAME_CONTROL can be enabled in +* config.h (it requires recompiling raylib). This way those steps are up to the user. +* +* Note that enabling this flag invalidates some functions: +* - GetFrameTime() +* - SetTargetFPS() +* - GetFPS() +* +* This example has been created using raylib 3.8 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2021 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - custom frame control"); + + // Custom timming variables + double previousTime = GetTime(); // Previous time measure + double currentTime = 0.0; // Current time measure + double updateDrawTime = 0.0; // Update + Draw time + double waitTime = 0.0; // Wait time (if target fps required) + float deltaTime = 0.0f; // Frame time (Update + Draw + Wait time) + + float timeCounter = 0.0f; // Accumulative time counter (seconds) + float position = 0.0f; // Circle position + bool pause = false; // Pause control flag + + int targetFPS = 60; // Our initial target fps + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + PollInputEvents(); // Poll input events (SUPPORT_CUSTOM_FRAME_CONTROL) + + if (IsKeyPressed(KEY_SPACE)) pause = !pause; + + if (IsKeyPressed(KEY_UP)) targetFPS += 20; + else if (IsKeyPressed(KEY_DOWN)) targetFPS -= 20; + + if (targetFPS < 0) targetFPS = 0; + + if (!pause) + { + position += 200*deltaTime; // We move at 200 pixels per second + if (position >= GetScreenWidth()) position = 0; + timeCounter += deltaTime; // We count time (seconds) + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + for (int i = 0; i < GetScreenWidth()/200; i++) DrawRectangle(200*i, 0, 1, GetScreenHeight(), SKYBLUE); + + DrawCircle((int)position, GetScreenHeight()/2 - 25, 50, RED); + + DrawText(FormatText("%03.0f ms", timeCounter*1000.0f), position - 40, GetScreenHeight()/2 - 100, 20, MAROON); + DrawText(FormatText("PosX: %03.0f", position), position - 50, GetScreenHeight()/2 + 40, 20, BLACK); + + DrawText("Circle is moving at a constant 200 pixels/sec,\nindependently of the frame rate.", 10, 10, 20, DARKGRAY); + DrawText("PRESS SPACE to PAUSE MOVEMENT", 10, GetScreenHeight() - 60, 20, GRAY); + DrawText("PRESS UP | DOWN to CHANGE TARGET FPS", 10, GetScreenHeight() - 30, 20, GRAY); + DrawText(FormatText("TARGET FPS: %i", targetFPS), GetScreenWidth() - 220, 10, 20, LIME); + DrawText(FormatText("CURRENT FPS: %i", (int)(1.0f/deltaTime)), GetScreenWidth() - 220, 40, 20, GREEN); + + EndDrawing(); + + // NOTE: In case raylib is configured to SUPPORT_CUSTOM_FRAME_CONTROL, + // Events polling, screen buffer swap and frame time control must be managed by the user + + SwapScreenBuffer(); // Flip the back buffer to screen (front buffer) + + currentTime = GetTime(); + updateDrawTime = currentTime - previousTime; + + if (targetFPS > 0) // We want a fixed frame rate + { + waitTime = (1.0f/(float)targetFPS) - updateDrawTime; + if (waitTime > 0.0) + { + WaitTime((float)waitTime*1000.0f); + currentTime = GetTime(); + deltaTime = (float)(currentTime - previousTime); + } + } + else deltaTime = updateDrawTime; // Framerate could be variable + + previousTime = currentTime; + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/core/core_custom_frame_control.png b/examples/core/core_custom_frame_control.png new file mode 100644 index 000000000..7d615efe2 Binary files /dev/null and b/examples/core/core_custom_frame_control.png differ diff --git a/examples/core/core_rotate_by_quat.c b/examples/core/core_rotate_by_quat.c new file mode 100644 index 000000000..a3ca6533d --- /dev/null +++ b/examples/core/core_rotate_by_quat.c @@ -0,0 +1,83 @@ +#include "raylib.h" +#include "rlgl.h" // just to change line width +#include "raymath.h" + +#define windowWidth 1280 +#define windowHeight 720 + +Vector3 Vector3MultiplyQuaternion(Vector3 v, Quaternion q) +{ + Vector3 r, qv, uv, uuv; + + qv.x = q.x; + qv.y = q.y; + qv.z = q.z; + + uv = Vector3CrossProduct(qv, v); + uuv = Vector3CrossProduct(qv, uv); + + uv = Vector3Scale(uv, 2.f*q.w); + uuv = Vector3Scale(uuv, 2.0f); + + r = Vector3Add(v, uv); + r = Vector3Add(r, uuv); + + return r; +} + +int main(void) +{ + SetTraceLogLevel( LOG_ALL ); + SetConfigFlags( FLAG_VSYNC_HINT | FLAG_MSAA_4X_HINT ); + InitWindow( windowWidth, windowHeight, "Raylib - template" ); + + Camera camera = { 0 }; + camera.position = (Vector3){ 0.0f, 1.0f, 4.0f }; + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; + camera.fovy = 45.0f; + camera.projection = CAMERA_PERSPECTIVE; + + Vector3 ang = { 0 }; + Vector3 qv = { 0 }; + Vector3 mv = { 0 }; + Vector3 bv = { 0 }; + Quaternion q; + + float dT = 0; + + rlSetLineWidth(4); + while ( !WindowShouldClose() ) + { + dT = GetFrameTime(); + + ang.x += .7f * dT; + ang.y += .55 * dT; + ang.z -= 2.75 * dT; + + q = QuaternionFromEuler(ang.x, ang.y, ang.z); + qv = Vector3MultiplyQuaternion((Vector3){0,0,1}, q); + + Matrix m = QuaternionToMatrix(q); + mv = Vector3Transform((Vector3){0,0,1},m); + + bv = Vector3RotateByQuaternion((Vector3){0,0,1}, q); + + BeginDrawing(); + ClearBackground( (Color){64,128,255,255} ); + + BeginMode3D( camera ); + DrawLine3D((Vector3){0,0,0}, qv, GREEN); + DrawLine3D((Vector3){-.1,0,0}, mv, YELLOW); + DrawLine3D((Vector3){.1,0,0}, bv, RED); + + DrawGrid( 10, 1.0f ); + + EndMode3D(); + + EndDrawing(); + } + + CloseWindow(); + return 0; +} \ No newline at end of file diff --git a/examples/core/core_split_screen.c b/examples/core/core_split_screen.c index 0bfdb84ac..31c3fb4bf 100644 --- a/examples/core/core_split_screen.c +++ b/examples/core/core_split_screen.c @@ -89,7 +89,7 @@ int main(void) // this moves thigns at 10 world units per second, regardless of the actual FPS float offsetThisFrame = 10.0f*GetFrameTime(); - // Move player 1 forward and backwards (no turning) + // Move Player1 forward and backwards (no turning) if (IsKeyDown(KEY_W)) { cameraPlayer1.position.z += offsetThisFrame; @@ -101,7 +101,7 @@ int main(void) cameraPlayer1.target.z -= offsetThisFrame; } - // Move player 2 forward and backwards (no turning) + // Move Player2 forward and backwards (no turning) if (IsKeyDown(KEY_UP)) { cameraPlayer2.position.x += offsetThisFrame; @@ -116,7 +116,7 @@ int main(void) // Draw //---------------------------------------------------------------------------------- - // Draw player 1's view to the render texture + // Draw Player1 view to the render texture BeginTextureMode(screenPlayer1); ClearBackground(SKYBLUE); BeginMode3D(cameraPlayer1); @@ -125,7 +125,7 @@ int main(void) DrawText("PLAYER1 W/S to move", 0, 0, 20, RED); EndTextureMode(); - // Draw player 2's view to the render texture + // Draw Player2 view to the render texture BeginTextureMode(screenPlayer2); ClearBackground(SKYBLUE); BeginMode3D(cameraPlayer2); @@ -134,21 +134,21 @@ int main(void) DrawText("PLAYER2 UP/DOWN to move", 0, 0, 20, BLUE); EndTextureMode(); - // Draw both view render textures to the screen side by side + // Draw both views render textures to the screen side by side BeginDrawing(); ClearBackground(BLACK); - DrawTextureRec(screenPlayer1.texture, splitScreenRect, (Vector2) { 0, 0 }, WHITE); - DrawTextureRec(screenPlayer2.texture, splitScreenRect, (Vector2) { screenWidth/2.0f, 0 }, WHITE); + DrawTextureRec(screenPlayer1.texture, splitScreenRect, (Vector2){ 0, 0 }, WHITE); + DrawTextureRec(screenPlayer2.texture, splitScreenRect, (Vector2){ screenWidth/2.0f, 0 }, WHITE); EndDrawing(); } // De-Initialization //-------------------------------------------------------------------------------------- - UnloadRenderTexture(screenPlayer1); - UnloadRenderTexture(screenPlayer2); - UnloadTexture(textureGrid); + UnloadRenderTexture(screenPlayer1); // Unload render texture + UnloadRenderTexture(screenPlayer2); // Unload render texture + UnloadTexture(textureGrid); // Unload texture - CloseWindow(); // Close window and OpenGL context + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; diff --git a/examples/core/core_vr_simulator.c b/examples/core/core_vr_simulator.c index bba90b823..65f0dec65 100644 --- a/examples/core/core_vr_simulator.c +++ b/examples/core/core_vr_simulator.c @@ -105,30 +105,26 @@ int main(void) // Draw //---------------------------------------------------------------------------------- - BeginDrawing(); - + BeginTextureMode(target); ClearBackground(RAYWHITE); + BeginVrStereoMode(config); + BeginMode3D(camera); - BeginTextureMode(target); - ClearBackground(RAYWHITE); - BeginVrStereoMode(config); - BeginMode3D(camera); - - DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); - DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, MAROON); - DrawGrid(40, 1.0f); - - EndMode3D(); - EndVrStereoMode(); - EndTextureMode(); + DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); + DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, MAROON); + DrawGrid(40, 1.0f); + EndMode3D(); + EndVrStereoMode(); + EndTextureMode(); + + BeginDrawing(); + ClearBackground(RAYWHITE); BeginShaderMode(distortion); DrawTextureRec(target.texture, (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, (Vector2){ 0.0f, 0.0f }, WHITE); EndShaderMode(); - DrawFPS(10, 10); - EndDrawing(); //---------------------------------------------------------------------------------- } diff --git a/examples/core/core_window_letterbox.c b/examples/core/core_window_letterbox.c index 2c3af6df6..2933ca422 100644 --- a/examples/core/core_window_letterbox.c +++ b/examples/core/core_window_letterbox.c @@ -48,11 +48,11 @@ int main(void) Color colors[10] = { 0 }; for (int i = 0; i < 10; i++) colors[i] = (Color){ GetRandomValue(100, 250), GetRandomValue(50, 150), GetRandomValue(10, 100), 255 }; - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- @@ -79,37 +79,33 @@ int main(void) // Draw //---------------------------------------------------------------------------------- + // Draw everything in the render texture, note this will not be rendered on screen, yet + BeginTextureMode(target); + ClearBackground(RAYWHITE); // Clear render texture background color + + for (int i = 0; i < 10; i++) DrawRectangle(0, (gameScreenHeight/10)*i, gameScreenWidth, gameScreenHeight/10, colors[i]); + + DrawText("If executed inside a window,\nyou can resize the window,\nand see the screen scaling!", 10, 25, 20, WHITE); + DrawText(TextFormat("Default Mouse: [%i , %i]", (int)mouse.x, (int)mouse.y), 350, 25, 20, GREEN); + DrawText(TextFormat("Virtual Mouse: [%i , %i]", (int)virtualMouse.x, (int)virtualMouse.y), 350, 55, 20, YELLOW); + EndTextureMode(); + BeginDrawing(); - ClearBackground(BLACK); + ClearBackground(BLACK); // Clear screen background - // Draw everything in the render texture, note this will not be rendered on screen, yet - BeginTextureMode(target); - - ClearBackground(RAYWHITE); // Clear render texture background color - - for (int i = 0; i < 10; i++) DrawRectangle(0, (gameScreenHeight/10)*i, gameScreenWidth, gameScreenHeight/10, colors[i]); - - DrawText("If executed inside a window,\nyou can resize the window,\nand see the screen scaling!", 10, 25, 20, WHITE); - - DrawText(TextFormat("Default Mouse: [%i , %i]", (int)mouse.x, (int)mouse.y), 350, 25, 20, GREEN); - DrawText(TextFormat("Virtual Mouse: [%i , %i]", (int)virtualMouse.x, (int)virtualMouse.y), 350, 55, 20, YELLOW); - - EndTextureMode(); - - // Draw RenderTexture2D to window, properly scaled + // Draw render texture to screen, properly scaled DrawTexturePro(target.texture, (Rectangle){ 0.0f, 0.0f, (float)target.texture.width, (float)-target.texture.height }, (Rectangle){ (GetScreenWidth() - ((float)gameScreenWidth*scale))*0.5f, (GetScreenHeight() - ((float)gameScreenHeight*scale))*0.5f, (float)gameScreenWidth*scale, (float)gameScreenHeight*scale }, (Vector2){ 0, 0 }, 0.0f, WHITE); - EndDrawing(); //-------------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- - UnloadRenderTexture(target); // Unload render texture + UnloadRenderTexture(target); // Unload render texture - CloseWindow(); // Close window and OpenGL context + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; diff --git a/examples/examples_template.c b/examples/examples_template.c index 8dc31706d..f17411045 100644 --- a/examples/examples_template.c +++ b/examples/examples_template.c @@ -41,16 +41,18 @@ * * raylib [core] example - Basic window * -* This example has been created using raylib 2.5 (www.raylib.com) +* This example has been created using raylib 3.8 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2019 Ramon Santamaria (@raysan5) +* Example contributed by (@) and reviewed by Ramon Santamaria (@raysan5) +* +* Copyright (c) 2021 (@) * ********************************************************************************************/ #include "raylib.h" -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_gltf_model.c b/examples/models/models_gltf_model.c index f19006d99..3f843c9d4 100644 --- a/examples/models/models_gltf_model.c +++ b/examples/models/models_gltf_model.c @@ -99,7 +99,7 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- - for(int i = 0; i < MAX_MODELS; i++) UnloadModel(model[i]); // Unload models + for (int i = 0; i < MAX_MODELS; i++) UnloadModel(model[i]); // Unload models CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/others/rlgl_standalone.c b/examples/others/rlgl_standalone.c index 47233afd8..0a5cb5096 100644 --- a/examples/others/rlgl_standalone.c +++ b/examples/others/rlgl_standalone.c @@ -65,6 +65,14 @@ #define RAYWHITE (Color){ 245, 245, 245, 255 } // My own White (raylib logo) #define DARKGRAY (Color){ 80, 80, 80, 255 } // Dark Gray +// Color, 4 components, R8G8B8A8 (32bit) +typedef struct Color { + unsigned char r; // Color red value + unsigned char g; // Color green value + unsigned char b; // Color blue value + unsigned char a; // Color alpha value +} Color; + // Camera type, defines a camera position/orientation in 3d space typedef struct Camera { Vector3 position; // Camera position @@ -271,7 +279,7 @@ static void DrawGrid(int slices, float spacing) int halfSlices = slices / 2; rlBegin(RL_LINES); - for(int i = -halfSlices; i <= halfSlices; i++) + for (int i = -halfSlices; i <= halfSlices; i++) { if (i == 0) { diff --git a/examples/shaders/shaders_custom_uniform.c b/examples/shaders/shaders_custom_uniform.c index 6efda727b..60516c110 100644 --- a/examples/shaders/shaders_custom_uniform.c +++ b/examples/shaders/shaders_custom_uniform.c @@ -65,11 +65,11 @@ int main(void) // Setup orbital camera SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- @@ -81,55 +81,46 @@ int main(void) // Send new value to the shader to be used on drawing SetShaderValue(shader, swirlCenterLoc, swirlCenter, SHADER_UNIFORM_VEC2); - UpdateCamera(&camera); // Update camera + UpdateCamera(&camera); // Update camera //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- + BeginTextureMode(target); // Enable drawing to texture + ClearBackground(RAYWHITE); // Clear texture background + + BeginMode3D(camera); // Begin 3d mode drawing + DrawModel(model, position, 0.5f, WHITE); // Draw 3d model with texture + DrawGrid(10, 1.0f); // Draw a grid + EndMode3D(); // End 3d mode drawing, returns to orthographic 2d mode + + DrawText("TEXT DRAWN IN RENDER TEXTURE", 200, 10, 30, RED); + EndTextureMode(); // End drawing to texture (now we have a texture available for next passes) + BeginDrawing(); + ClearBackground(RAYWHITE); // Clear screen background - ClearBackground(RAYWHITE); - - BeginTextureMode(target); // Enable drawing to texture - - ClearBackground(RAYWHITE); // Clear texture background - - BeginMode3D(camera); // Begin 3d mode drawing - - DrawModel(model, position, 0.5f, WHITE); // Draw 3d model with texture - - DrawGrid(10, 1.0f); // Draw a grid - - EndMode3D(); // End 3d mode drawing, returns to orthographic 2d mode - - DrawText("TEXT DRAWN IN RENDER TEXTURE", 200, 10, 30, RED); - - EndTextureMode(); // End drawing to texture (now we have a texture available for next passes) - + // Enable shader using the custom uniform BeginShaderMode(shader); - // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) DrawTextureRec(target.texture, (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, (Vector2){ 0, 0 }, WHITE); - EndShaderMode(); // Draw some 2d text over drawn texture DrawText("(c) Barracks 3D model by Alberto Cano", screenWidth - 220, screenHeight - 20, 10, GRAY); - DrawFPS(10, 10); - EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- - UnloadShader(shader); // Unload shader - UnloadTexture(texture); // Unload texture - UnloadModel(model); // Unload model - UnloadRenderTexture(target); // Unload render texture + UnloadShader(shader); // Unload shader + UnloadTexture(texture); // Unload texture + UnloadModel(model); // Unload model + UnloadRenderTexture(target); // Unload render texture - CloseWindow(); // Close window and OpenGL context + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; diff --git a/examples/shaders/shaders_eratosthenes.c b/examples/shaders/shaders_eratosthenes.c index d5163a7f6..65fd9f980 100644 --- a/examples/shaders/shaders_eratosthenes.c +++ b/examples/shaders/shaders_eratosthenes.c @@ -46,11 +46,11 @@ int main(void) // NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader Shader shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/eratosthenes.fs", GLSL_VERSION)); - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- @@ -59,35 +59,33 @@ int main(void) // Draw //---------------------------------------------------------------------------------- + BeginTextureMode(target); // Enable drawing to texture + ClearBackground(BLACK); // Clear the render texture + + // Draw a rectangle in shader mode to be used as shader canvas + // NOTE: Rectangle uses font white character texture coordinates, + // so shader can not be applied here directly because input vertexTexCoord + // do not represent full screen coordinates (space where want to apply shader) + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK); + EndTextureMode(); // End drawing to texture (now we have a blank texture available for the shader) + BeginDrawing(); - - ClearBackground(RAYWHITE); - - BeginTextureMode(target); // Enable drawing to texture - ClearBackground(BLACK); // Clear the render texture - - // Draw a rectangle in shader mode to be used as shader canvas - // NOTE: Rectangle uses font white character texture coordinates, - // so shader can not be applied here directly because input vertexTexCoord - // do not represent full screen coordinates (space where want to apply shader) - DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK); - EndTextureMode(); // End drawing to texture (now we have a blank texture available for the shader) + ClearBackground(RAYWHITE); // Clear screen background BeginShaderMode(shader); // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) DrawTextureRec(target.texture, (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, (Vector2){ 0.0f, 0.0f }, WHITE); EndShaderMode(); - EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- - UnloadShader(shader); // Unload shader - UnloadRenderTexture(target); // Unload texture + UnloadShader(shader); // Unload shader + UnloadRenderTexture(target); // Unload render texture - CloseWindow(); // Close window and OpenGL context + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; diff --git a/examples/shaders/shaders_julia_set.c b/examples/shaders/shaders_julia_set.c index 4a12ba02e..90c44cf58 100644 --- a/examples/shaders/shaders_julia_set.c +++ b/examples/shaders/shaders_julia_set.c @@ -75,15 +75,15 @@ int main(void) SetShaderValue(shader, zoomLoc, &zoom, SHADER_UNIFORM_FLOAT); SetShaderValue(shader, offsetLoc, offset, SHADER_UNIFORM_VEC2); - int incrementSpeed = 0; // Multiplier of speed to change c value - bool showControls = true; // Show controls - bool pause = false; // Pause animation + int incrementSpeed = 0; // Multiplier of speed to change c value + bool showControls = true; // Show controls + bool pause = false; // Pause animation - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- @@ -145,20 +145,19 @@ int main(void) // Draw //---------------------------------------------------------------------------------- + // Using a render texture to draw Julia set + BeginTextureMode(target); // Enable drawing to texture + ClearBackground(BLACK); // Clear the render texture + + // Draw a rectangle in shader mode to be used as shader canvas + // NOTE: Rectangle uses font white character texture coordinates, + // so shader can not be applied here directly because input vertexTexCoord + // do not represent full screen coordinates (space where want to apply shader) + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK); + EndTextureMode(); + BeginDrawing(); - - ClearBackground(BLACK); // Clear the screen of the previous frame. - - // Using a render texture to draw Julia set - BeginTextureMode(target); // Enable drawing to texture - ClearBackground(BLACK); // Clear the render texture - - // Draw a rectangle in shader mode to be used as shader canvas - // NOTE: Rectangle uses font white character texture coordinates, - // so shader can not be applied here directly because input vertexTexCoord - // do not represent full screen coordinates (space where want to apply shader) - DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK); - EndTextureMode(); + ClearBackground(BLACK); // Clear screen background // Draw the saved texture and rendered julia set with shader // NOTE: We do not invert texture on Y, already considered inside shader @@ -176,17 +175,16 @@ int main(void) DrawText("Press KEY_LEFT | KEY_RIGHT to change speed", 10, 60, 10, RAYWHITE); DrawText("Press KEY_SPACE to pause movement animation", 10, 75, 10, RAYWHITE); } - EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- - UnloadShader(shader); // Unload shader - UnloadRenderTexture(target); // Unload render texture + UnloadShader(shader); // Unload shader + UnloadRenderTexture(target); // Unload render texture - CloseWindow(); // Close window and OpenGL context + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; diff --git a/examples/shaders/shaders_postprocessing.c b/examples/shaders/shaders_postprocessing.c index ef815391b..ebe5fcdb4 100644 --- a/examples/shaders/shaders_postprocessing.c +++ b/examples/shaders/shaders_postprocessing.c @@ -124,50 +124,38 @@ int main(void) // Draw //---------------------------------------------------------------------------------- + BeginTextureMode(target); // Enable drawing to texture + ClearBackground(RAYWHITE); // Clear texture background + + BeginMode3D(camera); // Begin 3d mode drawing + DrawModel(model, position, 0.1f, WHITE); // Draw 3d model with texture + DrawGrid(10, 1.0f); // Draw a grid + EndMode3D(); // End 3d mode drawing, returns to orthographic 2d mode + EndTextureMode(); // End drawing to texture (now we have a texture available for next passes) + BeginDrawing(); + ClearBackground(RAYWHITE); // Clear screen background - ClearBackground(RAYWHITE); - - BeginTextureMode(target); // Enable drawing to texture - - ClearBackground(RAYWHITE); // Clear texture background - - BeginMode3D(camera); // Begin 3d mode drawing - - DrawModel(model, position, 0.1f, WHITE); // Draw 3d model with texture - - DrawGrid(10, 1.0f); // Draw a grid - - EndMode3D(); // End 3d mode drawing, returns to orthographic 2d mode - - EndTextureMode(); // End drawing to texture (now we have a texture available for next passes) - - // Render previously generated texture using selected postpro shader + // Render generated texture using selected postprocessing shader BeginShaderMode(shaders[currentShader]); - // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) DrawTextureRec(target.texture, (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, (Vector2){ 0, 0 }, WHITE); - EndShaderMode(); // Draw 2d shapes and text over drawn texture DrawRectangle(0, 9, 580, 30, Fade(LIGHTGRAY, 0.7f)); DrawText("(c) Church 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, GRAY); - DrawText("CURRENT POSTPRO SHADER:", 10, 15, 20, BLACK); DrawText(postproShaderText[currentShader], 330, 15, 20, RED); DrawText("< >", 540, 10, 30, DARKBLUE); - DrawFPS(700, 15); - EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- - // Unload all postpro shaders for (int i = 0; i < MAX_POSTPRO_SHADERS; i++) UnloadShader(shaders[i]); diff --git a/examples/text/text_draw_3d.c b/examples/text/text_draw_3d.c index a579a528b..8ce576b6b 100644 --- a/examples/text/text_draw_3d.c +++ b/examples/text/text_draw_3d.c @@ -291,7 +291,7 @@ int main(void) for (int i = 0; i < layers; ++i) { Color clr = light; - if(multicolor) clr = multi[i]; + if (multicolor) clr = multi[i]; DrawTextWave3D(font, text, (Vector3){ -tbox.x/2.0f, layerDistance*i, -4.5f }, fontSize, fontSpacing, lineSpacing, true, &wcfg, time, clr); } @@ -465,7 +465,7 @@ void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontS float width = (float)(font.recs[index].width + 2.0f*font.charsPadding)/(float)font.baseSize*scale; float height = (float)(font.recs[index].height + 2.0f*font.charsPadding)/(float)font.baseSize*scale; - if(font.texture.id > 0) + if (font.texture.id > 0) { const float x = 0.0f; const float y = 0.0f; @@ -477,7 +477,7 @@ void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontS const float tw = (srcRec.x+srcRec.width)/font.texture.width; const float th = (srcRec.y+srcRec.height)/font.texture.height; - if(SHOW_LETTER_BOUNDRY) + if (SHOW_LETTER_BOUNDRY) DrawCubeWiresV((Vector3){ position.x + width/2, position.y, position.z + height/2}, (Vector3){ width, LETTER_BOUNDRY_SIZE, height }, LETTER_BOUNDRY_COLOR); #if defined(RAYLIB_NEW_RLGL) @@ -533,7 +533,7 @@ void DrawText3D(Font font, const char *text, Vector3 position, float fontSize, f { // Get next codepoint from byte string and glyph index in font int codepointByteCount = 0; - int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); + int codepoint = GetCodepoint(&text[i], &codepointByteCount); int index = GetGlyphIndex(font, codepoint); // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) @@ -582,7 +582,7 @@ Vector3 MeasureText3D(Font font, const char* text, float fontSize, float fontSpa lenCounter++; int next = 0; - letter = GetNextCodepoint(&text[i], &next); + letter = GetCodepoint(&text[i], &next); index = GetGlyphIndex(font, letter); // NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) @@ -632,7 +632,7 @@ void DrawTextWave3D(Font font, const char *text, Vector3 position, float fontSiz { // Get next codepoint from byte string and glyph index in font int codepointByteCount = 0; - int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); + int codepoint = GetCodepoint(&text[i], &codepointByteCount); int index = GetGlyphIndex(font, codepoint); // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) @@ -649,7 +649,7 @@ void DrawTextWave3D(Font font, const char *text, Vector3 position, float fontSiz } else if (codepoint == '~') { - if (GetNextCodepoint(&text[i+1], &codepointByteCount) == '~') + if (GetCodepoint(&text[i+1], &codepointByteCount) == '~') { codepointByteCount += 1; wave = !wave; @@ -698,7 +698,7 @@ Vector3 MeasureTextWave3D(Font font, const char* text, float fontSize, float fon lenCounter++; int next = 0; - letter = GetNextCodepoint(&text[i], &next); + letter = GetCodepoint(&text[i], &next); index = GetGlyphIndex(font, letter); // NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) @@ -708,7 +708,7 @@ Vector3 MeasureTextWave3D(Font font, const char* text, float fontSize, float fon if (letter != '\n') { - if(letter == '~' && GetNextCodepoint(&text[i+1], &next) == '~') + if (letter == '~' && GetCodepoint(&text[i+1], &next) == '~') { i++; } diff --git a/projects/Geany/raylib.c.tags b/projects/Geany/raylib.c.tags index 1b47efdd7..78e6e7241 100644 --- a/projects/Geany/raylib.c.tags +++ b/projects/Geany/raylib.c.tags @@ -298,7 +298,7 @@ GenMeshTorus|Mesh|(float radius, float size, int radSeg, int sides);| GenMeshKnot|Mesh|(float radius, float size, int radSeg, int sides);| GenMeshHeightmap|Mesh|(Image heightmap, Vector3 size);| GenMeshCubicmap|Mesh|(Image cubicmap, Vector3 cubeSize);| -MeshBoundingBox|BoundingBox|(Mesh mesh);| +GetMeshBoundingBox|BoundingBox|(Mesh mesh);| MeshTangents|void|(Mesh *mesh);| MeshBinormals|void|(Mesh *mesh);| DrawModel|void|(Model model, Vector3 position, float scale, Color tint);| diff --git a/projects/Notepad++/c_raylib.xml b/projects/Notepad++/c_raylib.xml index 8deab87ef..497fb7b82 100644 --- a/projects/Notepad++/c_raylib.xml +++ b/projects/Notepad++/c_raylib.xml @@ -1549,7 +1549,7 @@ - + diff --git a/projects/Notepad++/raylib_npp_parser/raylib_npp.xml b/projects/Notepad++/raylib_npp_parser/raylib_npp.xml index 2c8bafb5e..b59fed57f 100644 --- a/projects/Notepad++/raylib_npp_parser/raylib_npp.xml +++ b/projects/Notepad++/raylib_npp_parser/raylib_npp.xml @@ -2495,7 +2495,7 @@ - + diff --git a/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h b/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h index 8079f5c78..f7f252975 100644 --- a/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h +++ b/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h @@ -515,7 +515,7 @@ RLAPI Mesh GenMeshHeightmap(Image heightmap, Vector3 size); RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); // Generate cubes-based map mesh from image data // Mesh manipulation functions -RLAPI BoundingBox MeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits +RLAPI BoundingBox GetMeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits RLAPI void MeshTangents(Mesh *mesh); // Compute mesh tangents RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals diff --git a/src/config.h b/src/config.h index 7c4777af6..6479d409a 100644 --- a/src/config.h +++ b/src/config.h @@ -37,7 +37,7 @@ // Reconfigure standard input to receive key inputs, works with SSH connection. #define SUPPORT_SSH_KEYBOARD_RPI 1 // Draw a mouse pointer on screen -#define SUPPORT_MOUSE_CURSOR_NATIVE 1 +//#define SUPPORT_MOUSE_CURSOR_POINT 1 // Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. // However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. #define SUPPORT_WINMM_HIGHRES_TIMER 1 @@ -56,7 +56,11 @@ // Support saving binary data automatically to a generated storage.data file. This file is managed internally. #define SUPPORT_DATA_STORAGE 1 // Support automatic generated events, loading and recording of those events when required -#define SUPPORT_EVENTS_AUTOMATION 1 +//#define SUPPORT_EVENTS_AUTOMATION 1 +// Support custom frame control, only for advance users +// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timming + PollInputEvents() +// Enabling this flag allows manual control of the frame processes, use at your own risk +//#define SUPPORT_CUSTOM_FRAME_CONTROL 1 // core: Configuration values //------------------------------------------------------------------------------------ @@ -161,7 +165,6 @@ //------------------------------------------------------------------------------------ #define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions: // TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit() -#define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints: GetCodepoints() #define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit() diff --git a/src/core.c b/src/core.c index 77a8d47e7..e711e4ec8 100644 --- a/src/core.c +++ b/src/core.c @@ -56,7 +56,7 @@ * WARNING: Reconfiguring standard input could lead to undesired effects, like breaking other running processes or * blocking the device is not restored properly. Use with care. * -* #define SUPPORT_MOUSE_CURSOR_NATIVE (Raspberry Pi and DRM only) +* #define SUPPORT_MOUSE_CURSOR_POINT * Draw a mouse pointer on screen * * #define SUPPORT_BUSY_WAIT_LOOP @@ -387,7 +387,7 @@ typedef struct CoreData { Point position; // Window position on screen (required on fullscreen toggle) Size display; // Display width and height (monitor, device-screen, LCD, ...) Size screen; // Screen width and height (used render area) - Size currentFbo; // Current render width and height, it could change on BeginTextureMode() + Size currentFbo; // Current render width and height (depends on active fbo) Size render; // Framebuffer width and height (render area, including black bars if required) Point renderOffset; // Offset from render area (must be divided by 2) Matrix screenScale; // Matrix to scale screen (framebuffer rendering) @@ -599,15 +599,10 @@ extern void UnloadFontDefault(void); // [Module: text] Unloads default fo //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- +static void InitTimer(void); // Initialize timer (hi-resolution if available) static bool InitGraphicsDevice(int width, int height); // Initialize graphics device static void SetupFramebuffer(int width, int height); // Setup main framebuffer static void SetupViewport(int width, int height); // Set viewport for a provided width and height -static void SwapBuffers(void); // Copy back buffer to front buffer - -static void InitTimer(void); // Initialize timer -static void Wait(float ms); // Wait for some milliseconds (stop program execution) - -static void PollInputEvents(void); // Register user events #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error @@ -636,6 +631,8 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) #if defined(PLATFORM_WEB) static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData); static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData); +static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *e, void *userData); + #endif #if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) @@ -673,7 +670,7 @@ static void PlayAutomationEvent(unsigned int frame); #if defined(_WIN32) // NOTE: We include Sleep() function signature here to avoid windows.h inclusion (kernel32 lib) - void __stdcall Sleep(unsigned long msTimeout); // Required for Wait() + void __stdcall Sleep(unsigned long msTimeout); // Required for WaitTime() #endif //---------------------------------------------------------------------------------- @@ -843,6 +840,9 @@ void InitWindow(int width, int height, const char *title) // Init hi-res timer InitTimer(); + + // Initialize random seed + srand((unsigned int)time(NULL)); #if defined(SUPPORT_DEFAULT_FONT) // Load default font @@ -875,10 +875,14 @@ void InitWindow(int width, int height, const char *title) #endif #if defined(PLATFORM_WEB) - // Check fullscreen change events - //emscripten_set_fullscreenchange_callback("#canvas", NULL, 1, EmscriptenFullscreenChangeCallback); - //emscripten_set_resize_callback("#canvas", NULL, 1, EmscriptenResizeCallback); - + // 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); + // Check Resize event (note this is done on the window since most browsers + // don't support this on #canvas) + emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback); + // Trigger this once to get initial window sizing + EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL); // Support keyboard events //emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback); //emscripten_set_keydown_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback); @@ -1556,7 +1560,7 @@ void SetWindowMinSize(int width, int height) // TODO: Issues on HighDPI scaling void SetWindowSize(int width, int height) { -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) glfwSetWindowSize(CORE.Window.handle, width, height); #endif #if defined(PLATFORM_WEB) @@ -1938,7 +1942,10 @@ void ClearBackground(Color color) // Setup canvas (framebuffer) to start drawing void BeginDrawing(void) { - CORE.Time.current = GetTime(); // Number of elapsed seconds since InitTimer() + // WARNING: Previously to BeginDrawing() other render textures drawing could happen, + // consequently the measure for update vs draw is not accurate (only the total frame time is accurate) + + CORE.Time.current = GetTime(); // Number of elapsed seconds since InitTimer() CORE.Time.update = CORE.Time.current - CORE.Time.previous; CORE.Time.previous = CORE.Time.current; @@ -1952,22 +1959,22 @@ void BeginDrawing(void) // End canvas drawing and swap buffers (double buffering) void EndDrawing(void) { -#if (defined(PLATFORM_RPI) || defined(PLATFORM_DRM)) && defined(SUPPORT_MOUSE_CURSOR_NATIVE) - // On native mode we have no system mouse cursor, so, - // we draw a small rectangle for user reference + rlDrawRenderBatchActive(); // Update and draw internal render batch + +#if defined(SUPPORT_MOUSE_CURSOR_POINT) + // Draw a small rectangle on mouse position for user reference if (!CORE.Input.Mouse.cursorHidden) { DrawRectangle(CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y, 3, 3, MAROON); + rlDrawRenderBatchActive(); // Update and draw internal render batch } #endif - rlDrawRenderBatchActive(); // Update and draw internal render batch - #if defined(SUPPORT_GIF_RECORDING) - #define GIF_RECORD_FRAMERATE 10 - + // Draw record indicator if (gifRecording) { + #define GIF_RECORD_FRAMERATE 10 gifFramesCounter++; // NOTE: We record one gif frame every 10 game frames @@ -1992,6 +1999,7 @@ void EndDrawing(void) #endif #if defined(SUPPORT_EVENTS_AUTOMATION) + // Draw record/play indicator if (eventsRecording) { gifFramesCounter++; @@ -2018,7 +2026,8 @@ void EndDrawing(void) } #endif - SwapBuffers(); // Copy back buffer to front buffer +#if !defined(SUPPORT_CUSTOM_FRAME_CONTROL) + SwapScreenBuffer(); // Copy back buffer to front buffer (screen) // Frame time control system CORE.Time.current = GetTime(); @@ -2030,7 +2039,7 @@ void EndDrawing(void) // Wait for some milliseconds... if (CORE.Time.frame < CORE.Time.target) { - Wait((float)(CORE.Time.target - CORE.Time.frame)*1000.0f); + WaitTime((float)(CORE.Time.target - CORE.Time.frame)*1000.0f); CORE.Time.current = GetTime(); double waitTime = CORE.Time.current - CORE.Time.previous; @@ -2039,14 +2048,15 @@ void EndDrawing(void) CORE.Time.frame += waitTime; // Total frame time: update + draw + wait } - PollInputEvents(); // Poll user events + PollInputEvents(); // Poll user events (before next frame update) +#endif #if defined(SUPPORT_EVENTS_AUTOMATION) + // Events recording and playing logic if (eventsRecording) RecordAutomationEvent(CORE.Time.frameCounter); - - // TODO: When should we play? After/before/replace PollInputEvents()? - if (eventsPlaying) + else if (eventsPlaying) { + // TODO: When should we play? After/before/replace PollInputEvents()? if (CORE.Time.frameCounter >= eventCount) eventsPlaying = false; PlayAutomationEvent(CORE.Time.frameCounter); } @@ -2638,6 +2648,9 @@ void SetTargetFPS(int fps) // NOTE: We calculate an average framerate int GetFPS(void) { + int fps = 0; + +#if !defined(SUPPORT_CUSTOM_FRAME_CONTROL) #define FPS_CAPTURE_FRAMES_COUNT 30 // 30 captures #define FPS_AVERAGE_TIME_SECONDS 0.5f // 500 millisecondes #define FPS_STEP (FPS_AVERAGE_TIME_SECONDS/FPS_CAPTURE_FRAMES_COUNT) @@ -2658,7 +2671,10 @@ int GetFPS(void) average += history[index]; } - return (int)roundf(1.0f/average); + fps = (int)roundf(1.0f/average); +#endif + + return fps; } // Get time in seconds for last frame drawn (delta time) @@ -3540,6 +3556,17 @@ Vector2 GetMousePosition(void) return position; } +// Get mouse delta between frames +Vector2 GetMouseDelta(void) +{ + Vector2 delta = {0}; + + delta.x = CORE.Input.Mouse.currentPosition.x - CORE.Input.Mouse.previousPosition.x; + delta.y = CORE.Input.Mouse.currentPosition.y - CORE.Input.Mouse.previousPosition.y; + + return delta; +} + // Set mouse position XY void SetMousePosition(int x, int y) { @@ -4661,8 +4688,6 @@ static void SetupFramebuffer(int width, int height) // Initialize hi-resolution timer static void InitTimer(void) { - srand((unsigned int)time(NULL)); // Initialize random seed - // Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. // However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. // High resolutions can also prevent the CPU power management system from entering power-saving modes. @@ -4689,7 +4714,7 @@ static void InitTimer(void) // take longer than expected... for that reason we use the busy wait loop // Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected // Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timming on Win32! -static void Wait(float ms) +void WaitTime(float ms) { #if defined(PLATFORM_UWP) UWPGetSleepFunc()(ms/1000); @@ -4737,8 +4762,70 @@ static void Wait(float ms) #endif } -// Poll (store) all input events -static void PollInputEvents(void) +// Swap back buffer with front buffer (screen drawing) +void SwapScreenBuffer(void) +{ +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) + glfwSwapBuffers(CORE.Window.handle); +#endif + +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) + eglSwapBuffers(CORE.Window.device, CORE.Window.surface); + +#if defined(PLATFORM_DRM) + if (!CORE.Window.gbmSurface || (-1 == CORE.Window.fd) || !CORE.Window.connector || !CORE.Window.crtc) + { + TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap"); + abort(); + } + + struct gbm_bo *bo = gbm_surface_lock_front_buffer(CORE.Window.gbmSurface); + if (!bo) + { + TRACELOG(LOG_ERROR, "DISPLAY: Failed GBM to lock front buffer"); + abort(); + } + + uint32_t fb = 0; + int result = drmModeAddFB(CORE.Window.fd, CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, + CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay, 24, 32, gbm_bo_get_stride(bo), gbm_bo_get_handle(bo).u32, &fb); + if (0 != result) + { + TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d", result); + abort(); + } + + result = drmModeSetCrtc(CORE.Window.fd, CORE.Window.crtc->crtc_id, fb, 0, 0, + &CORE.Window.connector->connector_id, 1, &CORE.Window.connector->modes[CORE.Window.modeIndex]); + if (0 != result) + { + TRACELOG(LOG_ERROR, "DISPLAY: drmModeSetCrtc() failed with result: %d", result); + abort(); + } + + if (CORE.Window.prevFB) + { + result = drmModeRmFB(CORE.Window.fd, CORE.Window.prevFB); + if (0 != result) + { + TRACELOG(LOG_ERROR, "DISPLAY: drmModeRmFB() failed with result: %d", result); + abort(); + } + } + CORE.Window.prevFB = fb; + + if (CORE.Window.prevBO) + { + gbm_surface_release_buffer(CORE.Window.gbmSurface, CORE.Window.prevBO); + } + + CORE.Window.prevBO = bo; +#endif // PLATFORM_DRM +#endif // PLATFORM_ANDROID || PLATFORM_RPI || PLATFORM_DRM || PLATFORM_UWP +} + +// Register all input events +void PollInputEvents(void) { #if defined(SUPPORT_GESTURES_SYSTEM) // NOTE: Gestures update must be called every frame to reset gestures correctly @@ -5014,68 +5101,6 @@ static void PollInputEvents(void) #endif } -// Copy back buffer to front buffers -static void SwapBuffers(void) -{ -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - glfwSwapBuffers(CORE.Window.handle); -#endif - -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) - eglSwapBuffers(CORE.Window.device, CORE.Window.surface); - -#if defined(PLATFORM_DRM) - if (!CORE.Window.gbmSurface || (-1 == CORE.Window.fd) || !CORE.Window.connector || !CORE.Window.crtc) - { - TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap"); - abort(); - } - - struct gbm_bo *bo = gbm_surface_lock_front_buffer(CORE.Window.gbmSurface); - if (!bo) - { - TRACELOG(LOG_ERROR, "DISPLAY: Failed GBM to lock front buffer"); - abort(); - } - - uint32_t fb = 0; - int result = drmModeAddFB(CORE.Window.fd, CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, - CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay, 24, 32, gbm_bo_get_stride(bo), gbm_bo_get_handle(bo).u32, &fb); - if (0 != result) - { - TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d", result); - abort(); - } - - result = drmModeSetCrtc(CORE.Window.fd, CORE.Window.crtc->crtc_id, fb, 0, 0, - &CORE.Window.connector->connector_id, 1, &CORE.Window.connector->modes[CORE.Window.modeIndex]); - if (0 != result) - { - TRACELOG(LOG_ERROR, "DISPLAY: drmModeSetCrtc() failed with result: %d", result); - abort(); - } - - if (CORE.Window.prevFB) - { - result = drmModeRmFB(CORE.Window.fd, CORE.Window.prevFB); - if (0 != result) - { - TRACELOG(LOG_ERROR, "DISPLAY: drmModeRmFB() failed with result: %d", result); - abort(); - } - } - CORE.Window.prevFB = fb; - - if (CORE.Window.prevBO) - { - gbm_surface_release_buffer(CORE.Window.gbmSurface, CORE.Window.prevBO); - } - - CORE.Window.prevBO = bo; -#endif // PLATFORM_DRM -#endif // PLATFORM_ANDROID || PLATFORM_RPI || PLATFORM_DRM || PLATFORM_UWP -} - #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // GLFW3 Error Callback, runs on GLFW3 error static void ErrorCallback(int error, const char *description) @@ -5083,6 +5108,36 @@ static void ErrorCallback(int error, const char *description) TRACELOG(LOG_WARNING, "GLFW: Error: %i Description: %s", error, description); } +#if defined(PLATFORM_WEB) +EM_JS(int, GetCanvasWidth, (), { return canvas.clientWidth; }); +EM_JS(int, GetCanvasHeight, (), { return canvas.clientHeight; }); + +static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *e, void *userData) +{ + // Don't resize non-resizeable windows + if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) return true; + + // This event is called whenever the window changes sizes, + // so the size of the canvas object is explicitly retrieved below + int width = GetCanvasWidth(); + int height = GetCanvasHeight(); + emscripten_set_canvas_element_size("#canvas",width,height); + + SetupViewport(width, height); // Reset viewport and projection matrix for new size + + CORE.Window.currentFbo.width = width; + CORE.Window.currentFbo.height = height; + CORE.Window.resizedLastFrame = true; + + if (IsWindowFullscreen()) return true; + + // Set current screen size + CORE.Window.screen.width = width; + CORE.Window.screen.height = height; + + // NOTE: Postprocessing texture is not scaled to new size +} +#endif // GLFW3 WindowSize Callback, runs when window is resizedLastFrame // NOTE: Window resizing not allowed by default @@ -5374,6 +5429,9 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) // Init hi-res timer InitTimer(); + + // Initialize random seed + srand((unsigned int)time(NULL)); #if defined(SUPPORT_DEFAULT_FONT) // Load default font @@ -6327,7 +6385,8 @@ static void *EventThread(void *arg) #endif } } - Wait(5); // Sleep for 5ms to avoid hogging CPU time + + WaitTime(5); // Sleep for 5ms to avoid hogging CPU time } close(worker->fd); @@ -6415,7 +6474,7 @@ static void *GamepadThread(void *arg) } } } - else Wait(1); // Sleep for 1 ms to avoid hogging CPU time + else WaitTime(1); // Sleep for 1 ms to avoid hogging CPU time } } @@ -6829,7 +6888,7 @@ static void LoadAutomationEvents(const char *fileName) { sscanf(buffer, "e %d %d %d %d %d", &events[count].frame, &events[count].type, &events[count].params[0], &events[count].params[1], &events[count].params[2]); - + count++; } diff --git a/src/external/tinyobj_loader_c.h b/src/external/tinyobj_loader_c.h index 6bd63fceb..6d34d25f7 100644 --- a/src/external/tinyobj_loader_c.h +++ b/src/external/tinyobj_loader_c.h @@ -948,6 +948,8 @@ static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out, /* @todo { unknown parameter } */ } + fclose(fp); + if (material.name) { /* Flush last material element */ materials = tinyobj_material_add(materials, num_materials, &material); diff --git a/src/extras/physac.h b/src/extras/physac.h index 676a96953..834290bc4 100644 --- a/src/extras/physac.h +++ b/src/extras/physac.h @@ -318,7 +318,7 @@ static unsigned int usedMemory = 0; // Total allocated d //---------------------------------------------------------------------------------- #if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) // Timming measure functions -static void InitTimer(void); // Initializes hi-resolution MONOTONIC timer +static void InitTimerHiRes(void); // Initializes hi-resolution MONOTONIC timer static unsigned long long int GetClockTicks(void); // Get hi-res MONOTONIC time measure in mseconds static double GetCurrentTime(void); // Get current time measure in milliseconds #endif @@ -370,7 +370,7 @@ PHYSACDEF void InitPhysics(void) { #if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) // Initialize high resolution timer - InitTimer(); + InitTimerHiRes(); #endif TRACELOG("[PHYSAC] Physics module initialized successfully\n"); @@ -1848,7 +1848,7 @@ static Vector2 MathTriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3) #if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) // Initializes hi-resolution MONOTONIC timer -static void InitTimer(void) +static void InitTimerHiRes(void) { #if defined(_WIN32) QueryPerformanceFrequency((unsigned long long int *) &frequency); diff --git a/src/models.c b/src/models.c index 6e6ebfcce..011965270 100644 --- a/src/models.c +++ b/src/models.c @@ -1105,10 +1105,6 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]); - rlEnableVertexBuffer(mesh.vboId[0]); - rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0); - rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]); - // Bind mesh VBO data: vertex texcoords (shader-location = 1) rlEnableVertexBuffer(mesh.vboId[1]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0); @@ -2652,7 +2648,7 @@ BoundingBox GetMeshBoundingBox(Mesh mesh) // Compute mesh tangents // NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates // Implementation base don: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html -void MeshTangents(Mesh *mesh) +void GenMeshTangents(Mesh *mesh) { if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float)); else TRACELOG(LOG_WARNING, "MESH: Tangents data already available, re-writting"); @@ -2732,7 +2728,7 @@ void MeshTangents(Mesh *mesh) } // Compute mesh binormals (aka bitangent) -void MeshBinormals(Mesh *mesh) +void GenMeshBinormals(Mesh *mesh) { for (int i = 0; i < mesh->vertexCount; i++) { @@ -4996,7 +4992,7 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo // output->framerate = // TODO: Use framerate instead of const timestep // Name and parent bones - for (unsigned int j = 0; j < output->boneCount; j++) + for (int j = 0; j < output->boneCount; j++) { strcpy(output->bones[j].name, data->nodes[j].name == 0 ? "ANIMJOINT" : data->nodes[j].name); output->bones[j].parent = (data->nodes[j].parent != NULL) ? (int)(data->nodes[j].parent - data->nodes) : -1; @@ -5007,7 +5003,7 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo for (int frame = 0; frame < output->frameCount; frame++) { output->framePoses[frame] = RL_MALLOC(output->boneCount*sizeof(Transform)); - + for (unsigned int i = 0; i < output->boneCount; i++) { if (data->nodes[i].has_translation) memcpy(&output->framePoses[frame][i].translation, data->nodes[i].translation, 3 * sizeof(float)); diff --git a/src/raylib.h b/src/raylib.h index cedf4f5dc..6c4ab45e6 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -222,7 +222,7 @@ typedef struct Color { // Rectangle, 4 components typedef struct Rectangle { - float x; // Rectangle top-left corner position x + float x; // Rectangle top-left corner position x float y; // Rectangle top-left corner position y float width; // Rectangle width float height; // Rectangle height @@ -960,6 +960,14 @@ RLAPI const char *GetMonitorName(int monitor); // Get the hum RLAPI void SetClipboardText(const char *text); // Set clipboard text content RLAPI const char *GetClipboardText(void); // Get clipboard text content +// Custom frame control functions +// NOTE: Those functions are intended for advance users that want full control over the frame processing +// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timming + PollInputEvents() +// To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL +RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing) +RLAPI void PollInputEvents(void); // Register all input events +RLAPI void WaitTime(float ms); // Wait for some milliseconds (halt program execution) + // Cursor-related functions RLAPI void ShowCursor(void); // Shows cursor RLAPI void HideCursor(void); // Hides cursor @@ -1104,6 +1112,7 @@ RLAPI bool IsMouseButtonUp(int button); // Check if a mous RLAPI int GetMouseX(void); // Get mouse position X RLAPI int GetMouseY(void); // Get mouse position Y RLAPI Vector2 GetMousePosition(void); // Get mouse position XY +RLAPI Vector2 GetMouseDelta(void); // Get mouse delta between frames RLAPI void SetMousePosition(int x, int y); // Set mouse position XY RLAPI void SetMouseOffset(int offsetX, int offsetY); // Set mouse offset RLAPI void SetMouseScale(float scaleX, float scaleY); // Set mouse scaling @@ -1360,9 +1369,10 @@ RLAPI int TextToInteger(const char *text); // Get int RLAPI char *TextToUtf8(int *codepoints, int length); // Encode text codepoint into utf8 text (memory must be freed!) // UTF8 text strings management functions -RLAPI int *GetCodepoints(const char *text, int *count); // Get all codepoints in a string, codepoints count returned by parameters +RLAPI int *LoadCodepoints(const char *text, int *count); // Load all codepoints from a UTF8 text string, codepoints count returned by parameter +RLAPI void UnloadCodepoints(int *codepoints); // Unload codepoints data from memory RLAPI int GetCodepointsCount(const char *text); // Get total number of characters (codepoints) in a UTF8 encoded string -RLAPI int GetNextCodepoint(const char *text, int *bytesProcessed); // Get next codepoint in a UTF8 encoded string; 0x3f('?') is returned on failure +RLAPI int GetCodepoint(const char *text, int *bytesProcessed); // Get next codepoint in a UTF8 encoded string, 0x3f('?') is returned on failure RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength); // Encode codepoint into utf8 text (char array length returned as parameter) //------------------------------------------------------------------------------------ @@ -1435,8 +1445,8 @@ RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); // Mesh manipulation functions RLAPI BoundingBox GetMeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits -RLAPI void MeshTangents(Mesh *mesh); // Compute mesh tangents -RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals +RLAPI void GenMeshTangents(Mesh *mesh); // Compute mesh tangents +RLAPI void GenMeshBinormals(Mesh *mesh); // Compute mesh binormals // Model drawing functions RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) diff --git a/src/raymath.h b/src/raymath.h index 6ab666e51..55ca14e80 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -138,7 +138,7 @@ typedef struct float3 { float v[3]; } float3; typedef struct float16 { float v[16]; } float16; -#include // Required for: sinf(), cosf(), sqrtf(), tan(), fabs() +#include // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), fminf(), fmaxf(), fabs() //---------------------------------------------------------------------------------- // Module Functions Definition - Utils math diff --git a/src/rlgl.h b/src/rlgl.h index 4b88e09df..662ec8344 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -297,14 +297,6 @@ typedef struct RenderBatch { typedef enum { false, true } bool; #endif - // Color, 4 components, R8G8B8A8 (32bit) - typedef struct Color { - unsigned char r; // Color red value - unsigned char g; // Color green value - unsigned char b; // Color blue value - unsigned char a; // Color alpha value - } Color; - // Texture type // NOTE: Data stored in GPU memory typedef struct Texture2D { @@ -880,8 +872,8 @@ static char *rlGetCompressedFormatName(int format); // Get compressed format off #endif // SUPPORT_GL_DETAILS_INFO #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 #if defined(GRAPHICS_API_OPENGL_11) -static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHeight); // Generate mipmaps data on CPU side -static Color *rlGenNextMipmapData(Color *srcData, int srcWidth, int srcHeight); // Generate next mipmap level on CPU side +static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHeight); // Generate mipmaps data on CPU side +static unsigned char *rlGenNextMipmapData(unsigned char *srcData, int srcWidth, int srcHeight); // Generate next mipmap level on CPU side #endif static int rlGetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture) @@ -3957,22 +3949,20 @@ static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHei width = baseWidth; height = baseHeight; - size = (width*height*4); + size = (width*height*4); // RGBA: 4 bytes // Generate mipmaps - // NOTE: Every mipmap data is stored after data - Color *image = (Color *)RL_MALLOC(width*height*sizeof(Color)); - Color *mipmap = NULL; + // NOTE: Every mipmap data is stored after data (RGBA - 4 bytes) + unsigned char *image = (unsigned char *)RL_MALLOC(width*height*4); + unsigned char *mipmap = NULL; int offset = 0; - int j = 0; for (int i = 0; i < size; i += 4) { - image[j].r = data[i]; - image[j].g = data[i + 1]; - image[j].b = data[i + 2]; - image[j].a = data[i + 3]; - j++; + image[i] = data[i]; + image[i + 1] = data[i + 1]; + image[i + 2] = data[i + 2]; + image[i + 3] = data[i + 3]; } TRACELOGD("TEXTURE: Mipmap base size (%ix%i)", width, height); @@ -3982,7 +3972,6 @@ static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHei mipmap = rlGenNextMipmapData(image, width, height); offset += (width*height*4); // Size of last mipmap - j = 0; width /= 2; height /= 2; @@ -3991,11 +3980,10 @@ static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHei // Add mipmap to data for (int i = 0; i < size; i += 4) { - data[offset + i] = mipmap[j].r; - data[offset + i + 1] = mipmap[j].g; - data[offset + i + 2] = mipmap[j].b; - data[offset + i + 3] = mipmap[j].a; - j++; + data[offset + i] = mipmap[i]; + data[offset + i + 1] = mipmap[i + 1]; + data[offset + i + 2] = mipmap[i + 2]; + data[offset + i + 3] = mipmap[i + 3]; } RL_FREE(image); @@ -4010,15 +3998,17 @@ static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHei } // Manual mipmap generation (basic scaling algorithm) -static Color *rlGenNextMipmapData(Color *srcData, int srcWidth, int srcHeight) +static unsigned char *rlGenNextMipmapData(unsigned char *srcData, int srcWidth, int srcHeight) { - int x2, y2; - Color prow, pcol; + int x2 = 0; + int y2 = 0; + unsigned char prow[4]; + unsigned char pcol[4]; int width = srcWidth/2; int height = srcHeight/2; - Color *mipmap = (Color *)RL_MALLOC(width*height*sizeof(Color)); + unsigned char *mipmap = (unsigned char *)RL_MALLOC(width*height*4); // Scaling algorithm works perfectly (box-filter) for (int y = 0; y < height; y++) @@ -4029,20 +4019,20 @@ static Color *rlGenNextMipmapData(Color *srcData, int srcWidth, int srcHeight) { x2 = 2*x; - prow.r = (srcData[y2*srcWidth + x2].r + srcData[y2*srcWidth + x2 + 1].r)/2; - prow.g = (srcData[y2*srcWidth + x2].g + srcData[y2*srcWidth + x2 + 1].g)/2; - prow.b = (srcData[y2*srcWidth + x2].b + srcData[y2*srcWidth + x2 + 1].b)/2; - prow.a = (srcData[y2*srcWidth + x2].a + srcData[y2*srcWidth + x2 + 1].a)/2; + prow[0] = (srcData[(y2*srcWidth + x2)*4 + 0] + srcData[(y2*srcWidth + x2 + 1)*4 + 0])/2; + prow[1] = (srcData[(y2*srcWidth + x2)*4 + 1] + srcData[(y2*srcWidth + x2 + 1)*4 + 1])/2; + prow[2] = (srcData[(y2*srcWidth + x2)*4 + 2] + srcData[(y2*srcWidth + x2 + 1)*4 + 2])/2; + prow[3] = (srcData[(y2*srcWidth + x2)*4 + 3] + srcData[(y2*srcWidth + x2 + 1)*4 + 3])/2; - pcol.r = (srcData[(y2+1)*srcWidth + x2].r + srcData[(y2+1)*srcWidth + x2 + 1].r)/2; - pcol.g = (srcData[(y2+1)*srcWidth + x2].g + srcData[(y2+1)*srcWidth + x2 + 1].g)/2; - pcol.b = (srcData[(y2+1)*srcWidth + x2].b + srcData[(y2+1)*srcWidth + x2 + 1].b)/2; - pcol.a = (srcData[(y2+1)*srcWidth + x2].a + srcData[(y2+1)*srcWidth + x2 + 1].a)/2; + pcol[0] = (srcData[((y2 + 1)*srcWidth + x2)*4 + 0] + srcData[((y2 + 1)*srcWidth + x2 + 1)*4 + 0])/2; + pcol[1] = (srcData[((y2 + 1)*srcWidth + x2)*4 + 1] + srcData[((y2 + 1)*srcWidth + x2 + 1)*4 + 1])/2; + pcol[2] = (srcData[((y2 + 1)*srcWidth + x2)*4 + 2] + srcData[((y2 + 1)*srcWidth + x2 + 1)*4 + 2])/2; + pcol[3] = (srcData[((y2 + 1)*srcWidth + x2)*4 + 3] + srcData[((y2 + 1)*srcWidth + x2 + 1)*4 + 3])/2; - mipmap[y*width + x].r = (prow.r + pcol.r)/2; - mipmap[y*width + x].g = (prow.g + pcol.g)/2; - mipmap[y*width + x].b = (prow.b + pcol.b)/2; - mipmap[y*width + x].a = (prow.a + pcol.a)/2; + mipmap[(y*width + x)*4 + 0] = (prow[0] + pcol[0])/2; + mipmap[(y*width + x)*4 + 1] = (prow[1] + pcol[1])/2; + mipmap[(y*width + x)*4 + 2] = (prow[2] + pcol[2])/2; + mipmap[(y*width + x)*4 + 3] = (prow[3] + pcol[3])/2; } } diff --git a/src/shapes.c b/src/shapes.c index 788c3c830..98852bc8c 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -1645,7 +1645,7 @@ bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshol if (fabsf(dxl) >= fabsf(dyl)) collision = (dxl > 0)? ((p1.x <= point.x) && (point.x <= p2.x)) : ((p2.x <= point.x) && (point.x <= p1.x)); else collision = (dyl > 0)? ((p1.y <= point.y) && (point.y <= p2.y)) : ((p2.y <= point.y) && (point.y <= p1.y)); } - + return collision; } diff --git a/src/text.c b/src/text.c index e18afe41e..5b5b85648 100644 --- a/src/text.c +++ b/src/text.c @@ -861,7 +861,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f { // Get next codepoint from byte string and glyph index in font int codepointByteCount = 0; - int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); + int codepoint = GetCodepoint(&text[i], &codepointByteCount); int index = GetGlyphIndex(font, codepoint); // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) @@ -901,10 +901,10 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f { int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop - int textOffsetY = 0; // Offset between lines (on line break '\n') + float textOffsetY = 0; // Offset between lines (on line break '\n') float textOffsetX = 0.0f; // Offset X to next character to draw - float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor + float scaleFactor = fontSize/(float)font.baseSize; // Character quad scaling factor // Word/character wrapping mechanism variables enum { MEASURE_STATE = 0, DRAW_STATE = 1 }; @@ -918,7 +918,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f { // Get next codepoint from byte string and glyph index in font int codepointByteCount = 0; - int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); + int codepoint = GetCodepoint(&text[i], &codepointByteCount); int index = GetGlyphIndex(font, codepoint); // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) @@ -926,12 +926,12 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f if (codepoint == 0x3f) codepointByteCount = 1; i += (codepointByteCount - 1); - int glyphWidth = 0; + float glyphWidth = 0; if (codepoint != '\n') { - glyphWidth = (font.chars[index].advanceX == 0)? - (int)(font.recs[index].width*scaleFactor + spacing): - (int)(font.chars[index].advanceX*scaleFactor + spacing); + glyphWidth = (font.chars[index].advanceX == 0) ? font.recs[index].width*scaleFactor : font.chars[index].advanceX*scaleFactor; + + if (i + 1 < length) glyphWidth = glyphWidth + spacing; } // NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside of the rec container @@ -945,7 +945,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f // Ref: http://jkorpela.fi/chars/spaces.html if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i; - if ((textOffsetX + glyphWidth + 1) >= rec.width) + if ((textOffsetX + glyphWidth) > rec.width) { endLine = (endLine < 1)? i : endLine; if (i == endLine) endLine -= codepointByteCount; @@ -956,7 +956,6 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f else if ((i + 1) == length) { endLine = i; - state = !state; } else if (codepoint == '\n') state = !state; @@ -979,26 +978,26 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f { if (!wordWrap) { - textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); + textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; textOffsetX = 0; } } else { - if (!wordWrap && ((textOffsetX + glyphWidth + 1) >= rec.width)) + if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width)) { - textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); + textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; textOffsetX = 0; } // When text overflows rectangle height limit, just stop drawing - if ((textOffsetY + (int)(font.baseSize*scaleFactor)) > rec.height) break; + if ((textOffsetY + font.baseSize*scaleFactor) > rec.height) break; // Draw selection background bool isGlyphSelected = false; if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength))) { - DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, (float)glyphWidth, (float)font.baseSize*scaleFactor }, selectBackTint); + DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, glyphWidth, (float)font.baseSize*scaleFactor }, selectBackTint); isGlyphSelected = true; } @@ -1011,7 +1010,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f if (wordWrap && (i == endLine)) { - textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); + textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; textOffsetX = 0; startLine = endLine; endLine = -1; @@ -1090,7 +1089,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing lenCounter++; int next = 0; - letter = GetNextCodepoint(&text[i], &next); + letter = GetCodepoint(&text[i], &next); index = GetGlyphIndex(font, letter); // NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) @@ -1564,28 +1563,38 @@ RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength) return utf8; } -// Get all codepoints in a string, codepoints count returned by parameters -// REQUIRES: memset() -int *GetCodepoints(const char *text, int *count) +// Load all codepoints from a UTF8 text string, codepoints count returned by parameter +int *LoadCodepoints(const char *text, int *count) { - static int codepoints[MAX_TEXT_UNICODE_CHARS] = { 0 }; - memset(codepoints, 0, MAX_TEXT_UNICODE_CHARS*sizeof(int)); - - int bytesProcessed = 0; int textLength = TextLength(text); + + int bytesProcessed = 0; int codepointsCount = 0; + + // Allocate a big enough buffer to store as many codepoints as text bytes + int *codepoints = RL_CALLOC(textLength, sizeof(int)); for (int i = 0; i < textLength; codepointsCount++) { - codepoints[codepointsCount] = GetNextCodepoint(text + i, &bytesProcessed); + codepoints[codepointsCount] = GetCodepoint(text + i, &bytesProcessed); i += bytesProcessed; } + // Re-allocate buffer to the actual number of codepoints loaded + void *temp = RL_REALLOC(codepoints, codepointsCount*sizeof(int)); + if (temp != NULL) codepoints = temp; + *count = codepointsCount; return codepoints; } +// Unload codepoints data from memory +void UnloadCodepoints(int *codepoints) +{ + RL_FREE(codepoints); +} + // Get total number of characters(codepoints) in a UTF8 encoded text, until '\0' is found // NOTE: If an invalid UTF8 sequence is encountered a '?'(0x3f) codepoint is counted instead int GetCodepointsCount(const char *text) @@ -1596,7 +1605,7 @@ int GetCodepointsCount(const char *text) while (*ptr != '\0') { int next = 0; - int letter = GetNextCodepoint(ptr, &next); + int letter = GetCodepoint(ptr, &next); if (letter == 0x3f) ptr += 1; else ptr += next; @@ -1614,7 +1623,7 @@ int GetCodepointsCount(const char *text) // NOTE: the standard says U+FFFD should be returned in case of errors // but that character is not supported by the default font in raylib // TODO: Optimize this code for speed!! -int GetNextCodepoint(const char *text, int *bytesProcessed) +int GetCodepoint(const char *text, int *bytesProcessed) { /* UTF8 specs from https://www.ietf.org/rfc/rfc3629.txt diff --git a/src/textures.c b/src/textures.c index 7017660ba..a9c40d50e 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1114,7 +1114,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co { // Get next codepoint from byte string and glyph index in font int codepointByteCount = 0; - int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); + int codepoint = GetCodepoint(&text[i], &codepointByteCount); int index = GetGlyphIndex(font, codepoint); // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)