This commit is contained in:
Hristo Stamenov 2021-06-24 00:12:38 +03:00
commit 9a1816bc5b
33 changed files with 643 additions and 414 deletions

14
.gitignore vendored
View File

@ -53,17 +53,6 @@ packages/
*.bc *.bc
*.so *.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 # Ignore files build by xcode
*.mode*v* *.mode*v*
*.pbxuser *.pbxuser
@ -93,9 +82,6 @@ compile_commands.json
CTestTestfile.cmake CTestTestfile.cmake
build build
# Unignore These makefiles...
!examples/CMakeLists.txt
# Ignore GNU global tags # Ignore GNU global tags
GPATH GPATH
GRTAGS GRTAGS

View File

@ -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 | | 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 | | 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 | | 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 | | 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 | | 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 | | raylib-scm | 2.5 | [Chicken Scheme](https://www.call-cc.org/) | https://github.com/yashrk/raylib-scm |

View File

@ -5,15 +5,16 @@
* This example has been created using raylib 3.7 (www.raylib.com) * 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) * 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) * 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 "raylib.h"
#include <math.h>
#include <math.h> // Required for: sinf(), cosf()
int main(void) int main(void)
{ {
@ -22,33 +23,32 @@ int main(void)
const int screenWidth = 800; const int screenWidth = 800;
const int screenHeight = 450; const int screenHeight = 450;
const int virualScreenWidth = 160; const int virtualScreenWidth = 160;
const int virtualScreenHeight = 90; 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"); 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; worldSpaceCamera.zoom = 1.0f;
Camera2D screenSpaceCamera = { 0 }; //Smoothing camera Camera2D screenSpaceCamera = { 0 }; // Smoothing camera
screenSpaceCamera.zoom = 1.0f; 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 rec01 = { 70.0f, 35.0f, 20.0f, 20.0f };
Rectangle secondRectangle = { 90.0f, 55.0f, 30.0f, 10.0f }; Rectangle rec02 = { 90.0f, 55.0f, 30.0f, 10.0f };
Rectangle thirdRectangle = { 80.0f, 65.0f, 15.0f, 25.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. // The target'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 sourceRec = { 0.0f, 0.0f, (float)target.texture.width, -(float)target.texture.height };
Rectangle renderTextureDest = { -virtualRatio, -virtualRatio, screenWidth + (virtualRatio*2), screenHeight + (virtualRatio*2) }; Rectangle destRec = { -virtualRatio, -virtualRatio, screenWidth + (virtualRatio*2), screenHeight + (virtualRatio*2) };
Vector2 origin = { 0.0f, 0.0f }; Vector2 origin = { 0.0f, 0.0f };
float rotation = 0.0f; float rotation = 0.0f;
float degreesPerSecond = 60.0f;
float cameraX = 0.0f; float cameraX = 0.0f;
float cameraY = 0.0f; float cameraY = 0.0f;
@ -61,16 +61,16 @@ int main(void)
{ {
// Update // 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; cameraX = (sinf(GetTime())*50.0f) - 10.0f;
cameraY = cosf(GetTime())*30.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 }; 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; worldSpaceCamera.target.x = (int)screenSpaceCamera.target.x;
screenSpaceCamera.target.x -= worldSpaceCamera.target.x; screenSpaceCamera.target.x -= worldSpaceCamera.target.x;
screenSpaceCamera.target.x *= virtualRatio; screenSpaceCamera.target.x *= virtualRatio;
@ -83,46 +83,34 @@ int main(void)
// Draw // Draw
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
BeginDrawing(); BeginTextureMode(target);
ClearBackground(RED); // This is for debug purposes. If you see red, then you've probably done something wrong. ClearBackground(RAYWHITE);
BeginTextureMode(renderTexture);
BeginMode2D(worldSpaceCamera); BeginMode2D(worldSpaceCamera);
ClearBackground(RAYWHITE); // This is the color you should see as background color. DrawRectanglePro(rec01, origin, rotation, BLACK);
DrawRectanglePro(rec02, origin, -rotation, RED);
// Draw the rectangles DrawRectanglePro(rec03, origin, rotation + 45.0f, BLUE);
DrawRectanglePro(firstRectangle, origin, rotation, BLACK);
DrawRectanglePro(secondRectangle, origin, -rotation, RED);
DrawRectanglePro(thirdRectangle, origin, rotation + 45.0f, BLUE);
EndMode2D(); EndMode2D();
EndTextureMode(); EndTextureMode();
BeginDrawing();
ClearBackground(RED);
BeginMode2D(screenSpaceCamera); BeginMode2D(screenSpaceCamera);
DrawTexturePro(target.texture, sourceRec, destRec, origin, 0.0f, WHITE);
// 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(); EndMode2D();
//Debug info DrawText(TextFormat("Screen resolution: %ix%i", screenWidth, screenHeight), 10, 10, 20, DARKBLUE);
DrawText("Screen resolution: 800x450", 5, 0, 20, DARKBLUE); DrawText(TextFormat("World resolution: %ix%i", virtualScreenWidth, virtualScreenHeight), 10, 40, 20, DARKGREEN);
DrawText("World resolution: 160x90", 5, 20, 20, DARKGREEN); DrawFPS(GetScreenWidth() - 95, 10);
DrawFPS(screenWidth - 75, 0);
EndDrawing(); EndDrawing();
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
} }
// De-Initialization // De-Initialization
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
UnloadRenderTexture(renderTexture); // RenderTexture unloading UnloadRenderTexture(target); // Unload render texture
CloseWindow(); // Close window and OpenGL context CloseWindow(); // Close window and OpenGL context
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -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;
}

View File

@ -89,7 +89,7 @@ int main(void)
// this moves thigns at 10 world units per second, regardless of the actual FPS // this moves thigns at 10 world units per second, regardless of the actual FPS
float offsetThisFrame = 10.0f*GetFrameTime(); float offsetThisFrame = 10.0f*GetFrameTime();
// Move player 1 forward and backwards (no turning) // Move Player1 forward and backwards (no turning)
if (IsKeyDown(KEY_W)) if (IsKeyDown(KEY_W))
{ {
cameraPlayer1.position.z += offsetThisFrame; cameraPlayer1.position.z += offsetThisFrame;
@ -101,7 +101,7 @@ int main(void)
cameraPlayer1.target.z -= offsetThisFrame; cameraPlayer1.target.z -= offsetThisFrame;
} }
// Move player 2 forward and backwards (no turning) // Move Player2 forward and backwards (no turning)
if (IsKeyDown(KEY_UP)) if (IsKeyDown(KEY_UP))
{ {
cameraPlayer2.position.x += offsetThisFrame; cameraPlayer2.position.x += offsetThisFrame;
@ -116,7 +116,7 @@ int main(void)
// Draw // Draw
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Draw player 1's view to the render texture // Draw Player1 view to the render texture
BeginTextureMode(screenPlayer1); BeginTextureMode(screenPlayer1);
ClearBackground(SKYBLUE); ClearBackground(SKYBLUE);
BeginMode3D(cameraPlayer1); BeginMode3D(cameraPlayer1);
@ -125,7 +125,7 @@ int main(void)
DrawText("PLAYER1 W/S to move", 0, 0, 20, RED); DrawText("PLAYER1 W/S to move", 0, 0, 20, RED);
EndTextureMode(); EndTextureMode();
// Draw player 2's view to the render texture // Draw Player2 view to the render texture
BeginTextureMode(screenPlayer2); BeginTextureMode(screenPlayer2);
ClearBackground(SKYBLUE); ClearBackground(SKYBLUE);
BeginMode3D(cameraPlayer2); BeginMode3D(cameraPlayer2);
@ -134,19 +134,19 @@ int main(void)
DrawText("PLAYER2 UP/DOWN to move", 0, 0, 20, BLUE); DrawText("PLAYER2 UP/DOWN to move", 0, 0, 20, BLUE);
EndTextureMode(); EndTextureMode();
// Draw both view render textures to the screen side by side // Draw both views render textures to the screen side by side
BeginDrawing(); BeginDrawing();
ClearBackground(BLACK); ClearBackground(BLACK);
DrawTextureRec(screenPlayer1.texture, splitScreenRect, (Vector2) { 0, 0 }, WHITE); DrawTextureRec(screenPlayer1.texture, splitScreenRect, (Vector2){ 0, 0 }, WHITE);
DrawTextureRec(screenPlayer2.texture, splitScreenRect, (Vector2) { screenWidth/2.0f, 0 }, WHITE); DrawTextureRec(screenPlayer2.texture, splitScreenRect, (Vector2){ screenWidth/2.0f, 0 }, WHITE);
EndDrawing(); EndDrawing();
} }
// De-Initialization // De-Initialization
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
UnloadRenderTexture(screenPlayer1); UnloadRenderTexture(screenPlayer1); // Unload render texture
UnloadRenderTexture(screenPlayer2); UnloadRenderTexture(screenPlayer2); // Unload render texture
UnloadTexture(textureGrid); UnloadTexture(textureGrid); // Unload texture
CloseWindow(); // Close window and OpenGL context CloseWindow(); // Close window and OpenGL context
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------

View File

@ -105,10 +105,6 @@ int main(void)
// Draw // Draw
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginTextureMode(target); BeginTextureMode(target);
ClearBackground(RAYWHITE); ClearBackground(RAYWHITE);
BeginVrStereoMode(config); BeginVrStereoMode(config);
@ -122,13 +118,13 @@ int main(void)
EndVrStereoMode(); EndVrStereoMode();
EndTextureMode(); EndTextureMode();
BeginDrawing();
ClearBackground(RAYWHITE);
BeginShaderMode(distortion); BeginShaderMode(distortion);
DrawTextureRec(target.texture, (Rectangle){ 0, 0, (float)target.texture.width, DrawTextureRec(target.texture, (Rectangle){ 0, 0, (float)target.texture.width,
(float)-target.texture.height }, (Vector2){ 0.0f, 0.0f }, WHITE); (float)-target.texture.height }, (Vector2){ 0.0f, 0.0f }, WHITE);
EndShaderMode(); EndShaderMode();
DrawFPS(10, 10); DrawFPS(10, 10);
EndDrawing(); EndDrawing();
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
} }

View File

@ -79,28 +79,24 @@ int main(void)
// Draw // Draw
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(BLACK);
// Draw everything in the render texture, note this will not be rendered on screen, yet // Draw everything in the render texture, note this will not be rendered on screen, yet
BeginTextureMode(target); BeginTextureMode(target);
ClearBackground(RAYWHITE); // Clear render texture background color ClearBackground(RAYWHITE); // Clear render texture background color
for (int i = 0; i < 10; i++) DrawRectangle(0, (gameScreenHeight/10)*i, gameScreenWidth, gameScreenHeight/10, colors[i]); 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("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("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); DrawText(TextFormat("Virtual Mouse: [%i , %i]", (int)virtualMouse.x, (int)virtualMouse.y), 350, 55, 20, YELLOW);
EndTextureMode(); EndTextureMode();
// Draw RenderTexture2D to window, properly scaled BeginDrawing();
ClearBackground(BLACK); // Clear screen background
// Draw render texture to screen, properly scaled
DrawTexturePro(target.texture, (Rectangle){ 0.0f, 0.0f, (float)target.texture.width, (float)-target.texture.height }, 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, (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); (float)gameScreenWidth*scale, (float)gameScreenHeight*scale }, (Vector2){ 0, 0 }, 0.0f, WHITE);
EndDrawing(); EndDrawing();
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
} }

View File

@ -41,16 +41,18 @@
* *
* raylib [core] example - Basic window * 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) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* *
* Copyright (c) 2019 Ramon Santamaria (@raysan5) * Example contributed by <user_name> (@<user_github>) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2021 <user_name> (@<user_github>)
* *
********************************************************************************************/ ********************************************************************************************/
#include "raylib.h" #include "raylib.h"
int main() int main(void)
{ {
// Initialization // Initialization
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------

View File

@ -99,7 +99,7 @@ int main(void)
// De-Initialization // 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 CloseWindow(); // Close window and OpenGL context
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------

View File

@ -65,6 +65,14 @@
#define RAYWHITE (Color){ 245, 245, 245, 255 } // My own White (raylib logo) #define RAYWHITE (Color){ 245, 245, 245, 255 } // My own White (raylib logo)
#define DARKGRAY (Color){ 80, 80, 80, 255 } // Dark Gray #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 // Camera type, defines a camera position/orientation in 3d space
typedef struct Camera { typedef struct Camera {
Vector3 position; // Camera position Vector3 position; // Camera position
@ -271,7 +279,7 @@ static void DrawGrid(int slices, float spacing)
int halfSlices = slices / 2; int halfSlices = slices / 2;
rlBegin(RL_LINES); rlBegin(RL_LINES);
for(int i = -halfSlices; i <= halfSlices; i++) for (int i = -halfSlices; i <= halfSlices; i++)
{ {
if (i == 0) if (i == 0)
{ {

View File

@ -86,38 +86,29 @@ int main(void)
// Draw // Draw
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginTextureMode(target); // Enable drawing to texture BeginTextureMode(target); // Enable drawing to texture
ClearBackground(RAYWHITE); // Clear texture background ClearBackground(RAYWHITE); // Clear texture background
BeginMode3D(camera); // Begin 3d mode drawing BeginMode3D(camera); // Begin 3d mode drawing
DrawModel(model, position, 0.5f, WHITE); // Draw 3d model with texture DrawModel(model, position, 0.5f, WHITE); // Draw 3d model with texture
DrawGrid(10, 1.0f); // Draw a grid DrawGrid(10, 1.0f); // Draw a grid
EndMode3D(); // End 3d mode drawing, returns to orthographic 2d mode EndMode3D(); // End 3d mode drawing, returns to orthographic 2d mode
DrawText("TEXT DRAWN IN RENDER TEXTURE", 200, 10, 30, RED); DrawText("TEXT DRAWN IN RENDER TEXTURE", 200, 10, 30, RED);
EndTextureMode(); // End drawing to texture (now we have a texture available for next passes) EndTextureMode(); // End drawing to texture (now we have a texture available for next passes)
BeginShaderMode(shader); BeginDrawing();
ClearBackground(RAYWHITE); // Clear screen background
// Enable shader using the custom uniform
BeginShaderMode(shader);
// NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) // 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); DrawTextureRec(target.texture, (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, (Vector2){ 0, 0 }, WHITE);
EndShaderMode(); EndShaderMode();
// Draw some 2d text over drawn texture // Draw some 2d text over drawn texture
DrawText("(c) Barracks 3D model by Alberto Cano", screenWidth - 220, screenHeight - 20, 10, GRAY); DrawText("(c) Barracks 3D model by Alberto Cano", screenWidth - 220, screenHeight - 20, 10, GRAY);
DrawFPS(10, 10); DrawFPS(10, 10);
EndDrawing(); EndDrawing();
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
} }

View File

@ -59,10 +59,6 @@ int main(void)
// Draw // Draw
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginTextureMode(target); // Enable drawing to texture BeginTextureMode(target); // Enable drawing to texture
ClearBackground(BLACK); // Clear the render texture ClearBackground(BLACK); // Clear the render texture
@ -73,11 +69,13 @@ int main(void)
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK); DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK);
EndTextureMode(); // End drawing to texture (now we have a blank texture available for the shader) EndTextureMode(); // End drawing to texture (now we have a blank texture available for the shader)
BeginDrawing();
ClearBackground(RAYWHITE); // Clear screen background
BeginShaderMode(shader); BeginShaderMode(shader);
// NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) // 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); DrawTextureRec(target.texture, (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, (Vector2){ 0.0f, 0.0f }, WHITE);
EndShaderMode(); EndShaderMode();
EndDrawing(); EndDrawing();
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
} }
@ -85,7 +83,7 @@ int main(void)
// De-Initialization // De-Initialization
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
UnloadShader(shader); // Unload shader UnloadShader(shader); // Unload shader
UnloadRenderTexture(target); // Unload texture UnloadRenderTexture(target); // Unload render texture
CloseWindow(); // Close window and OpenGL context CloseWindow(); // Close window and OpenGL context
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------

View File

@ -145,10 +145,6 @@ int main(void)
// Draw // Draw
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(BLACK); // Clear the screen of the previous frame.
// Using a render texture to draw Julia set // Using a render texture to draw Julia set
BeginTextureMode(target); // Enable drawing to texture BeginTextureMode(target); // Enable drawing to texture
ClearBackground(BLACK); // Clear the render texture ClearBackground(BLACK); // Clear the render texture
@ -160,6 +156,9 @@ int main(void)
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK); DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK);
EndTextureMode(); EndTextureMode();
BeginDrawing();
ClearBackground(BLACK); // Clear screen background
// Draw the saved texture and rendered julia set with shader // Draw the saved texture and rendered julia set with shader
// NOTE: We do not invert texture on Y, already considered inside shader // NOTE: We do not invert texture on Y, already considered inside shader
BeginShaderMode(shader); BeginShaderMode(shader);
@ -176,7 +175,6 @@ int main(void)
DrawText("Press KEY_LEFT | KEY_RIGHT to change speed", 10, 60, 10, RAYWHITE); 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); DrawText("Press KEY_SPACE to pause movement animation", 10, 75, 10, RAYWHITE);
} }
EndDrawing(); EndDrawing();
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
} }

View File

@ -124,50 +124,38 @@ int main(void)
// Draw // Draw
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginTextureMode(target); // Enable drawing to texture BeginTextureMode(target); // Enable drawing to texture
ClearBackground(RAYWHITE); // Clear texture background ClearBackground(RAYWHITE); // Clear texture background
BeginMode3D(camera); // Begin 3d mode drawing BeginMode3D(camera); // Begin 3d mode drawing
DrawModel(model, position, 0.1f, WHITE); // Draw 3d model with texture DrawModel(model, position, 0.1f, WHITE); // Draw 3d model with texture
DrawGrid(10, 1.0f); // Draw a grid DrawGrid(10, 1.0f); // Draw a grid
EndMode3D(); // End 3d mode drawing, returns to orthographic 2d mode EndMode3D(); // End 3d mode drawing, returns to orthographic 2d mode
EndTextureMode(); // End drawing to texture (now we have a texture available for next passes) EndTextureMode(); // End drawing to texture (now we have a texture available for next passes)
// Render previously generated texture using selected postpro shader BeginDrawing();
BeginShaderMode(shaders[currentShader]); ClearBackground(RAYWHITE); // Clear screen background
// Render generated texture using selected postprocessing shader
BeginShaderMode(shaders[currentShader]);
// NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) // 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); DrawTextureRec(target.texture, (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, (Vector2){ 0, 0 }, WHITE);
EndShaderMode(); EndShaderMode();
// Draw 2d shapes and text over drawn texture // Draw 2d shapes and text over drawn texture
DrawRectangle(0, 9, 580, 30, Fade(LIGHTGRAY, 0.7f)); DrawRectangle(0, 9, 580, 30, Fade(LIGHTGRAY, 0.7f));
DrawText("(c) Church 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, GRAY); DrawText("(c) Church 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, GRAY);
DrawText("CURRENT POSTPRO SHADER:", 10, 15, 20, BLACK); DrawText("CURRENT POSTPRO SHADER:", 10, 15, 20, BLACK);
DrawText(postproShaderText[currentShader], 330, 15, 20, RED); DrawText(postproShaderText[currentShader], 330, 15, 20, RED);
DrawText("< >", 540, 10, 30, DARKBLUE); DrawText("< >", 540, 10, 30, DARKBLUE);
DrawFPS(700, 15); DrawFPS(700, 15);
EndDrawing(); EndDrawing();
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
} }
// De-Initialization // De-Initialization
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
// Unload all postpro shaders // Unload all postpro shaders
for (int i = 0; i < MAX_POSTPRO_SHADERS; i++) UnloadShader(shaders[i]); for (int i = 0; i < MAX_POSTPRO_SHADERS; i++) UnloadShader(shaders[i]);

View File

@ -291,7 +291,7 @@ int main(void)
for (int i = 0; i < layers; ++i) for (int i = 0; i < layers; ++i)
{ {
Color clr = light; 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); 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 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; 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 x = 0.0f;
const float y = 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 tw = (srcRec.x+srcRec.width)/font.texture.width;
const float th = (srcRec.y+srcRec.height)/font.texture.height; 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); 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) #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 // Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0; int codepointByteCount = 0;
int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); int codepoint = GetCodepoint(&text[i], &codepointByteCount);
int index = GetGlyphIndex(font, codepoint); int index = GetGlyphIndex(font, codepoint);
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // 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++; lenCounter++;
int next = 0; int next = 0;
letter = GetNextCodepoint(&text[i], &next); letter = GetCodepoint(&text[i], &next);
index = GetGlyphIndex(font, letter); index = GetGlyphIndex(font, letter);
// NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // 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 // Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0; int codepointByteCount = 0;
int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); int codepoint = GetCodepoint(&text[i], &codepointByteCount);
int index = GetGlyphIndex(font, codepoint); int index = GetGlyphIndex(font, codepoint);
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // 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 == '~') else if (codepoint == '~')
{ {
if (GetNextCodepoint(&text[i+1], &codepointByteCount) == '~') if (GetCodepoint(&text[i+1], &codepointByteCount) == '~')
{ {
codepointByteCount += 1; codepointByteCount += 1;
wave = !wave; wave = !wave;
@ -698,7 +698,7 @@ Vector3 MeasureTextWave3D(Font font, const char* text, float fontSize, float fon
lenCounter++; lenCounter++;
int next = 0; int next = 0;
letter = GetNextCodepoint(&text[i], &next); letter = GetCodepoint(&text[i], &next);
index = GetGlyphIndex(font, letter); index = GetGlyphIndex(font, letter);
// NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // 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 != '\n')
{ {
if(letter == '~' && GetNextCodepoint(&text[i+1], &next) == '~') if (letter == '~' && GetCodepoint(&text[i+1], &next) == '~')
{ {
i++; i++;
} }

View File

@ -298,7 +298,7 @@ GenMeshTorus|Mesh|(float radius, float size, int radSeg, int sides);|
GenMeshKnot|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);| GenMeshHeightmap|Mesh|(Image heightmap, Vector3 size);|
GenMeshCubicmap|Mesh|(Image cubicmap, Vector3 cubeSize);| GenMeshCubicmap|Mesh|(Image cubicmap, Vector3 cubeSize);|
MeshBoundingBox|BoundingBox|(Mesh mesh);| GetMeshBoundingBox|BoundingBox|(Mesh mesh);|
MeshTangents|void|(Mesh *mesh);| MeshTangents|void|(Mesh *mesh);|
MeshBinormals|void|(Mesh *mesh);| MeshBinormals|void|(Mesh *mesh);|
DrawModel|void|(Model model, Vector3 position, float scale, Color tint);| DrawModel|void|(Model model, Vector3 position, float scale, Color tint);|

View File

@ -1549,7 +1549,7 @@
</KeyWord> </KeyWord>
<!-- Mesh manipulation functions --> <!-- Mesh manipulation functions -->
<KeyWord name="MeshBoundingBox" func="yes"> <KeyWord name="GetMeshBoundingBox" func="yes">
<Overload retVal="BoundingBox" descr="Compute mesh bounding box limits"> <Overload retVal="BoundingBox" descr="Compute mesh bounding box limits">
<Param name="Mesh mesh" /> <Param name="Mesh mesh" />
</Overload> </Overload>

View File

@ -2495,7 +2495,7 @@
</KeyWord> </KeyWord>
<!-- Mesh manipulation functions --> <!-- Mesh manipulation functions -->
<KeyWord name="MeshBoundingBox" func="yes"> <KeyWord name="GetMeshBoundingBox" func="yes">
<Overload retVal="BoundingBox" descr="Compute mesh bounding box limits"> <Overload retVal="BoundingBox" descr="Compute mesh bounding box limits">
<Param name="Mesh mesh" /> <Param name="Mesh mesh" />
</Overload> </Overload>

View File

@ -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 RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); // Generate cubes-based map mesh from image data
// Mesh manipulation functions // 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 MeshTangents(Mesh *mesh); // Compute mesh tangents
RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals

View File

@ -37,7 +37,7 @@
// Reconfigure standard input to receive key inputs, works with SSH connection. // Reconfigure standard input to receive key inputs, works with SSH connection.
#define SUPPORT_SSH_KEYBOARD_RPI 1 #define SUPPORT_SSH_KEYBOARD_RPI 1
// Draw a mouse pointer on screen // 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. // 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. // However, it can also reduce overall system performance, because the thread scheduler switches tasks more often.
#define SUPPORT_WINMM_HIGHRES_TIMER 1 #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. // Support saving binary data automatically to a generated storage.data file. This file is managed internally.
#define SUPPORT_DATA_STORAGE 1 #define SUPPORT_DATA_STORAGE 1
// Support automatic generated events, loading and recording of those events when required // 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 // core: Configuration values
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
@ -161,7 +165,6 @@
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions: #define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit() // 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() #define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit()

View File

@ -56,7 +56,7 @@
* WARNING: Reconfiguring standard input could lead to undesired effects, like breaking other running processes or * 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. * 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 * Draw a mouse pointer on screen
* *
* #define SUPPORT_BUSY_WAIT_LOOP * #define SUPPORT_BUSY_WAIT_LOOP
@ -387,7 +387,7 @@ typedef struct CoreData {
Point position; // Window position on screen (required on fullscreen toggle) Point position; // Window position on screen (required on fullscreen toggle)
Size display; // Display width and height (monitor, device-screen, LCD, ...) Size display; // Display width and height (monitor, device-screen, LCD, ...)
Size screen; // Screen width and height (used render area) 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) Size render; // Framebuffer width and height (render area, including black bars if required)
Point renderOffset; // Offset from render area (must be divided by 2) Point renderOffset; // Offset from render area (must be divided by 2)
Matrix screenScale; // Matrix to scale screen (framebuffer rendering) 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 // 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 bool InitGraphicsDevice(int width, int height); // Initialize graphics device
static void SetupFramebuffer(int width, int height); // Setup main framebuffer 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 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) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error 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) #if defined(PLATFORM_WEB)
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData); 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 EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData);
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *e, void *userData);
#endif #endif
#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) #if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
@ -673,7 +670,7 @@ static void PlayAutomationEvent(unsigned int frame);
#if defined(_WIN32) #if defined(_WIN32)
// NOTE: We include Sleep() function signature here to avoid windows.h inclusion (kernel32 lib) // 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 #endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -844,6 +841,9 @@ void InitWindow(int width, int height, const char *title)
// Init hi-res timer // Init hi-res timer
InitTimer(); InitTimer();
// Initialize random seed
srand((unsigned int)time(NULL));
#if defined(SUPPORT_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
// Load default font // Load default font
// NOTE: External functions (defined in module: text) // NOTE: External functions (defined in module: text)
@ -875,10 +875,14 @@ void InitWindow(int width, int height, const char *title)
#endif #endif
#if defined(PLATFORM_WEB) #if defined(PLATFORM_WEB)
// Check fullscreen change events // Check fullscreen change events(note this is done on the window since most
//emscripten_set_fullscreenchange_callback("#canvas", NULL, 1, EmscriptenFullscreenChangeCallback); // browsers don't support this on #canvas)
//emscripten_set_resize_callback("#canvas", NULL, 1, EmscriptenResizeCallback); 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 // Support keyboard events
//emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback); //emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
//emscripten_set_keydown_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 // TODO: Issues on HighDPI scaling
void SetWindowSize(int width, int height) void SetWindowSize(int width, int height)
{ {
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
glfwSetWindowSize(CORE.Window.handle, width, height); glfwSetWindowSize(CORE.Window.handle, width, height);
#endif #endif
#if defined(PLATFORM_WEB) #if defined(PLATFORM_WEB)
@ -1938,6 +1942,9 @@ void ClearBackground(Color color)
// Setup canvas (framebuffer) to start drawing // Setup canvas (framebuffer) to start drawing
void BeginDrawing(void) void BeginDrawing(void)
{ {
// 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.current = GetTime(); // Number of elapsed seconds since InitTimer()
CORE.Time.update = CORE.Time.current - CORE.Time.previous; CORE.Time.update = CORE.Time.current - CORE.Time.previous;
CORE.Time.previous = CORE.Time.current; CORE.Time.previous = CORE.Time.current;
@ -1952,22 +1959,22 @@ void BeginDrawing(void)
// End canvas drawing and swap buffers (double buffering) // End canvas drawing and swap buffers (double buffering)
void EndDrawing(void) void EndDrawing(void)
{ {
#if (defined(PLATFORM_RPI) || defined(PLATFORM_DRM)) && defined(SUPPORT_MOUSE_CURSOR_NATIVE) rlDrawRenderBatchActive(); // Update and draw internal render batch
// On native mode we have no system mouse cursor, so,
// we draw a small rectangle for user reference #if defined(SUPPORT_MOUSE_CURSOR_POINT)
// Draw a small rectangle on mouse position for user reference
if (!CORE.Input.Mouse.cursorHidden) if (!CORE.Input.Mouse.cursorHidden)
{ {
DrawRectangle(CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y, 3, 3, MAROON); DrawRectangle(CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y, 3, 3, MAROON);
rlDrawRenderBatchActive(); // Update and draw internal render batch
} }
#endif #endif
rlDrawRenderBatchActive(); // Update and draw internal render batch
#if defined(SUPPORT_GIF_RECORDING) #if defined(SUPPORT_GIF_RECORDING)
#define GIF_RECORD_FRAMERATE 10 // Draw record indicator
if (gifRecording) if (gifRecording)
{ {
#define GIF_RECORD_FRAMERATE 10
gifFramesCounter++; gifFramesCounter++;
// NOTE: We record one gif frame every 10 game frames // NOTE: We record one gif frame every 10 game frames
@ -1992,6 +1999,7 @@ void EndDrawing(void)
#endif #endif
#if defined(SUPPORT_EVENTS_AUTOMATION) #if defined(SUPPORT_EVENTS_AUTOMATION)
// Draw record/play indicator
if (eventsRecording) if (eventsRecording)
{ {
gifFramesCounter++; gifFramesCounter++;
@ -2018,7 +2026,8 @@ void EndDrawing(void)
} }
#endif #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 // Frame time control system
CORE.Time.current = GetTime(); CORE.Time.current = GetTime();
@ -2030,7 +2039,7 @@ void EndDrawing(void)
// Wait for some milliseconds... // Wait for some milliseconds...
if (CORE.Time.frame < CORE.Time.target) 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(); CORE.Time.current = GetTime();
double waitTime = CORE.Time.current - CORE.Time.previous; 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 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) #if defined(SUPPORT_EVENTS_AUTOMATION)
// Events recording and playing logic
if (eventsRecording) RecordAutomationEvent(CORE.Time.frameCounter); if (eventsRecording) RecordAutomationEvent(CORE.Time.frameCounter);
else if (eventsPlaying)
// TODO: When should we play? After/before/replace PollInputEvents()?
if (eventsPlaying)
{ {
// TODO: When should we play? After/before/replace PollInputEvents()?
if (CORE.Time.frameCounter >= eventCount) eventsPlaying = false; if (CORE.Time.frameCounter >= eventCount) eventsPlaying = false;
PlayAutomationEvent(CORE.Time.frameCounter); PlayAutomationEvent(CORE.Time.frameCounter);
} }
@ -2638,6 +2648,9 @@ void SetTargetFPS(int fps)
// NOTE: We calculate an average framerate // NOTE: We calculate an average framerate
int GetFPS(void) int GetFPS(void)
{ {
int fps = 0;
#if !defined(SUPPORT_CUSTOM_FRAME_CONTROL)
#define FPS_CAPTURE_FRAMES_COUNT 30 // 30 captures #define FPS_CAPTURE_FRAMES_COUNT 30 // 30 captures
#define FPS_AVERAGE_TIME_SECONDS 0.5f // 500 millisecondes #define FPS_AVERAGE_TIME_SECONDS 0.5f // 500 millisecondes
#define FPS_STEP (FPS_AVERAGE_TIME_SECONDS/FPS_CAPTURE_FRAMES_COUNT) #define FPS_STEP (FPS_AVERAGE_TIME_SECONDS/FPS_CAPTURE_FRAMES_COUNT)
@ -2658,7 +2671,10 @@ int GetFPS(void)
average += history[index]; 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) // Get time in seconds for last frame drawn (delta time)
@ -3540,6 +3556,17 @@ Vector2 GetMousePosition(void)
return position; 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 // Set mouse position XY
void SetMousePosition(int x, int y) void SetMousePosition(int x, int y)
{ {
@ -4661,8 +4688,6 @@ static void SetupFramebuffer(int width, int height)
// Initialize hi-resolution timer // Initialize hi-resolution timer
static void InitTimer(void) 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. // 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. // 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. // 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 // 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://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! // 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) #if defined(PLATFORM_UWP)
UWPGetSleepFunc()(ms/1000); UWPGetSleepFunc()(ms/1000);
@ -4737,8 +4762,70 @@ static void Wait(float ms)
#endif #endif
} }
// Poll (store) all input events // Swap back buffer with front buffer (screen drawing)
static void PollInputEvents(void) 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) #if defined(SUPPORT_GESTURES_SYSTEM)
// NOTE: Gestures update must be called every frame to reset gestures correctly // NOTE: Gestures update must be called every frame to reset gestures correctly
@ -5014,68 +5101,6 @@ static void PollInputEvents(void)
#endif #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) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
// GLFW3 Error Callback, runs on GLFW3 error // GLFW3 Error Callback, runs on GLFW3 error
static void ErrorCallback(int error, const char *description) 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); 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 // GLFW3 WindowSize Callback, runs when window is resizedLastFrame
// NOTE: Window resizing not allowed by default // NOTE: Window resizing not allowed by default
@ -5375,6 +5430,9 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
// Init hi-res timer // Init hi-res timer
InitTimer(); InitTimer();
// Initialize random seed
srand((unsigned int)time(NULL));
#if defined(SUPPORT_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
// Load default font // Load default font
// NOTE: External function (defined in module: text) // NOTE: External function (defined in module: text)
@ -6327,7 +6385,8 @@ static void *EventThread(void *arg)
#endif #endif
} }
} }
Wait(5); // Sleep for 5ms to avoid hogging CPU time
WaitTime(5); // Sleep for 5ms to avoid hogging CPU time
} }
close(worker->fd); 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
} }
} }

View File

@ -948,6 +948,8 @@ static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out,
/* @todo { unknown parameter } */ /* @todo { unknown parameter } */
} }
fclose(fp);
if (material.name) { if (material.name) {
/* Flush last material element */ /* Flush last material element */
materials = tinyobj_material_add(materials, num_materials, &material); materials = tinyobj_material_add(materials, num_materials, &material);

View File

@ -318,7 +318,7 @@ static unsigned int usedMemory = 0; // Total allocated d
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) #if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
// Timming measure functions // 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 unsigned long long int GetClockTicks(void); // Get hi-res MONOTONIC time measure in mseconds
static double GetCurrentTime(void); // Get current time measure in milliseconds static double GetCurrentTime(void); // Get current time measure in milliseconds
#endif #endif
@ -370,7 +370,7 @@ PHYSACDEF void InitPhysics(void)
{ {
#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) #if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
// Initialize high resolution timer // Initialize high resolution timer
InitTimer(); InitTimerHiRes();
#endif #endif
TRACELOG("[PHYSAC] Physics module initialized successfully\n"); 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) #if !defined(PHYSAC_AVOID_TIMMING_SYSTEM)
// Initializes hi-resolution MONOTONIC timer // Initializes hi-resolution MONOTONIC timer
static void InitTimer(void) static void InitTimerHiRes(void)
{ {
#if defined(_WIN32) #if defined(_WIN32)
QueryPerformanceFrequency((unsigned long long int *) &frequency); QueryPerformanceFrequency((unsigned long long int *) &frequency);

View File

@ -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); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]); 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) // Bind mesh VBO data: vertex texcoords (shader-location = 1)
rlEnableVertexBuffer(mesh.vboId[1]); rlEnableVertexBuffer(mesh.vboId[1]);
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0); 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 // Compute mesh tangents
// NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates // 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 // 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)); 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"); else TRACELOG(LOG_WARNING, "MESH: Tangents data already available, re-writting");
@ -2732,7 +2728,7 @@ void MeshTangents(Mesh *mesh)
} }
// Compute mesh binormals (aka bitangent) // Compute mesh binormals (aka bitangent)
void MeshBinormals(Mesh *mesh) void GenMeshBinormals(Mesh *mesh)
{ {
for (int i = 0; i < mesh->vertexCount; i++) 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 // output->framerate = // TODO: Use framerate instead of const timestep
// Name and parent bones // 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); 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; output->bones[j].parent = (data->nodes[j].parent != NULL) ? (int)(data->nodes[j].parent - data->nodes) : -1;

View File

@ -960,6 +960,14 @@ RLAPI const char *GetMonitorName(int monitor); // Get the hum
RLAPI void SetClipboardText(const char *text); // Set clipboard text content RLAPI void SetClipboardText(const char *text); // Set clipboard text content
RLAPI const char *GetClipboardText(void); // Get 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 // Cursor-related functions
RLAPI void ShowCursor(void); // Shows cursor RLAPI void ShowCursor(void); // Shows cursor
RLAPI void HideCursor(void); // Hides 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 GetMouseX(void); // Get mouse position X
RLAPI int GetMouseY(void); // Get mouse position Y RLAPI int GetMouseY(void); // Get mouse position Y
RLAPI Vector2 GetMousePosition(void); // Get mouse position XY 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 SetMousePosition(int x, int y); // Set mouse position XY
RLAPI void SetMouseOffset(int offsetX, int offsetY); // Set mouse offset RLAPI void SetMouseOffset(int offsetX, int offsetY); // Set mouse offset
RLAPI void SetMouseScale(float scaleX, float scaleY); // Set mouse scaling 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!) RLAPI char *TextToUtf8(int *codepoints, int length); // Encode text codepoint into utf8 text (memory must be freed!)
// UTF8 text strings management functions // 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 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) 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 // Mesh manipulation functions
RLAPI BoundingBox GetMeshBoundingBox(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 GenMeshTangents(Mesh *mesh); // Compute mesh tangents
RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals RLAPI void GenMeshBinormals(Mesh *mesh); // Compute mesh binormals
// Model drawing functions // Model drawing functions
RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set)

View File

@ -138,7 +138,7 @@
typedef struct float3 { float v[3]; } float3; typedef struct float3 { float v[3]; } float3;
typedef struct float16 { float v[16]; } float16; typedef struct float16 { float v[16]; } float16;
#include <math.h> // Required for: sinf(), cosf(), sqrtf(), tan(), fabs() #include <math.h> // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), fminf(), fmaxf(), fabs()
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition - Utils math // Module Functions Definition - Utils math

View File

@ -297,14 +297,6 @@ typedef struct RenderBatch {
typedef enum { false, true } bool; typedef enum { false, true } bool;
#endif #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 // Texture type
// NOTE: Data stored in GPU memory // NOTE: Data stored in GPU memory
typedef struct Texture2D { typedef struct Texture2D {
@ -881,7 +873,7 @@ static char *rlGetCompressedFormatName(int format); // Get compressed format off
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
#if defined(GRAPHICS_API_OPENGL_11) #if defined(GRAPHICS_API_OPENGL_11)
static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHeight); // Generate mipmaps data on CPU side 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 unsigned char *rlGenNextMipmapData(unsigned char *srcData, int srcWidth, int srcHeight); // Generate next mipmap level on CPU side
#endif #endif
static int rlGetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture) 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; width = baseWidth;
height = baseHeight; height = baseHeight;
size = (width*height*4); size = (width*height*4); // RGBA: 4 bytes
// Generate mipmaps // Generate mipmaps
// NOTE: Every mipmap data is stored after data // NOTE: Every mipmap data is stored after data (RGBA - 4 bytes)
Color *image = (Color *)RL_MALLOC(width*height*sizeof(Color)); unsigned char *image = (unsigned char *)RL_MALLOC(width*height*4);
Color *mipmap = NULL; unsigned char *mipmap = NULL;
int offset = 0; int offset = 0;
int j = 0;
for (int i = 0; i < size; i += 4) for (int i = 0; i < size; i += 4)
{ {
image[j].r = data[i]; image[i] = data[i];
image[j].g = data[i + 1]; image[i + 1] = data[i + 1];
image[j].b = data[i + 2]; image[i + 2] = data[i + 2];
image[j].a = data[i + 3]; image[i + 3] = data[i + 3];
j++;
} }
TRACELOGD("TEXTURE: Mipmap base size (%ix%i)", width, height); 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); mipmap = rlGenNextMipmapData(image, width, height);
offset += (width*height*4); // Size of last mipmap offset += (width*height*4); // Size of last mipmap
j = 0;
width /= 2; width /= 2;
height /= 2; height /= 2;
@ -3991,11 +3980,10 @@ static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHei
// Add mipmap to data // Add mipmap to data
for (int i = 0; i < size; i += 4) for (int i = 0; i < size; i += 4)
{ {
data[offset + i] = mipmap[j].r; data[offset + i] = mipmap[i];
data[offset + i + 1] = mipmap[j].g; data[offset + i + 1] = mipmap[i + 1];
data[offset + i + 2] = mipmap[j].b; data[offset + i + 2] = mipmap[i + 2];
data[offset + i + 3] = mipmap[j].a; data[offset + i + 3] = mipmap[i + 3];
j++;
} }
RL_FREE(image); RL_FREE(image);
@ -4010,15 +3998,17 @@ static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHei
} }
// Manual mipmap generation (basic scaling algorithm) // 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; int x2 = 0;
Color prow, pcol; int y2 = 0;
unsigned char prow[4];
unsigned char pcol[4];
int width = srcWidth/2; int width = srcWidth/2;
int height = srcHeight/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) // Scaling algorithm works perfectly (box-filter)
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
@ -4029,20 +4019,20 @@ static Color *rlGenNextMipmapData(Color *srcData, int srcWidth, int srcHeight)
{ {
x2 = 2*x; x2 = 2*x;
prow.r = (srcData[y2*srcWidth + x2].r + srcData[y2*srcWidth + x2 + 1].r)/2; prow[0] = (srcData[(y2*srcWidth + x2)*4 + 0] + srcData[(y2*srcWidth + x2 + 1)*4 + 0])/2;
prow.g = (srcData[y2*srcWidth + x2].g + srcData[y2*srcWidth + x2 + 1].g)/2; prow[1] = (srcData[(y2*srcWidth + x2)*4 + 1] + srcData[(y2*srcWidth + x2 + 1)*4 + 1])/2;
prow.b = (srcData[y2*srcWidth + x2].b + srcData[y2*srcWidth + x2 + 1].b)/2; prow[2] = (srcData[(y2*srcWidth + x2)*4 + 2] + srcData[(y2*srcWidth + x2 + 1)*4 + 2])/2;
prow.a = (srcData[y2*srcWidth + x2].a + srcData[y2*srcWidth + x2 + 1].a)/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[0] = (srcData[((y2 + 1)*srcWidth + x2)*4 + 0] + srcData[((y2 + 1)*srcWidth + x2 + 1)*4 + 0])/2;
pcol.g = (srcData[(y2+1)*srcWidth + x2].g + srcData[(y2+1)*srcWidth + x2 + 1].g)/2; pcol[1] = (srcData[((y2 + 1)*srcWidth + x2)*4 + 1] + srcData[((y2 + 1)*srcWidth + x2 + 1)*4 + 1])/2;
pcol.b = (srcData[(y2+1)*srcWidth + x2].b + srcData[(y2+1)*srcWidth + x2 + 1].b)/2; pcol[2] = (srcData[((y2 + 1)*srcWidth + x2)*4 + 2] + srcData[((y2 + 1)*srcWidth + x2 + 1)*4 + 2])/2;
pcol.a = (srcData[(y2+1)*srcWidth + x2].a + srcData[(y2+1)*srcWidth + x2 + 1].a)/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)*4 + 0] = (prow[0] + pcol[0])/2;
mipmap[y*width + x].g = (prow.g + pcol.g)/2; mipmap[(y*width + x)*4 + 1] = (prow[1] + pcol[1])/2;
mipmap[y*width + x].b = (prow.b + pcol.b)/2; mipmap[(y*width + x)*4 + 2] = (prow[2] + pcol[2])/2;
mipmap[y*width + x].a = (prow.a + pcol.a)/2; mipmap[(y*width + x)*4 + 3] = (prow[3] + pcol[3])/2;
} }
} }

View File

@ -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 // Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0; int codepointByteCount = 0;
int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); int codepoint = GetCodepoint(&text[i], &codepointByteCount);
int index = GetGlyphIndex(font, codepoint); int index = GetGlyphIndex(font, codepoint);
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // 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 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 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 // Word/character wrapping mechanism variables
enum { MEASURE_STATE = 0, DRAW_STATE = 1 }; 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 // Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0; int codepointByteCount = 0;
int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); int codepoint = GetCodepoint(&text[i], &codepointByteCount);
int index = GetGlyphIndex(font, codepoint); int index = GetGlyphIndex(font, codepoint);
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // 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; if (codepoint == 0x3f) codepointByteCount = 1;
i += (codepointByteCount - 1); i += (codepointByteCount - 1);
int glyphWidth = 0; float glyphWidth = 0;
if (codepoint != '\n') if (codepoint != '\n')
{ {
glyphWidth = (font.chars[index].advanceX == 0)? glyphWidth = (font.chars[index].advanceX == 0) ? font.recs[index].width*scaleFactor : font.chars[index].advanceX*scaleFactor;
(int)(font.recs[index].width*scaleFactor + spacing):
(int)(font.chars[index].advanceX*scaleFactor + spacing); 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 // 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 // Ref: http://jkorpela.fi/chars/spaces.html
if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i; if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i;
if ((textOffsetX + glyphWidth + 1) >= rec.width) if ((textOffsetX + glyphWidth) > rec.width)
{ {
endLine = (endLine < 1)? i : endLine; endLine = (endLine < 1)? i : endLine;
if (i == endLine) endLine -= codepointByteCount; 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) else if ((i + 1) == length)
{ {
endLine = i; endLine = i;
state = !state; state = !state;
} }
else if (codepoint == '\n') 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) if (!wordWrap)
{ {
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
textOffsetX = 0; textOffsetX = 0;
} }
} }
else 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; textOffsetX = 0;
} }
// When text overflows rectangle height limit, just stop drawing // 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 // Draw selection background
bool isGlyphSelected = false; bool isGlyphSelected = false;
if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength))) 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; isGlyphSelected = true;
} }
@ -1011,7 +1010,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
if (wordWrap && (i == endLine)) if (wordWrap && (i == endLine))
{ {
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
textOffsetX = 0; textOffsetX = 0;
startLine = endLine; startLine = endLine;
endLine = -1; endLine = -1;
@ -1090,7 +1089,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
lenCounter++; lenCounter++;
int next = 0; int next = 0;
letter = GetNextCodepoint(&text[i], &next); letter = GetCodepoint(&text[i], &next);
index = GetGlyphIndex(font, letter); index = GetGlyphIndex(font, letter);
// NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // 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; return utf8;
} }
// Get all codepoints in a string, codepoints count returned by parameters // Load all codepoints from a UTF8 text string, codepoints count returned by parameter
// REQUIRES: memset() int *LoadCodepoints(const char *text, int *count)
int *GetCodepoints(const char *text, int *count)
{ {
static int codepoints[MAX_TEXT_UNICODE_CHARS] = { 0 }; int textLength = TextLength(text);
memset(codepoints, 0, MAX_TEXT_UNICODE_CHARS*sizeof(int));
int bytesProcessed = 0; int bytesProcessed = 0;
int textLength = TextLength(text);
int codepointsCount = 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++) for (int i = 0; i < textLength; codepointsCount++)
{ {
codepoints[codepointsCount] = GetNextCodepoint(text + i, &bytesProcessed); codepoints[codepointsCount] = GetCodepoint(text + i, &bytesProcessed);
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; *count = codepointsCount;
return codepoints; 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 // 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 // NOTE: If an invalid UTF8 sequence is encountered a '?'(0x3f) codepoint is counted instead
int GetCodepointsCount(const char *text) int GetCodepointsCount(const char *text)
@ -1596,7 +1605,7 @@ int GetCodepointsCount(const char *text)
while (*ptr != '\0') while (*ptr != '\0')
{ {
int next = 0; int next = 0;
int letter = GetNextCodepoint(ptr, &next); int letter = GetCodepoint(ptr, &next);
if (letter == 0x3f) ptr += 1; if (letter == 0x3f) ptr += 1;
else ptr += next; 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 // NOTE: the standard says U+FFFD should be returned in case of errors
// but that character is not supported by the default font in raylib // but that character is not supported by the default font in raylib
// TODO: Optimize this code for speed!! // 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 UTF8 specs from https://www.ietf.org/rfc/rfc3629.txt

View File

@ -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 // Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0; int codepointByteCount = 0;
int codepoint = GetNextCodepoint(&text[i], &codepointByteCount); int codepoint = GetCodepoint(&text[i], &codepointByteCount);
int index = GetGlyphIndex(font, codepoint); int index = GetGlyphIndex(font, codepoint);
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)