Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Daniel Tasada 2026-01-29 18:14:17 +01:00
commit f79c0d66ca
59 changed files with 1492 additions and 1249 deletions

View File

@ -84,8 +84,10 @@ jobs:
- name: Upload Artifacts - name: Upload Artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: ${{ env.RELEASE_NAME }}.tar.gz name: ${{ env.RELEASE_NAME }}
path: ./build/${{ env.RELEASE_NAME }}.tar.gz path: |
./build/${{ env.RELEASE_NAME }}
!./build/${{ env.RELEASE_NAME }}.tar.gz
- name: Upload Artifact to Release - name: Upload Artifact to Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1

View File

@ -114,8 +114,10 @@ jobs:
- name: Upload Artifacts - name: Upload Artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: ${{ env.RELEASE_NAME }}.tar.gz name: ${{ env.RELEASE_NAME }}
path: ./build/${{ env.RELEASE_NAME }}.tar.gz path: |
./build/${{ env.RELEASE_NAME }}
!./build/${{ env.RELEASE_NAME }}.tar.gz
- name: Upload Artifact to Release - name: Upload Artifact to Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1

View File

@ -101,8 +101,10 @@ jobs:
- name: Upload Artifacts - name: Upload Artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: ${{ env.RELEASE_NAME }}.tar.gz name: ${{ env.RELEASE_NAME }}
path: ./build/${{ env.RELEASE_NAME }}.tar.gz path: |
./build/${{ env.RELEASE_NAME }}
!./build/${{ env.RELEASE_NAME }}.tar.gz
- name: Upload Artifact to Release - name: Upload Artifact to Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1

View File

@ -71,8 +71,10 @@ jobs:
- name: Upload Artifacts - name: Upload Artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: ${{ env.RELEASE_NAME }}.zip name: ${{ env.RELEASE_NAME }}
path: ./build/${{ env.RELEASE_NAME }}.zip path: |
./build/${{ env.RELEASE_NAME }}
!./build/${{ env.RELEASE_NAME }}.zip
- name: Upload Artifact to Release - name: Upload Artifact to Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1

View File

@ -142,8 +142,10 @@ jobs:
- name: Upload Artifacts - name: Upload Artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: ${{ env.RELEASE_NAME }}.zip name: ${{ env.RELEASE_NAME }}
path: ./build/${{ env.RELEASE_NAME }}.zip path: |
./build/${{ env.RELEASE_NAME }}
!./build/${{ env.RELEASE_NAME }}.zip
- name: Upload Artifact to Release - name: Upload Artifact to Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1

View File

@ -226,10 +226,10 @@ void UpdateCameraCenterInsideMap(Camera2D *camera, Player *player, EnvItem *envI
Vector2 max = GetWorldToScreen2D((Vector2){ maxX, maxY }, *camera); Vector2 max = GetWorldToScreen2D((Vector2){ maxX, maxY }, *camera);
Vector2 min = GetWorldToScreen2D((Vector2){ minX, minY }, *camera); Vector2 min = GetWorldToScreen2D((Vector2){ minX, minY }, *camera);
if (max.x < width) camera->offset.x = width - (max.x - width/2); if (max.x < width) camera->offset.x = width - (max.x - (float)width/2);
if (max.y < height) camera->offset.y = height - (max.y - height/2); if (max.y < height) camera->offset.y = height - (max.y - (float)height/2);
if (min.x > 0) camera->offset.x = width/2 - min.x; if (min.x > 0) camera->offset.x = (float)width/2 - min.x;
if (min.y > 0) camera->offset.y = height/2 - min.y; if (min.y > 0) camera->offset.y = (float)height/2 - min.y;
} }
void UpdateCameraCenterSmoothFollow(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height) void UpdateCameraCenterSmoothFollow(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height)

View File

@ -225,10 +225,10 @@ int main(void)
Vector2 max = GetWorldToScreen2D((Vector2){ maxX, maxY }, camera); Vector2 max = GetWorldToScreen2D((Vector2){ maxX, maxY }, camera);
Vector2 min = GetWorldToScreen2D((Vector2){ minX, minY }, camera); Vector2 min = GetWorldToScreen2D((Vector2){ minX, minY }, camera);
if (max.x < screenWidth) camera.offset.x = screenWidth - (max.x - screenWidth/2); if (max.x < screenWidth) camera.offset.x = screenWidth - (max.x - (float)screenWidth/2);
if (max.y < screenHeight) camera.offset.y = screenHeight - (max.y - screenHeight/2); if (max.y < screenHeight) camera.offset.y = screenHeight - (max.y - (float)screenHeight/2);
if (min.x > 0) camera.offset.x = screenWidth/2 - min.x; if (min.x > 0) camera.offset.x = (float)screenWidth/2 - min.x;
if (min.y > 0) camera.offset.y = screenHeight/2 - min.y; if (min.y > 0) camera.offset.y = (float)screenHeight/2 - min.y;
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Events management // Events management

View File

@ -216,7 +216,7 @@ static void KeepAspectCenteredInteger(int screenWidth, int screenHeight, int gam
static void KeepHeightCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect) static void KeepHeightCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
{ {
const float resizeRatio = (float)(screenHeight/gameHeight); const float resizeRatio = (float)screenHeight/gameHeight;
sourceRect->x = 0.0f; sourceRect->x = 0.0f;
sourceRect->y = 0.0f; sourceRect->y = 0.0f;
sourceRect->width = (float)(int)(screenWidth/resizeRatio); sourceRect->width = (float)(int)(screenWidth/resizeRatio);
@ -230,7 +230,7 @@ static void KeepHeightCenteredInteger(int screenWidth, int screenHeight, int gam
static void KeepWidthCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect) static void KeepWidthCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
{ {
const float resizeRatio = (float)(screenWidth/gameWidth); const float resizeRatio = (float)screenWidth/gameWidth;
sourceRect->x = 0.0f; sourceRect->x = 0.0f;
sourceRect->y = 0.0f; sourceRect->y = 0.0f;
sourceRect->width = (float)gameWidth; sourceRect->width = (float)gameWidth;

View File

@ -413,7 +413,7 @@ static MsfGifBuffer * msf_compress_frame(void * allocContext, int width, int hei
//generate palette //generate palette
typedef struct { uint8_t r, g, b; } Color3; typedef struct { uint8_t r, g, b; } Color3;
Color3 table[256] = { {0} }; Color3 table[256] = { { 0 } };
int tableIdx = 1; //we start counting at 1 because 0 is the transparent color int tableIdx = 1; //we start counting at 1 because 0 is the transparent color
//transparent is always last in the table //transparent is always last in the table
tlb[tlbSize-1] = 0; tlb[tlbSize-1] = 0;
@ -550,7 +550,7 @@ static void msf_free_gif_state(MsfGifState * handle) {
int msf_gif_begin(MsfGifState * handle, int width, int height) { MsfTimeFunc int msf_gif_begin(MsfGifState * handle, int width, int height) { MsfTimeFunc
//NOTE: we cannot stomp the entire struct to zero because we must preserve `customAllocatorContext`. //NOTE: we cannot stomp the entire struct to zero because we must preserve `customAllocatorContext`.
MsfCookedFrame empty = {0}; //god I hate MSVC... MsfCookedFrame empty = { 0 }; //god I hate MSVC...
handle->previousFrame = empty; handle->previousFrame = empty;
handle->currentFrame = empty; handle->currentFrame = empty;
handle->width = width; handle->width = width;
@ -614,7 +614,7 @@ int msf_gif_frame(MsfGifState * handle, uint8_t * pixelData, int centiSecondsPer
} }
MsfGifResult msf_gif_end(MsfGifState * handle) { MsfTimeFunc MsfGifResult msf_gif_end(MsfGifState * handle) { MsfTimeFunc
if (!handle->listHead) { MsfGifResult empty = {0}; return empty; } if (!handle->listHead) { MsfGifResult empty = { 0 }; return empty; }
//first pass: determine total size //first pass: determine total size
size_t total = 1; //1 byte for trailing marker size_t total = 1; //1 byte for trailing marker

View File

@ -183,7 +183,7 @@ int main(void)
if (showModel) DrawModel(model, (Vector3){0.0f, 0.0f, 0.0f}, 1.0f, WHITE); if (showModel) DrawModel(model, (Vector3){0.0f, 0.0f, 0.0f}, 1.0f, WHITE);
// Draw the decal models // Draw the decal models
for (int i = 0; i < decalCount; i++) DrawModel(decalModels[i], (Vector3){0}, 1.0f, WHITE); for (int i = 0; i < decalCount; i++) DrawModel(decalModels[i], (Vector3){ 0 }, 1.0f, WHITE);
// If we hit the mesh, draw the box for the decal // If we hit the mesh, draw the box for the decal
if (collision.hit) if (collision.hit)
@ -191,7 +191,7 @@ int main(void)
Vector3 origin = Vector3Add(collision.point, Vector3Scale(collision.normal, 1.0f)); Vector3 origin = Vector3Add(collision.point, Vector3Scale(collision.normal, 1.0f));
Matrix splat = MatrixLookAt(collision.point, origin, (Vector3){0,1,0}); Matrix splat = MatrixLookAt(collision.point, origin, (Vector3){0,1,0});
placementCube.transform = MatrixInvert(splat); placementCube.transform = MatrixInvert(splat);
DrawModel(placementCube, (Vector3){0}, 1.0f, Fade(WHITE, 0.5f)); DrawModel(placementCube, (Vector3){ 0 }, 1.0f, Fade(WHITE, 0.5f));
} }
DrawGrid(10, 10.0f); DrawGrid(10, 10.0f);

View File

@ -148,25 +148,25 @@ void DrawSphereBasic(Color color)
{ {
for (int j = 0; j < slices; j++) for (int j = 0; j < slices; j++)
{ {
rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*i))*sinf(DEG2RAD*(j*360.0f/slices)),
sinf(DEG2RAD*(270+(180/(rings + 1))*i)), sinf(DEG2RAD*(270+(180.0f/(rings + 1))*i)),
cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); cosf(DEG2RAD*(270+(180.0f/(rings + 1))*i))*cosf(DEG2RAD*(j*360.0f/slices)));
rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360.0f/slices)),
sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), sinf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1))),
cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360.0f/slices)));
rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)), rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360.0f/slices)),
sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), sinf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1))),
cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices))); cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360.0f/slices)));
rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*i))*sinf(DEG2RAD*(j*360.0f/slices)),
sinf(DEG2RAD*(270+(180/(rings + 1))*i)), sinf(DEG2RAD*(270+(180.0f/(rings + 1))*i)),
cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); cosf(DEG2RAD*(270+(180.0f/(rings + 1))*i))*cosf(DEG2RAD*(j*360.0f/slices)));
rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*sinf(DEG2RAD*((j+1)*360/slices)), rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i)))*sinf(DEG2RAD*((j+1)*360.0f/slices)),
sinf(DEG2RAD*(270+(180/(rings + 1))*(i))), sinf(DEG2RAD*(270+(180.0f/(rings + 1))*(i))),
cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*cosf(DEG2RAD*((j+1)*360/slices))); cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i)))*cosf(DEG2RAD*((j+1)*360.0f/slices)));
rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360.0f/slices)),
sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), sinf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1))),
cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360.0f/slices)));
} }
} }
rlEnd(); rlEnd();

View File

@ -85,9 +85,9 @@ int main(void)
// Calculate the cube position // Calculate the cube position
Vector3 cubePos = { Vector3 cubePos = {
(float)(x - numBlocks/2)*(scale*3.0f) + scatter, (float)(x - (float)numBlocks/2)*(scale*3.0f) + scatter,
(float)(y - numBlocks/2)*(scale*2.0f) + scatter, (float)(y - (float)numBlocks/2)*(scale*2.0f) + scatter,
(float)(z - numBlocks/2)*(scale*3.0f) + scatter (float)(z - (float)numBlocks/2)*(scale*3.0f) + scatter
}; };
// Pick a color with a hue depending on cube position for the rainbow color effect // Pick a color with a hue depending on cube position for the rainbow color effect

View File

@ -258,8 +258,8 @@ int main(void)
UnloadImage(pattern); UnloadImage(pattern);
mode = MODE_PAUSE; mode = MODE_PAUSE;
offsetX = worldWidth*presetPatterns[preset].position.x - windowWidth/zoom/2.0f; offsetX = worldWidth*presetPatterns[preset].position.x - (float)windowWidth/zoom/2.0f;
offsetY = worldHeight*presetPatterns[preset].position.y - windowHeight/zoom/2.0f; offsetY = worldHeight*presetPatterns[preset].position.y - (float)windowHeight/zoom/2.0f;
} }
// Check window draw inside world limits // Check window draw inside world limits

View File

@ -65,7 +65,7 @@ int main(void)
Shader shdrRaster = LoadShader(0, TextFormat("resources/shaders/glsl%i/hybrid_raster.fs", GLSL_VERSION)); Shader shdrRaster = LoadShader(0, TextFormat("resources/shaders/glsl%i/hybrid_raster.fs", GLSL_VERSION));
// Declare Struct used to store camera locs // Declare Struct used to store camera locs
RayLocs marchLocs = {0}; RayLocs marchLocs = { 0 };
// Fill the struct with shader locs // Fill the struct with shader locs
marchLocs.camPos = GetShaderLocation(shdrRaymarch, "camPos"); marchLocs.camPos = GetShaderLocation(shdrRaymarch, "camPos");

View File

@ -41,7 +41,7 @@ int main(void)
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - vertex displacement"); InitWindow(screenWidth, screenHeight, "raylib [shaders] example - vertex displacement");
// set up camera // set up camera
Camera camera = {0}; Camera camera = { 0 };
camera.position = (Vector3) {20.0f, 5.0f, -20.0f}; camera.position = (Vector3) {20.0f, 5.0f, -20.0f};
camera.target = (Vector3) {0.0f, 0.0f, 0.0f}; camera.target = (Vector3) {0.0f, 0.0f, 0.0f};
camera.up = (Vector3) {0.0f, 1.0f, 0.0f}; camera.up = (Vector3) {0.0f, 1.0f, 0.0f};

View File

@ -58,7 +58,7 @@ int main(void)
int ballCount = 1; int ballCount = 1;
Ball *grabbedBall = NULL; // A pointer to the current ball that is grabbed Ball *grabbedBall = NULL; // A pointer to the current ball that is grabbed
Vector2 pressOffset = {0}; // Mouse press offset relative to the ball that grabbedd Vector2 pressOffset = { 0 }; // Mouse press offset relative to the ball that grabbedd
float gravity = 100; // World gravity float gravity = 100; // World gravity

View File

@ -45,7 +45,7 @@ int main(void)
for (int i = 0; i < MAX_COLORS_COUNT; i++) for (int i = 0; i < MAX_COLORS_COUNT; i++)
{ {
colorsRecs[i].x = 20.0f + 100.0f *(i%7) + 10.0f *(i%7); colorsRecs[i].x = 20.0f + 100.0f *(i%7) + 10.0f *(i%7);
colorsRecs[i].y = 80.0f + 100.0f *(i/7) + 10.0f *(i/7); colorsRecs[i].y = 80.0f + 100.0f *((float)i/7) + 10.0f *((float)i/7);
colorsRecs[i].width = 100.0f; colorsRecs[i].width = 100.0f;
colorsRecs[i].height = 100.0f; colorsRecs[i].height = 100.0f;
} }

View File

@ -311,7 +311,7 @@ static void DrawDisplaySegment(Vector2 center, int length, int thick, bool verti
(Vector2){ center.x + thick/2.0f, center.y - length/2.0f }, // Point 3 (Vector2){ center.x + thick/2.0f, center.y - length/2.0f }, // Point 3
(Vector2){ center.x - thick/2.0f, center.y + length/2.0f }, // Point 4 (Vector2){ center.x - thick/2.0f, center.y + length/2.0f }, // Point 4
(Vector2){ center.x + thick/2.0f, center.y + length/2.0f }, // Point 5 (Vector2){ center.x + thick/2.0f, center.y + length/2.0f }, // Point 5
(Vector2){ center.x, center.y + length/2 + thick/2.0f }, // Point 6 (Vector2){ center.x, center.y + (float)length/2 + thick/2.0f }, // Point 6
}; };
DrawTriangleStrip(segmentPointsV, 6, color); DrawTriangleStrip(segmentPointsV, 6, color);

View File

@ -49,8 +49,8 @@ int main(void)
float totalM = m1 + m2; float totalM = m1 + m2;
Vector2 previousPosition = CalculateDoublePendulumEndPoint(l1, theta1, l2, theta2); Vector2 previousPosition = CalculateDoublePendulumEndPoint(l1, theta1, l2, theta2);
previousPosition.x += (screenWidth/2); previousPosition.x += ((float)screenWidth/2);
previousPosition.y += (screenHeight/2 - 100); previousPosition.y += ((float)screenHeight/2 - 100);
// Scale length // Scale length
float L1 = l1*lengthScaler; float L1 = l1*lengthScaler;
@ -105,8 +105,8 @@ int main(void)
// Calculate position // Calculate position
Vector2 currentPosition = CalculateDoublePendulumEndPoint(l1, theta1, l2, theta2); Vector2 currentPosition = CalculateDoublePendulumEndPoint(l1, theta1, l2, theta2);
currentPosition.x += screenWidth/2; currentPosition.x += (float)screenWidth/2;
currentPosition.y += screenHeight/2 - 100; currentPosition.y += (float)screenHeight/2 - 100;
// Draw to render texture // Draw to render texture
BeginTextureMode(target); BeginTextureMode(target);

View File

@ -49,8 +49,8 @@ int main(void)
bool showPercentages = false; bool showPercentages = false;
bool showDonut = false; bool showDonut = false;
int hoveredSlice = -1; int hoveredSlice = -1;
Rectangle scrollPanelBounds = {0}; Rectangle scrollPanelBounds = { 0 };
Vector2 scrollContentOffset = {0}; Vector2 scrollContentOffset = { 0 };
Rectangle view = { 0 }; Rectangle view = { 0 };
// UI layout parameters // UI layout parameters

View File

@ -113,7 +113,7 @@ int main(void)
// Set the text (using markdown!) // Set the text (using markdown!)
char text[64] = "Hello ~~World~~ in 3D!"; char text[64] = "Hello ~~World~~ in 3D!";
Vector3 tbox = {0}; Vector3 tbox = { 0 };
int layers = 1; int layers = 1;
int quads = 0; int quads = 0;
float layerDistance = 0.01f; float layerDistance = 0.01f;
@ -133,7 +133,7 @@ int main(void)
Shader alphaDiscard = LoadShader(NULL, TextFormat("resources/shaders/glsl%i/alpha_discard.fs", GLSL_VERSION)); Shader alphaDiscard = LoadShader(NULL, TextFormat("resources/shaders/glsl%i/alpha_discard.fs", GLSL_VERSION));
// Array filled with multiple random colors (when multicolor mode is set) // Array filled with multiple random colors (when multicolor mode is set)
Color multi[TEXT_MAX_LAYERS] = {0}; Color multi[TEXT_MAX_LAYERS] = { 0 };
DisableCursor(); // Limit cursor to relative movement inside the window DisableCursor(); // Limit cursor to relative movement inside the window

View File

@ -97,8 +97,8 @@ int main(void)
if (currentFont == 0) textSize = MeasureTextEx(fontDefault, msg, fontSize, 0); if (currentFont == 0) textSize = MeasureTextEx(fontDefault, msg, fontSize, 0);
else textSize = MeasureTextEx(fontSDF, msg, fontSize, 0); else textSize = MeasureTextEx(fontSDF, msg, fontSize, 0);
fontPosition.x = GetScreenWidth()/2 - textSize.x/2; fontPosition.x = (float)GetScreenWidth()/2 - textSize.x/2;
fontPosition.y = GetScreenHeight()/2 - textSize.y/2 + 80; fontPosition.y = (float)GetScreenHeight()/2 - textSize.y/2 + 80;
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Draw // Draw

View File

@ -180,12 +180,12 @@ static void DrawTextStyled(Font font, const char *text, Vector2 position, float
if (text[i - 1] == 'c') if (text[i - 1] == 'c')
{ {
colFront = GetColor(colHexValue); colFront = GetColor(colHexValue);
colFront.a = (unsigned char)(colFront.a * (float)color.a/255.0f); //colFront.a *= (unsigned char)(colFront.a*(float)color.a/255.0f); // TODO: Review
} }
else if (text[i - 1] == 'b') else if (text[i - 1] == 'b')
{ {
colBack = GetColor(colHexValue); colBack = GetColor(colHexValue);
colBack.a *= (unsigned char)(colFront.a * (float)color.a / 255.0f); //colBack.a *= (unsigned char)(colFront.a*(float)color.a/255.0f);
} }
i += (colHexCount + 1); // Skip color value retrieved and ']' i += (colHexCount + 1); // Skip color value retrieved and ']'

View File

@ -226,7 +226,7 @@ static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec,
{ {
if (!wordWrap) if (!wordWrap)
{ {
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
textOffsetX = 0; textOffsetX = 0;
} }
} }
@ -234,7 +234,7 @@ static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec,
{ {
if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width)) if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width))
{ {
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
textOffsetX = 0; textOffsetX = 0;
} }
@ -258,7 +258,7 @@ static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec,
if (wordWrap && (i == endLine)) if (wordWrap && (i == endLine))
{ {
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
textOffsetX = 0; textOffsetX = 0;
startLine = endLine; startLine = endLine;
endLine = -1; endLine = -1;

View File

@ -65,7 +65,7 @@ int main(void)
TextParticle textParticles[MAX_TEXT_PARTICLES] = { 0 }; TextParticle textParticles[MAX_TEXT_PARTICLES] = { 0 };
int particleCount = 0; int particleCount = 0;
TextParticle *grabbedTextParticle = NULL; TextParticle *grabbedTextParticle = NULL;
Vector2 pressOffset = {0}; Vector2 pressOffset = { 0 };
PrepareFirstTextParticle("raylib => fun videogames programming!", textParticles, &particleCount); PrepareFirstTextParticle("raylib => fun videogames programming!", textParticles, &particleCount);

View File

@ -277,7 +277,7 @@ int main(void)
DrawTriangle(a, b, c, emoji[selected].color); DrawTriangle(a, b, c, emoji[selected].color);
// Draw the main text message // Draw the main text message
Rectangle textRect = { msgRect.x + horizontalPadding/2, msgRect.y + verticalPadding/2, msgRect.width - horizontalPadding, msgRect.height }; Rectangle textRect = { msgRect.x + (float)horizontalPadding/2, msgRect.y + (float)verticalPadding/2, msgRect.width - horizontalPadding, msgRect.height };
DrawTextBoxed(*font, messages[message].text, textRect, (float)font->baseSize, 1.0f, true, WHITE); DrawTextBoxed(*font, messages[message].text, textRect, (float)font->baseSize, 1.0f, true, WHITE);
// Draw the info text below the main message // Draw the info text below the main message
@ -421,7 +421,7 @@ static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec,
{ {
if (!wordWrap) if (!wordWrap)
{ {
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
textOffsetX = 0; textOffsetX = 0;
} }
} }
@ -429,7 +429,7 @@ static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec,
{ {
if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width)) if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width))
{ {
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
textOffsetX = 0; textOffsetX = 0;
} }
@ -453,7 +453,7 @@ static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec,
if (wordWrap && (i == endLine)) if (wordWrap && (i == endLine))
{ {
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor; textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
textOffsetX = 0; textOffsetX = 0;
startLine = endLine; startLine = endLine;
endLine = -1; endLine = -1;

View File

@ -41,7 +41,7 @@ int main(void)
InitWindow(screenWidth, screenHeight, "raylib [text] example - words alignment"); InitWindow(screenWidth, screenHeight, "raylib [text] example - words alignment");
// Define the rectangle we will draw the text in // Define the rectangle we will draw the text in
Rectangle textContainerRect = (Rectangle){ screenWidth/2-screenWidth/4, screenHeight/2-screenHeight/3, screenWidth/2, screenHeight*2/3 }; Rectangle textContainerRect = (Rectangle){ (float)screenWidth/2-(float)screenWidth/4, (float)screenHeight/2-(float)screenHeight/3, (float)screenWidth/2, (float)screenHeight*2/3 };
// Some text to display the current alignment // Some text to display the current alignment
const char *textAlignNameH[] = { "Left", "Centre", "Right" }; const char *textAlignNameH[] = { "Left", "Centre", "Right" };

View File

@ -83,10 +83,10 @@ int main(void)
bunnies[i].position.x += bunnies[i].speed.x; bunnies[i].position.x += bunnies[i].speed.x;
bunnies[i].position.y += bunnies[i].speed.y; bunnies[i].position.y += bunnies[i].speed.y;
if (((bunnies[i].position.x + texBunny.width/2) > GetScreenWidth()) || if (((bunnies[i].position.x + (float)texBunny.width/2) > GetScreenWidth()) ||
((bunnies[i].position.x + texBunny.width/2) < 0)) bunnies[i].speed.x *= -1; ((bunnies[i].position.x + (float)texBunny.width/2) < 0)) bunnies[i].speed.x *= -1;
if (((bunnies[i].position.y + texBunny.height/2) > GetScreenHeight()) || if (((bunnies[i].position.y + (float)texBunny.height/2) > GetScreenHeight()) ||
((bunnies[i].position.y + texBunny.height/2 - 40) < 0)) bunnies[i].speed.y *= -1; ((bunnies[i].position.y + (float)texBunny.height/2 - 40) < 0)) bunnies[i].speed.y *= -1;
} }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------

View File

@ -165,7 +165,7 @@ int main(void)
// If the mouse is on this preset, highlight it // If the mouse is on this preset, highlight it
if (mouseInCell == i + 8) if (mouseInCell == i + 8)
DrawRectangleLinesEx((Rectangle) { 2 + (presetsSizeX + 2.0f)*(i/2), DrawRectangleLinesEx((Rectangle) { 2 + (presetsSizeX + 2.0f)*((float)i/2),
(presetsSizeY + 2.0f)*(i%2), (presetsSizeY + 2.0f)*(i%2),
presetsSizeX + 4.0f, presetsSizeY + 4.0f }, 3, RED); presetsSizeX + 4.0f, presetsSizeY + 4.0f }, 3, RED);
} }

View File

@ -93,8 +93,8 @@ int main(void)
for (unsigned int i = 0; i < map.tilesX*map.tilesY; i++) if (map.tileFog[i] == 1) map.tileFog[i] = 2; for (unsigned int i = 0; i < map.tilesX*map.tilesY; i++) if (map.tileFog[i] == 1) map.tileFog[i] = 2;
// Get current tile position from player pixel position // Get current tile position from player pixel position
playerTileX = (int)((playerPosition.x + MAP_TILE_SIZE/2)/MAP_TILE_SIZE); playerTileX = (int)((playerPosition.x + (float)MAP_TILE_SIZE/2)/MAP_TILE_SIZE);
playerTileY = (int)((playerPosition.y + MAP_TILE_SIZE/2)/MAP_TILE_SIZE); playerTileY = (int)((playerPosition.y + (float)MAP_TILE_SIZE/2)/MAP_TILE_SIZE);
// Check visibility and update fog // Check visibility and update fog
// NOTE: We check tilemap limits to avoid processing tiles out-of-array-bounds (it could crash program) // NOTE: We check tilemap limits to avoid processing tiles out-of-array-bounds (it could crash program)

View File

@ -156,7 +156,7 @@ int main(void)
{ {
DrawRectangleRec(toggleRecs[i], ((i == currentProcess) || (i == mouseHoverRec)) ? SKYBLUE : LIGHTGRAY); DrawRectangleRec(toggleRecs[i], ((i == currentProcess) || (i == mouseHoverRec)) ? SKYBLUE : LIGHTGRAY);
DrawRectangleLines((int)toggleRecs[i].x, (int) toggleRecs[i].y, (int) toggleRecs[i].width, (int) toggleRecs[i].height, ((i == currentProcess) || (i == mouseHoverRec)) ? BLUE : GRAY); DrawRectangleLines((int)toggleRecs[i].x, (int) toggleRecs[i].y, (int) toggleRecs[i].width, (int) toggleRecs[i].height, ((i == currentProcess) || (i == mouseHoverRec)) ? BLUE : GRAY);
DrawText( processText[i], (int)( toggleRecs[i].x + toggleRecs[i].width/2 - MeasureText(processText[i], 10)/2), (int) toggleRecs[i].y + 11, 10, ((i == currentProcess) || (i == mouseHoverRec)) ? DARKBLUE : DARKGRAY); DrawText( processText[i], (int)( toggleRecs[i].x + toggleRecs[i].width/2 - (float)MeasureText(processText[i], 10)/2), (int) toggleRecs[i].y + 11, 10, ((i == currentProcess) || (i == mouseHoverRec)) ? DARKBLUE : DARKGRAY);
} }
DrawTexture(texture, screenWidth - texture.width - 60, screenHeight/2 - texture.height/2, WHITE); DrawTexture(texture, screenWidth - texture.width - 60, screenHeight/2 - texture.height/2, WHITE);

View File

@ -38,7 +38,7 @@ int main(void)
Texture2D texture = LoadTextureFromImage(parrots); // Image converted to texture, uploaded to GPU memory (VRAM) Texture2D texture = LoadTextureFromImage(parrots); // Image converted to texture, uploaded to GPU memory (VRAM)
UnloadImage(parrots); // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM UnloadImage(parrots); // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM
Vector2 position = { (float)(screenWidth/2 - texture.width/2), (float)(screenHeight/2 - texture.height/2 - 20) }; Vector2 position = { (float)screenWidth/2 - (float)texture.width/2, (float)screenHeight/2 - (float)texture.height/2 - 20 };
bool showFont = false; bool showFont = false;

View File

@ -39,7 +39,7 @@ int main(void)
Rectangle sourceRec = { 0, 0, (float)button.width, frameHeight }; Rectangle sourceRec = { 0, 0, (float)button.width, frameHeight };
// Define button bounds on screen // Define button bounds on screen
Rectangle btnBounds = { screenWidth/2.0f - button.width/2.0f, screenHeight/2.0f - button.height/NUM_FRAMES/2.0f, (float)button.width, frameHeight }; Rectangle btnBounds = { screenWidth/2.0f - button.width/2.0f, screenHeight/2.0f - (float)button.height/NUM_FRAMES/2.0f, (float)button.width, frameHeight };
int btnState = 0; // Button state: 0-NORMAL, 1-MOUSE_HOVER, 2-PRESSED int btnState = 0; // Button state: 0-NORMAL, 1-MOUSE_HOVER, 2-PRESSED
bool btnAction = false; // Button action should be activated bool btnAction = false; // Button action should be activated

View File

@ -39,8 +39,8 @@ int main(void)
Texture2D explosion = LoadTexture("resources/explosion.png"); Texture2D explosion = LoadTexture("resources/explosion.png");
// Init variables for animation // Init variables for animation
float frameWidth = (float)(explosion.width/NUM_FRAMES_PER_LINE); // Sprite one frame rectangle width float frameWidth = (float)explosion.width/NUM_FRAMES_PER_LINE; // Sprite one frame rectangle width
float frameHeight = (float)(explosion.height/NUM_LINES); // Sprite one frame rectangle height float frameHeight = (float)explosion.height/NUM_LINES; // Sprite one frame rectangle height
int currentFrame = 0; int currentFrame = 0;
int currentLine = 0; int currentLine = 0;

File diff suppressed because it is too large Load Diff

30
src/external/rlsw.h vendored
View File

@ -1177,7 +1177,7 @@ static inline void sw_float_to_unorm8_simd(uint8_t dst[4], const float src[4])
static inline void sw_float_from_unorm8_simd(float dst[4], const uint8_t src[4]) static inline void sw_float_from_unorm8_simd(float dst[4], const uint8_t src[4])
{ {
#if defined(SW_HAS_NEON) #if defined(SW_HAS_NEON)
uint8x8_t bytes8 = vld1_u8(src); //< Read 8 bytes, faster, but let's hope we're not at the end of the page (unlikely)... uint8x8_t bytes8 = vld1_u8(src); // Reading 8 bytes, faster, but let's hope not hitting the end of the page (unlikely)...
uint16x8_t bytes16 = vmovl_u8(bytes8); uint16x8_t bytes16 = vmovl_u8(bytes8);
uint32x4_t ints = vmovl_u16(vget_low_u16(bytes16)); uint32x4_t ints = vmovl_u16(vget_low_u16(bytes16));
float32x4_t floats = vcvtq_f32_u32(ints); float32x4_t floats = vcvtq_f32_u32(ints);
@ -1224,8 +1224,8 @@ static inline uint32_t sw_half_to_float_ui(uint16_t h)
// denormal: flush to zero // denormal: flush to zero
r = (em < (1 << 10))? 0 : r; r = (em < (1 << 10))? 0 : r;
// infinity/NaN; note that we preserve NaN payload as a byproduct of unifying inf/nan cases // NOTE: infinity/NaN; NaN payload is preserved as a byproduct of unifying inf/nan cases
// 112 is an exponent bias fixup; since we already applied it once, applying it twice converts 31 to 255 // 112 is an exponent bias fixup; since it is already applied once, applying it twice converts 31 to 255
r += (em >= (31 << 10))? (112 << 23) : 0; r += (em >= (31 << 10))? (112 << 23) : 0;
return s | r; return s | r;
@ -1252,7 +1252,7 @@ static inline uint16_t sw_half_from_float_ui(uint32_t ui)
// Overflow: infinity; 143 encodes exponent 16 // Overflow: infinity; 143 encodes exponent 16
h = (em >= (143 << 23))? 0x7c00 : h; h = (em >= (143 << 23))? 0x7c00 : h;
// NaN; note that we convert all types of NaN to qNaN // NOTE: NaN; all types of NaN aree converted to qNaN
h = (em > (255 << 23))? 0x7e00 : h; h = (em > (255 << 23))? 0x7e00 : h;
return (uint16_t)(s | h); return (uint16_t)(s | h);
@ -1918,8 +1918,8 @@ static inline void sw_texture_sample_nearest(float *color, const sw_texture_t *t
static inline void sw_texture_sample_linear(float *color, const sw_texture_t *tex, float u, float v) static inline void sw_texture_sample_linear(float *color, const sw_texture_t *tex, float u, float v)
{ {
// TODO: With a bit more cleverness we could clearly reduce the // TODO: With a bit more cleverness thee number of operations can
// number of operations here, but for now it works fine // be clearly reduced, but for now it works fine
float xf = (u*tex->width) - 0.5f; float xf = (u*tex->width) - 0.5f;
float yf = (v*tex->height) - 0.5f; float yf = (v*tex->height) - 0.5f;
@ -1933,7 +1933,7 @@ static inline void sw_texture_sample_linear(float *color, const sw_texture_t *te
int x1 = x0 + 1; int x1 = x0 + 1;
int y1 = y0 + 1; int y1 = y0 + 1;
// NOTE: If the textures are POT we could avoid the division for SW_REPEAT // NOTE: If the textures are POT, avoid the division for SW_REPEAT
if (tex->sWrap == SW_CLAMP) if (tex->sWrap == SW_CLAMP)
{ {
@ -1974,7 +1974,7 @@ static inline void sw_texture_sample_linear(float *color, const sw_texture_t *te
static inline void sw_texture_sample(float *color, const sw_texture_t *tex, float u, float v, float dUdx, float dUdy, float dVdx, float dVdy) static inline void sw_texture_sample(float *color, const sw_texture_t *tex, float u, float v, float dUdx, float dUdy, float dVdx, float dVdy)
{ {
// Previous method: There is no need to compute the square root // Previous method: There is no need to compute the square root
// because using the squared value, the comparison remains `L2 > 1.0f*1.0f` // because using the squared value, the comparison remains (L2 > 1.0f*1.0f)
//float du = sqrtf(dUdx*dUdx + dUdy*dUdy); //float du = sqrtf(dUdx*dUdx + dUdy*dUdy);
//float dv = sqrtf(dVdx*dVdx + dVdy*dVdy); //float dv = sqrtf(dVdx*dVdx + dVdy*dVdy);
//float L = (du > dv)? du : dv; //float L = (du > dv)? du : dv;
@ -2205,7 +2205,7 @@ static inline bool sw_triangle_face_culling(void)
{ {
// NOTE: Face culling is done before clipping to avoid unnecessary computations // NOTE: Face culling is done before clipping to avoid unnecessary computations
// To handle triangles crossing the w=0 plane correctly, // To handle triangles crossing the w=0 plane correctly,
// we perform the winding order test in homogeneous coordinates directly, // the winding order test is performeed in homogeneous coordinates directly,
// before the perspective division (division by w) // before the perspective division (division by w)
// This test determines the orientation of the triangle in the (x,y,w) plane, // This test determines the orientation of the triangle in the (x,y,w) plane,
// which corresponds to the projected 2D winding order sign, // which corresponds to the projected 2D winding order sign,
@ -2559,11 +2559,11 @@ static inline bool sw_quad_face_culling(void)
{ {
// NOTE: Face culling is done before clipping to avoid unnecessary computations // NOTE: Face culling is done before clipping to avoid unnecessary computations
// To handle quads crossing the w=0 plane correctly, // To handle quads crossing the w=0 plane correctly,
// we perform the winding order test in homogeneous coordinates directly, // the winding order test is performed in homogeneous coordinates directly,
// before the perspective division (division by w) // before the perspective division (division by w)
// For a convex quad with vertices P0, P1, P2, P3 in sequential order, // For a convex quad with vertices P0, P1, P2, P3 in sequential order,
// the winding order of the quad is the same as the winding order // the winding order of the quad is the same as the winding order
// of the triangle P0 P1 P2. We use the homogeneous triangle // of the triangle P0 P1 P2. The homogeneous triangle is used on
// winding test on this first triangle // winding test on this first triangle
// Preload homogeneous coordinates into local variables // Preload homogeneous coordinates into local variables
@ -2649,7 +2649,7 @@ static inline bool sw_quad_is_axis_aligned(void)
{ {
// Reject quads with perspective projection // Reject quads with perspective projection
// The fast path assumes affine (non-perspective) quads, // The fast path assumes affine (non-perspective) quads,
// so we require all vertices to have homogeneous w = 1.0 // so it's required for all vertices to have homogeneous w = 1.0
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
if (RLSW.vertexBuffer[i].homogeneous[3] != 1.0f) return false; if (RLSW.vertexBuffer[i].homogeneous[3] != 1.0f) return false;
@ -2721,7 +2721,7 @@ static inline void sw_quad_sort_cw(const sw_vertex_t* *output)
// TODO: REVIEW: Could a perfectly aligned quad, where one of the four points has a different depth, // TODO: REVIEW: Could a perfectly aligned quad, where one of the four points has a different depth,
// still appear perfectly aligned from a certain point of view? // still appear perfectly aligned from a certain point of view?
// Because in that case, we would still need to perform perspective division for textures and colors... // Because in that case, it's still needed to perform perspective division for textures and colors...
#define DEFINE_QUAD_RASTER_AXIS_ALIGNED(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \ #define DEFINE_QUAD_RASTER_AXIS_ALIGNED(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \
static inline void FUNC_NAME(void) \ static inline void FUNC_NAME(void) \
{ \ { \
@ -3090,7 +3090,7 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \
\ \
for (int i = 0; i < numPixels; i++) \ for (int i = 0; i < numPixels; i++) \
{ \ { \
/* REVIEW: May require reviewing projection details */ \ /* TODO: REVIEW: May require reviewing projection details */ \
int px = (int)(x - 0.5f); \ int px = (int)(x - 0.5f); \
int py = (int)(y - 0.5f); \ int py = (int)(y - 0.5f); \
\ \
@ -3721,7 +3721,7 @@ void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySr
ySrc = sw_clampi(ySrc, 0, hSrc); ySrc = sw_clampi(ySrc, 0, hSrc);
// Check if the sizes are identical after clamping the source to avoid unexpected issues // Check if the sizes are identical after clamping the source to avoid unexpected issues
// REVIEW: This repeats the operations if true, so we could make a copy function without these checks // TODO: REVIEW: This repeats the operations if true, so a copy function can be made without these checks
if (xDst == xSrc && yDst == ySrc && wDst == wSrc && hDst == hSrc) if (xDst == xSrc && yDst == ySrc && wDst == wSrc && hDst == hSrc)
{ {
swCopyFramebuffer(xSrc, ySrc, wSrc, hSrc, format, type, pixels); swCopyFramebuffer(xSrc, ySrc, wSrc, hSrc, format, type, pixels);

View File

@ -886,8 +886,8 @@ void ClosePlatform(void)
// NOTE: Reset global state in case the activity is being relaunched // NOTE: Reset global state in case the activity is being relaunched
if (platform.app->destroyRequested != 0) if (platform.app->destroyRequested != 0)
{ {
CORE = (CoreData){0}; CORE = (CoreData){ 0 };
platform = (PlatformData){0}; platform = (PlatformData){ 0 };
} }
} }
@ -1189,7 +1189,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
if (FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) || if (FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) ||
FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD)) FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD))
{ {
// For now we'll assume a single gamepad which we "detect" on its input event // Assuming a single gamepad, "detected" on its input event
CORE.Input.Gamepad.ready[0] = true; CORE.Input.Gamepad.ready[0] = true;
CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_LEFT_X] = AMotionEvent_getAxisValue( CORE.Input.Gamepad.axisState[0][GAMEPAD_AXIS_LEFT_X] = AMotionEvent_getAxisValue(
@ -1256,7 +1256,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD)) && FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD)) &&
!FLAG_IS_SET(source, AINPUT_SOURCE_KEYBOARD)) !FLAG_IS_SET(source, AINPUT_SOURCE_KEYBOARD))
{ {
// For now we'll assume a single gamepad which we "detect" on its input event // Assuming a single gamepad, "detected" on its input event
CORE.Input.Gamepad.ready[0] = true; CORE.Input.Gamepad.ready[0] = true;
GamepadButton button = AndroidTranslateGamepadButton(keycode); GamepadButton button = AndroidTranslateGamepadButton(keycode);

View File

@ -100,7 +100,7 @@
#include <unistd.h> // Required for: usleep() #include <unistd.h> // Required for: usleep()
//#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: Fails due to type redefinition //#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: Fails due to type redefinition
void *glfwGetCocoaWindow(GLFWwindow* handle); void *glfwGetCocoaWindow(GLFWwindow *handle);
#include "GLFW/glfw3native.h" // Required for: glfwGetCocoaWindow() #include "GLFW/glfw3native.h" // Required for: glfwGetCocoaWindow()
#endif #endif
@ -224,8 +224,8 @@ void ToggleFullscreen(void)
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{ {
Vector2 scaleDpi = GetWindowScaleDPI(); Vector2 scaleDpi = GetWindowScaleDPI();
CORE.Window.screen.width = (unsigned int)(CORE.Window.screen.width * scaleDpi.x); CORE.Window.screen.width = (unsigned int)(CORE.Window.screen.width*scaleDpi.x);
CORE.Window.screen.height = (unsigned int)(CORE.Window.screen.height * scaleDpi.y); CORE.Window.screen.height = (unsigned int)(CORE.Window.screen.height*scaleDpi.y);
} }
#endif #endif
@ -303,8 +303,8 @@ void ToggleBorderlessWindowed(void)
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{ {
Vector2 scaleDpi = GetWindowScaleDPI(); Vector2 scaleDpi = GetWindowScaleDPI();
CORE.Window.screen.width = (unsigned int)(CORE.Window.screen.width * scaleDpi.x); CORE.Window.screen.width = (unsigned int)(CORE.Window.screen.width*scaleDpi.x);
CORE.Window.screen.height = (unsigned int)(CORE.Window.screen.height * scaleDpi.y); CORE.Window.screen.height = (unsigned int)(CORE.Window.screen.height*scaleDpi.y);
} }
#endif #endif
@ -602,7 +602,7 @@ void SetWindowIcon(Image image)
icon[0].height = image.height; icon[0].height = image.height;
icon[0].pixels = (unsigned char *)image.data; icon[0].pixels = (unsigned char *)image.data;
// NOTE 1: We only support one image icon // NOTE 1: Only one image icon supported
// NOTE 2: The specified image data is copied before this function returns // NOTE 2: The specified image data is copied before this function returns
glfwSetWindowIcon(platform.handle, 1, icon); glfwSetWindowIcon(platform.handle, 1, icon);
} }
@ -833,7 +833,7 @@ int GetCurrentMonitor(void)
} }
else else
{ {
// In case the window is between two monitors, we use below logic // In case the window is between two monitors, below logic is used
// to try to detect the "current monitor" for that window, note that // to try to detect the "current monitor" for that window, note that
// this is probably an overengineered solution for a very side case // this is probably an overengineered solution for a very side case
// trying to match SDL behaviour // trying to match SDL behaviour
@ -1186,7 +1186,7 @@ void SetMouseCursor(int cursor)
if (cursor == MOUSE_CURSOR_DEFAULT) glfwSetCursor(platform.handle, NULL); if (cursor == MOUSE_CURSOR_DEFAULT) glfwSetCursor(platform.handle, NULL);
else else
{ {
// NOTE: We are relating internal GLFW enum values to our MouseCursor enum values // NOTE: Mapping internal GLFW enum values to MouseCursor enum values
glfwSetCursor(platform.handle, glfwCreateStandardCursor(0x00036000 + cursor)); glfwSetCursor(platform.handle, glfwCreateStandardCursor(0x00036000 + cursor));
} }
} }
@ -1211,7 +1211,7 @@ void PollInputEvents(void)
CORE.Input.Keyboard.charPressedQueueCount = 0; CORE.Input.Keyboard.charPressedQueueCount = 0;
// Reset last gamepad button/axis registered state // Reset last gamepad button/axis registered state
CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_UNKNOWN;
//CORE.Input.Gamepad.axisCount = 0; //CORE.Input.Gamepad.axisCount = 0;
// Keyboard/Mouse input polling (automatically managed by GLFW3 through callback) // Keyboard/Mouse input polling (automatically managed by GLFW3 through callback)
@ -1247,7 +1247,7 @@ void PollInputEvents(void)
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
// Check if gamepads are ready // Check if gamepads are ready
// NOTE: We do it here in case of disconnection // NOTE: Doing it here in case of disconnection
for (int i = 0; i < MAX_GAMEPADS; i++) for (int i = 0; i < MAX_GAMEPADS; i++)
{ {
if (glfwJoystickPresent(i)) CORE.Input.Gamepad.ready[i] = true; if (glfwJoystickPresent(i)) CORE.Input.Gamepad.ready[i] = true;
@ -1263,7 +1263,7 @@ void PollInputEvents(void)
for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k]; for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k];
// Get current gamepad state // Get current gamepad state
// NOTE: There is no callback available, so we get it manually // NOTE: There is no callback available, getting it manually
GLFWgamepadstate state = { 0 }; GLFWgamepadstate state = { 0 };
int result = glfwGetGamepadState(i, &state); // This remaps all gamepads so they have their buttons mapped like an xbox controller int result = glfwGetGamepadState(i, &state); // This remaps all gamepads so they have their buttons mapped like an xbox controller
if (result == GLFW_FALSE) // No joystick is connected, no gamepad mapping or an error occurred if (result == GLFW_FALSE) // No joystick is connected, no gamepad mapping or an error occurred
@ -1359,8 +1359,8 @@ void PollInputEvents(void)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Internal Functions Definition // Module Internal Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Function wrappers around RL_*alloc macros, used by glfwInitAllocator() inside of InitPlatform() // Function wrappers around RL_*ALLOC macros, used by glfwInitAllocator() inside of InitPlatform()
// We need to provide these because GLFWallocator expects function pointers with specific signatures // GLFWallocator expects function pointers with specific signatures to be provided
// REF: https://www.glfw.org/docs/latest/intro_guide.html#init_allocator // REF: https://www.glfw.org/docs/latest/intro_guide.html#init_allocator
static void *AllocateWrapper(size_t size, void *user) static void *AllocateWrapper(size_t size, void *user)
{ {
@ -1742,7 +1742,7 @@ int InitPlatform(void)
for (int i = 0; i < MAX_GAMEPADS; i++) for (int i = 0; i < MAX_GAMEPADS; i++)
{ {
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH, // WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
// we can get a not-NULL terminated string, so, we only copy up to (MAX_GAMEPAD_NAME_LENGTH - 1) // only copying up to (MAX_GAMEPAD_NAME_LENGTH - 1)
if (glfwJoystickPresent(i)) if (glfwJoystickPresent(i))
{ {
CORE.Input.Gamepad.ready[i] = true; CORE.Input.Gamepad.ready[i] = true;
@ -1819,8 +1819,8 @@ static void FramebufferSizeCallback(GLFWwindow *window, int width, int height)
{ {
//TRACELOG(LOG_INFO, "GLFW3: Window framebuffer size callback called [%i,%i]", width, height); //TRACELOG(LOG_INFO, "GLFW3: Window framebuffer size callback called [%i,%i]", width, height);
// WARNING: On window minimization, callback is called, // WARNING: On window minimization, callback is called with 0 values,
// but we don't want to change internal screen values, it breaks things // but internal screen values should not be changed, it breaks things
if ((width == 0) || (height == 0)) return; if ((width == 0) || (height == 0)) return;
// Reset viewport and projection matrix for new size // Reset viewport and projection matrix for new size
@ -1926,7 +1926,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
{ {
if (count > 0) if (count > 0)
{ {
// In case previous dropped filepaths have not been freed, we free them // In case previous dropped filepaths have not been freed, free them
if (CORE.Window.dropFileCount > 0) if (CORE.Window.dropFileCount > 0)
{ {
for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]); for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]);
@ -1937,7 +1937,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
CORE.Window.dropFilepaths = NULL; CORE.Window.dropFilepaths = NULL;
} }
// WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy // WARNING: Paths are freed by GLFW when the callback returns, keeping an internal copy
CORE.Window.dropFileCount = count; CORE.Window.dropFileCount = count;
CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *)); CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *));
@ -1954,7 +1954,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
{ {
if (key < 0) return; // Security check, macOS fn key generates -1 if (key < 0) return; // Security check, macOS fn key generates -1
// WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1 // WARNING: GLFW could return GLFW_REPEAT, it needs to be considered as 1
// to work properly with our implementation (IsKeyDown/IsKeyUp checks) // to work properly with our implementation (IsKeyDown/IsKeyUp checks)
if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0; if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0;
else if (action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1; else if (action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1;
@ -2079,7 +2079,7 @@ static void JoystickCallback(int jid, int event)
if (event == GLFW_CONNECTED) if (event == GLFW_CONNECTED)
{ {
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH, // WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
// we can get a not-NULL terminated string, so, we clean destination and only copy up to -1 // only copy up to (MAX_GAMEPAD_NAME_LENGTH -1) to destination string
memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH); memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
strncpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid), MAX_GAMEPAD_NAME_LENGTH - 1); strncpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
} }

View File

@ -49,7 +49,7 @@
#define USING_SDL3_PROJECT #define USING_SDL3_PROJECT
#endif #endif
#ifndef SDL_ENABLE_OLD_NAMES #ifndef SDL_ENABLE_OLD_NAMES
#define SDL_ENABLE_OLD_NAMES // Just in case we're on SDL3, we need some in-between compatibily #define SDL_ENABLE_OLD_NAMES // Just in case on SDL3, some in-between compatibily is needed
#endif #endif
// SDL base library (window/rendered, input, timing... functionality) // SDL base library (window/rendered, input, timing... functionality)
#ifdef USING_SDL3_PROJECT #ifdef USING_SDL3_PROJECT
@ -323,7 +323,7 @@ Uint8 SDL_EventState(Uint32 type, int state)
return stateBefore; return stateBefore;
} }
void SDL_GetCurrentDisplayMode_Adapter(SDL_DisplayID displayID, SDL_DisplayMode* mode) void SDL_GetCurrentDisplayMode_Adapter(SDL_DisplayID displayID, SDL_DisplayMode *mode)
{ {
const SDL_DisplayMode *currentMode = SDL_GetCurrentDisplayMode(displayID); const SDL_DisplayMode *currentMode = SDL_GetCurrentDisplayMode(displayID);
@ -340,8 +340,7 @@ SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth
} }
// SDL3 Migration: // SDL3 Migration:
// SDL_GetDisplayDPI() - // SDL_GetDisplayDPI() not reliable across platforms, approximately replaced by multiplying
// not reliable across platforms, approximately replaced by multiplying
// SDL_GetWindowDisplayScale() times 160 on iPhone and Android, and 96 on other platforms // SDL_GetWindowDisplayScale() times 160 on iPhone and Android, and 96 on other platforms
// returns 0 on success or a negative error code on failure // returns 0 on success or a negative error code on failure
int SDL_GetDisplayDPI(int displayIndex, float *ddpi, float *hdpi, float *vdpi) int SDL_GetDisplayDPI(int displayIndex, float *ddpi, float *hdpi, float *vdpi)
@ -413,7 +412,7 @@ int SDL_GetNumTouchFingers(SDL_TouchID touchID)
return count; return count;
} }
#else // We're on SDL2 #else // SDL2 fallback
// Since SDL2 doesn't have this function we leave a stub // Since SDL2 doesn't have this function we leave a stub
// SDL_GetClipboardData function is available since SDL 3.1.3. (e.g. SDL3) // SDL_GetClipboardData function is available since SDL 3.1.3. (e.g. SDL3)
@ -833,10 +832,9 @@ void SetWindowMonitor(int monitor)
if ((monitor >= 0) && (monitor < monitorCount)) if ((monitor >= 0) && (monitor < monitorCount))
#endif #endif
{ {
// NOTE: // NOTE 1: SDL started supporting moving exclusive fullscreen windows between displays on SDL3,
// 1. SDL started supporting moving exclusive fullscreen windows between displays on SDL3,
// see commit https://github.com/libsdl-org/SDL/commit/3f5ef7dd422057edbcf3e736107e34be4b75d9ba // see commit https://github.com/libsdl-org/SDL/commit/3f5ef7dd422057edbcf3e736107e34be4b75d9ba
// 2. A workaround for SDL2 is leaving fullscreen, moving the window, then entering full screen again // NOTE 2: A workaround for SDL2 is leaving fullscreen, moving the window, then entering full screen again
const bool wasFullscreen = (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))? true : false; const bool wasFullscreen = (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))? true : false;
const int screenWidth = CORE.Window.screen.width; const int screenWidth = CORE.Window.screen.width;
@ -854,13 +852,12 @@ void SetWindowMonitor(int monitor)
// If the screen size is larger than the monitor usable area, anchor it on the top left corner, otherwise, center it // If the screen size is larger than the monitor usable area, anchor it on the top left corner, otherwise, center it
if ((screenWidth >= usableBounds.w) || (screenHeight >= usableBounds.h)) if ((screenWidth >= usableBounds.w) || (screenHeight >= usableBounds.h))
{ {
// NOTE: // NOTE 1: There's a known issue where if the window larger than the target display bounds,
// 1. There's a known issue where if the window larger than the target display bounds,
// when moving the windows to that display, the window could be clipped back // when moving the windows to that display, the window could be clipped back
// ending up positioned partly outside the target display // ending up positioned partly outside the target display
// 2. The workaround for that is, previously to moving the window, // NOTE 2: The workaround for that is, previously to moving the window,
// setting the window size to the target display size, so they match // setting the window size to the target display size, so they match
// 3. It wasn't done here because we can't assume changing the window size automatically // NOTE 3: It wasn't done here because we can't assume changing the window size automatically
// is acceptable behavior by the user // is acceptable behavior by the user
SDL_SetWindowPosition(platform.window, usableBounds.x, usableBounds.y); SDL_SetWindowPosition(platform.window, usableBounds.x, usableBounds.y);
CORE.Window.position.x = usableBounds.x; CORE.Window.position.x = usableBounds.x;
@ -1250,7 +1247,7 @@ void DisableCursor(void)
void SwapScreenBuffer(void) void SwapScreenBuffer(void)
{ {
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
// NOTE: We use a preprocessor condition here because `rlCopyFramebuffer` is only declared for software rendering // NOTE: We use a preprocessor condition here because rlCopyFramebuffer() is only declared for software rendering
SDL_Surface *surface = SDL_GetWindowSurface(platform.window); SDL_Surface *surface = SDL_GetWindowSurface(platform.window);
rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, surface->pixels); rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, surface->pixels);
SDL_UpdateWindowSurface(platform.window); SDL_UpdateWindowSurface(platform.window);

View File

@ -433,7 +433,7 @@ static bool UpdateWindowSize(int mode, HWND hwnd, int width, int height, unsigne
return true; return true;
} }
// Verify if we are running in Windows 10 version 1703 (Creators Update) // Check if running in Windows 10 version 1703 (Creators Update)
static BOOL IsWindows10Version1703OrGreaterWin32(void) static BOOL IsWindows10Version1703OrGreaterWin32(void)
{ {
HMODULE ntdll = LoadLibraryW(L"ntdll.dll"); HMODULE ntdll = LoadLibraryW(L"ntdll.dll");
@ -1138,7 +1138,7 @@ void ShowCursor(void)
// Hides mouse cursor // Hides mouse cursor
void HideCursor(void) void HideCursor(void)
{ {
// NOTE: We use SetCursor() instead of ShowCursor() because // NOTE: Using SetCursor() instead of ShowCursor() because
// it makes it easy to only hide the cursor while it's inside the client area // it makes it easy to only hide the cursor while it's inside the client area
SetCursor(NULL); SetCursor(NULL);
CORE.Input.Mouse.cursorHidden = true; CORE.Input.Mouse.cursorHidden = true;
@ -1227,7 +1227,7 @@ void SwapScreenBuffer(void)
// Get elapsed time measure in seconds // Get elapsed time measure in seconds
double GetTime(void) double GetTime(void)
{ {
LARGE_INTEGER now = 0; LARGE_INTEGER now = { 0 };
QueryPerformanceCounter(&now); QueryPerformanceCounter(&now);
return (double)(now.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart; return (double)(now.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart;
} }
@ -1345,7 +1345,7 @@ void PollInputEvents(void)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Initialize modern OpenGL context // Initialize modern OpenGL context
// NOTE: We need to create a dummy context first to query required extensions // NOTE: Creating a dummy context first to query required extensions
HGLRC InitOpenGL(HWND hwnd, HDC hdc) HGLRC InitOpenGL(HWND hwnd, HDC hdc)
{ {
// First, create a dummy context to get WGL extensions // First, create a dummy context to get WGL extensions
@ -1460,7 +1460,7 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc)
0 // Terminator 0 // Terminator
}; };
// NOTE: We are not sharing context resources so, second parameters is NULL // NOTE: Not sharing context resources so, second parameters is NULL
realContext = wglCreateContextAttribsARB(hdc, NULL, contextAttribs); realContext = wglCreateContextAttribsARB(hdc, NULL, contextAttribs);
// Check for error context creation errors // Check for error context creation errors
@ -1476,8 +1476,8 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc)
// Activate real context // Activate real context
if (realContext) wglMakeCurrent(hdc, realContext); if (realContext) wglMakeCurrent(hdc, realContext);
// Once we got a real modern OpenGL context, // Once a real modern OpenGL context is created,
// we can load required extensions (function pointers) // required extensions can be loaded (function pointers)
rlLoadExtensions(WglGetProcAddress); rlLoadExtensions(WglGetProcAddress);
return realContext; return realContext;
@ -1521,7 +1521,7 @@ int InitPlatform(void)
.lpfnWndProc = WndProc, // Custom procedure assigned .lpfnWndProc = WndProc, // Custom procedure assigned
.cbWndExtra = sizeof(LONG_PTR), // extra space for the Tuple object ptr .cbWndExtra = sizeof(LONG_PTR), // extra space for the Tuple object ptr
.hInstance = hInstance, .hInstance = hInstance,
.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW), // TODO: Audit if we want to set this since we're implementing WM_SETCURSOR .hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW), // TODO: Check if this is really required, since WM_SETCURSOR event is processed
.lpszClassName = CLASS_NAME // Class name: L"raylibWindow" .lpszClassName = CLASS_NAME // Class name: L"raylibWindow"
}; };
@ -1854,8 +1854,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
SIZE *inoutSize = (SIZE *)lparam; SIZE *inoutSize = (SIZE *)lparam;
UINT newDpi = (UINT)wparam; // TODO: WARNING: Converting from WPARAM = UINT_PTR UINT newDpi = (UINT)wparam; // TODO: WARNING: Converting from WPARAM = UINT_PTR
// for any of these other cases, we might want to post a window // For the following flag changes, a window resize event should be posted,
// resize event after the dpi changes? // TODO: Should it be done after dpi changes?
if (CORE.Window.flags & FLAG_WINDOW_MINIMIZED) return TRUE; if (CORE.Window.flags & FLAG_WINDOW_MINIMIZED) return TRUE;
if (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) return TRUE; if (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) return TRUE;
if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) return TRUE; if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) return TRUE;
@ -1875,8 +1875,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
case WM_DPICHANGED: case WM_DPICHANGED:
{ {
// Get current dpi scale factor // Get current dpi scale factor
float scalex = HIWORD(wParam)/96.0f; float scalex = HIWORD(wparam)/96.0f;
float scaley = LOWORD(wParam)/96.0f; float scaley = LOWORD(wparam)/96.0f;
RECT *suggestedRect = (RECT *)lparam; RECT *suggestedRect = (RECT *)lparam;
@ -2025,8 +2025,8 @@ static void HandleRawInput(LPARAM lparam)
if (input.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) TRACELOG(LOG_ERROR, "TODO: handle virtual desktop mouse inputs!"); if (input.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) TRACELOG(LOG_ERROR, "TODO: handle virtual desktop mouse inputs!");
// Trick to keep the mouse position at 0,0 and instead move // Trick to keep the mouse position at (0,0) and instead move
// the previous position so we can still get a proper mouse delta // the previous position so a proper mouse delta can still be retrieved
//CORE.Input.Mouse.previousPosition.x -= input.data.mouse.lLastX; //CORE.Input.Mouse.previousPosition.x -= input.data.mouse.lLastX;
//CORE.Input.Mouse.previousPosition.y -= input.data.mouse.lLastY; //CORE.Input.Mouse.previousPosition.y -= input.data.mouse.lLastY;
//if (CORE.Input.Mouse.currentPosition.x != 0) abort(); //if (CORE.Input.Mouse.currentPosition.x != 0) abort();
@ -2138,12 +2138,12 @@ static unsigned SanitizeFlags(int mode, unsigned flags)
// This design takes care of many odd corner cases. For example, if you want to restore // This design takes care of many odd corner cases. For example, if you want to restore
// a window that was previously maximized AND minimized and you want to remove both these // a window that was previously maximized AND minimized and you want to remove both these
// flags, you actually need to call ShowWindow with SW_RESTORE twice. Another example is // flags, you actually need to call ShowWindow with SW_RESTORE twice. Another example is
// if you have a maximized window, if the undecorated flag is modified then we'd need to // if you have a maximized window, if the undecorated flag is modified then the window style
// update the window style, but updating the style would mean the window size would change // needs to be updated, but updating the style would mean the window size would change
// causing the window to lose its Maximized state which would mean we'd need to update the // causing the window to lose its Maximized state which would mean the window size
// window size and then update the window style a second time to restore that maximized // needs to be updated, followed by the update of window style, a second time, to restore that maximized
// state. This implementation is able to handle any/all of these special situations with a // state. This implementation is able to handle any/all of these special situations with a
// retry loop that continues until we either reach the desired state or the state stops changing // retry loop that continues until either the desired state is reached or the state stops changing
static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height) static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height)
{ {
// Flags that just apply immediately without needing any operations // Flags that just apply immediately without needing any operations

View File

@ -915,7 +915,7 @@ void SwapScreenBuffer(void)
{ {
TRACELOG(LOG_ERROR, "DISPLAY: Failed to get DRM resources"); TRACELOG(LOG_ERROR, "DISPLAY: Failed to get DRM resources");
drmModeRmFB(platform.fd, fb); drmModeRmFB(platform.fd, fb);
struct drm_mode_destroy_dumb dreq = {0}; struct drm_mode_destroy_dumb dreq = { 0 };
dreq.handle = creq.handle; dreq.handle = creq.handle;
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
return; return;
@ -955,7 +955,7 @@ void SwapScreenBuffer(void)
{ {
TRACELOG(LOG_ERROR, "DISPLAY: No compatible CRTC found"); TRACELOG(LOG_ERROR, "DISPLAY: No compatible CRTC found");
drmModeRmFB(platform.fd, fb); drmModeRmFB(platform.fd, fb);
struct drm_mode_destroy_dumb dreq = {0}; struct drm_mode_destroy_dumb dreq = { 0 };
dreq.handle = creq.handle; dreq.handle = creq.handle;
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
return; return;
@ -971,7 +971,7 @@ void SwapScreenBuffer(void)
TRACELOG(LOG_ERROR, "DISPLAY: Mode: %dx%d@%d", mode->hdisplay, mode->vdisplay, mode->vrefresh); TRACELOG(LOG_ERROR, "DISPLAY: Mode: %dx%d@%d", mode->hdisplay, mode->vdisplay, mode->vrefresh);
drmModeRmFB(platform.fd, fb); drmModeRmFB(platform.fd, fb);
struct drm_mode_destroy_dumb dreq = {0}; struct drm_mode_destroy_dumb dreq = { 0 };
dreq.handle = creq.handle; dreq.handle = creq.handle;
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
return; return;
@ -989,7 +989,7 @@ void SwapScreenBuffer(void)
// Clean up previous dumb buffer // Clean up previous dumb buffer
if (platform.prevDumbHandle) if (platform.prevDumbHandle)
{ {
struct drm_mode_destroy_dumb dreq = {0}; struct drm_mode_destroy_dumb dreq = { 0 };
dreq.handle = platform.prevDumbHandle; dreq.handle = platform.prevDumbHandle;
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
} }

View File

@ -499,7 +499,7 @@ int InitPlatform(void)
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// If everything work as expected, we can continue // If everything worked as expected, continue
CORE.Window.render.width = CORE.Window.screen.width; CORE.Window.render.width = CORE.Window.screen.width;
CORE.Window.render.height = CORE.Window.screen.height; CORE.Window.render.height = CORE.Window.screen.height;
CORE.Window.currentFbo.width = CORE.Window.render.width; CORE.Window.currentFbo.width = CORE.Window.render.width;

View File

@ -316,15 +316,16 @@ void ToggleBorderlessWindowed(void)
// 2. The style unset handles the possibility of a width="value%" like on the default shell.html file // 2. The style unset handles the possibility of a width="value%" like on the default shell.html file
EM_ASM EM_ASM
( (
const canvasId = UTF8ToString($0);
setTimeout(function() setTimeout(function()
{ {
Module.requestFullscreen(false, true); Module.requestFullscreen(false, true);
setTimeout(function() setTimeout(function()
{ {
canvas.style.width="unset"; document.querySelector(canvasId).style.width="unset";
}, 100); }, 100);
}, 100); }, 100);
); , platform.canvasId);
FLAG_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE); FLAG_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
} }
} }
@ -953,7 +954,7 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
if (duration > MAX_GAMEPAD_VIBRATION_TIME) duration = MAX_GAMEPAD_VIBRATION_TIME; if (duration > MAX_GAMEPAD_VIBRATION_TIME) duration = MAX_GAMEPAD_VIBRATION_TIME;
duration *= 1000.0f; // Convert duration to ms duration *= 1000.0f; // Convert duration to ms
// Note: At the moment (2024.10.21) Chrome, Edge, Opera, Safari, Android Chrome, Android Webview only support the vibrationActuator API, // NOTE: At the moment (2024.10.21) Chrome, Edge, Opera, Safari, Android Chrome, Android Webview only support the vibrationActuator API,
// and Firefox only supports the hapticActuators API // and Firefox only supports the hapticActuators API
EM_ASM({ EM_ASM({
try try
@ -1238,9 +1239,9 @@ int InitPlatform(void)
// Avoid creating a WebGL canvas, avoid calling glfwCreateWindow() // Avoid creating a WebGL canvas, avoid calling glfwCreateWindow()
emscripten_set_canvas_element_size(platform.canvasId, CORE.Window.screen.width, CORE.Window.screen.height); emscripten_set_canvas_element_size(platform.canvasId, CORE.Window.screen.width, CORE.Window.screen.height);
EM_ASM({ EM_ASM({
const canvas = document.getElementById("canvas"); const canvas = document.querySelector(UTF8ToString($0));
Module.canvas = canvas; Module.canvas = canvas;
}); }, platform.canvasId);
// Load memory framebuffer with desired screen size // Load memory framebuffer with desired screen size
// NOTE: Despite using a software framebuffer for blitting, GLFW still creates a WebGL canvas, // NOTE: Despite using a software framebuffer for blitting, GLFW still creates a WebGL canvas,
@ -1798,8 +1799,8 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
// Emscripten: Called on fullscreen change events // Emscripten: Called on fullscreen change events
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData) static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData)
{ {
// NOTE: 1. Reset the fullscreen flags if the user left fullscreen manually by pressing the Escape key // NOTE 1: Reset the fullscreen flags if the user left fullscreen manually by pressing the Escape key
// 2. Which is a necessary safeguard because that case will bypass the toggles CORE.Window.flags resets // NOTE 2: Which is a necessary safeguard because that case will bypass the toggles CORE.Window.flags resets
if (platform.ourFullscreen) platform.ourFullscreen = false; if (platform.ourFullscreen) platform.ourFullscreen = false;
else else
{ {

View File

@ -137,7 +137,7 @@ bool WindowShouldClose(void)
// and encapsulating one frame execution on a UpdateDrawFrame() function, // and encapsulating one frame execution on a UpdateDrawFrame() function,
// allowing the browser to manage execution asynchronously // allowing the browser to manage execution asynchronously
// Optionally we can manage the time we give-control-back-to-browser if required, // NOTE: Optionally, time can be managed, giving control back-to-browser as required,
// but it seems below line could generate stuttering on some browsers // but it seems below line could generate stuttering on some browsers
emscripten_sleep(12); emscripten_sleep(12);
@ -280,15 +280,16 @@ void ToggleBorderlessWindowed(void)
// 2. The style unset handles the possibility of a width="value%" like on the default shell.html file // 2. The style unset handles the possibility of a width="value%" like on the default shell.html file
EM_ASM EM_ASM
( (
const canvasId = UTF8ToString($0);
setTimeout(function() setTimeout(function()
{ {
Module.requestFullscreen(false, true); Module.requestFullscreen(false, true);
setTimeout(function() setTimeout(function()
{ {
canvas.style.width="unset"; document.querySelector(canvasId).style.width="unset";
}, 100); }, 100);
}, 100); }, 100);
); , platform.canvasId);
FLAG_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE); FLAG_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
} }
} }
@ -1358,7 +1359,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
{ {
if (count > 0) if (count > 0)
{ {
// In case previous dropped filepaths have not been freed, we free them // In case previous dropped filepaths have not been freed, free them
if (CORE.Window.dropFileCount > 0) if (CORE.Window.dropFileCount > 0)
{ {
for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]); for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]);
@ -1369,7 +1370,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
CORE.Window.dropFilepaths = NULL; CORE.Window.dropFilepaths = NULL;
} }
// WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy // WARNING: Paths are freed by GLFW when the callback returns, an internal copy should be kept
CORE.Window.dropFileCount = count; CORE.Window.dropFileCount = count;
CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *)); CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *));
@ -1610,7 +1611,7 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
double canvasWidth = 0.0; double canvasWidth = 0.0;
double canvasHeight = 0.0; double canvasHeight = 0.0;
// NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but // NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but
// we are looking for actual CSS size: canvas.style.width and canvas.style.height // looking for actual CSS size: canvas.style.width and canvas.style.height
// EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight); // EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight);
emscripten_get_element_css_size(platform.canvasId, &canvasWidth, &canvasHeight); emscripten_get_element_css_size(platform.canvasId, &canvasWidth, &canvasHeight);
@ -1630,7 +1631,7 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0; else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0;
} }
// Update mouse position if we detect a single touch // Update mouse position if a single touch is detected
if (CORE.Input.Touch.pointCount == 1) if (CORE.Input.Touch.pointCount == 1)
{ {
CORE.Input.Mouse.currentPosition.x = CORE.Input.Touch.position[0].x; CORE.Input.Mouse.currentPosition.x = CORE.Input.Touch.position[0].x;

View File

@ -2418,7 +2418,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
audioBuffer->frameCursorPos = (audioBuffer->frameCursorPos + framesToRead)%audioBuffer->sizeInFrames; audioBuffer->frameCursorPos = (audioBuffer->frameCursorPos + framesToRead)%audioBuffer->sizeInFrames;
framesRead += framesToRead; framesRead += framesToRead;
// If we've read to the end of the buffer, mark it as processed // If the end of the buffer is read, mark it as processed
if (framesToRead == framesRemainingInOutputBuffer) if (framesToRead == framesRemainingInOutputBuffer)
{ {
audioBuffer->isSubBufferProcessed[currentSubBufferIndex] = true; audioBuffer->isSubBufferProcessed[currentSubBufferIndex] = true;
@ -2426,7 +2426,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
currentSubBufferIndex = (currentSubBufferIndex + 1)%2; currentSubBufferIndex = (currentSubBufferIndex + 1)%2;
// We need to break from this loop if we're not looping // Break from this loop if looping not enabled
if (!audioBuffer->looping) if (!audioBuffer->looping)
{ {
StopAudioBufferInLockedState(audioBuffer); StopAudioBufferInLockedState(audioBuffer);
@ -2453,10 +2453,12 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
// Reads audio data from an AudioBuffer object in device format, returned data will be in a format appropriate for mixing // Reads audio data from an AudioBuffer object in device format, returned data will be in a format appropriate for mixing
static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, float *framesOut, ma_uint32 frameCount) static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, float *framesOut, ma_uint32 frameCount)
{ {
// What's going on here is that we're continuously converting data from the AudioBuffer's internal format to the mixing format, which // NOTE: Continuously converting data from the AudioBuffer's internal format to the mixing format,
// should be defined by the output format of the data converter. We do this until frameCount frames have been output. The important // which should be defined by the output format of the data converter.
// detail to remember here is that we never, ever attempt to read more input data than is required for the specified number of output // This is done until frameCount frames have been output.
// frames. This can be achieved with ma_data_converter_get_required_input_frame_count() // The important detail to remember is that more data than required should neeveer be read,
// for the specified number of output frames.
// This can be achieved with ma_data_converter_get_required_input_frame_count()
ma_uint8 inputBuffer[4096] = { 0 }; ma_uint8 inputBuffer[4096] = { 0 };
ma_uint32 inputBufferFrameCap = sizeof(inputBuffer)/ma_get_bytes_per_frame(audioBuffer->converter.formatIn, audioBuffer->converter.channelsIn); ma_uint32 inputBufferFrameCap = sizeof(inputBuffer)/ma_get_bytes_per_frame(audioBuffer->converter.formatIn, audioBuffer->converter.channelsIn);
@ -2573,8 +2575,8 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const
} }
} }
// If for some reason we weren't able to read every frame we'll need to break from the loop // If for some reason is not possible to read every frame, the loop needs to be broken
// Not doing this could theoretically put us into an infinite loop // Not doing this could theoretically eend up into an infinite loop
if (framesToRead > 0) break; if (framesToRead > 0) break;
} }
} }

View File

@ -512,7 +512,6 @@ typedef struct VrStereoConfig {
// File path list // File path list
typedef struct FilePathList { typedef struct FilePathList {
unsigned int capacity; // Filepaths max entries
unsigned int count; // Filepaths entries count unsigned int count; // Filepaths entries count
char **paths; // Filepaths entries char **paths; // Filepaths entries
} FilePathList; } FilePathList;
@ -1152,6 +1151,8 @@ RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload fi
RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window
RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths
RLAPI void UnloadDroppedFiles(FilePathList files); // Unload dropped filepaths RLAPI void UnloadDroppedFiles(FilePathList files); // Unload dropped filepaths
RLAPI unsigned int GetDirectoryFileCount(const char *dirPath); // Get the file count in a directory
RLAPI unsigned int GetDirectoryFileCountEx(const char *basePath, const char *filter, bool scanSubdirs);// Get the file count in a directory with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result
// Compression/Encoding functionality // Compression/Encoding functionality
RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree() RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree()

View File

@ -66,11 +66,11 @@
// Function specifiers definition // Function specifiers definition
#if defined(RAYMATH_IMPLEMENTATION) #if defined(RAYMATH_IMPLEMENTATION)
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED) #if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
#define RMAPI __declspec(dllexport) extern inline // We are building raylib as a Win32 shared library (.dll) #define RMAPI __declspec(dllexport) extern inline // Building raylib as a Win32 shared library (.dll)
#elif defined(BUILD_LIBTYPE_SHARED) #elif defined(BUILD_LIBTYPE_SHARED)
#define RMAPI __attribute__((visibility("default"))) // We are building raylib as a Unix shared library (.so/.dylib) #define RMAPI __attribute__((visibility("default"))) // Building raylib as a Unix shared library (.so/.dylib)
#elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED)
#define RMAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll) #define RMAPI __declspec(dllimport) // Using raylib as a Win32 shared library (.dll)
#else #else
#define RMAPI extern inline // Provide external definition #define RMAPI extern inline // Provide external definition
#endif #endif
@ -1083,7 +1083,7 @@ RMAPI Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c)
} }
// Projects a Vector3 from screen space into object space // Projects a Vector3 from screen space into object space
// NOTE: We are avoiding calling other raymath functions despite available // NOTE: Self-contained function, no other raymath functions are called
RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view) RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)
{ {
Vector3 result = { 0 }; Vector3 result = { 0 };
@ -2369,7 +2369,7 @@ RMAPI Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)
result.x = cross.x; result.x = cross.x;
result.y = cross.y; result.y = cross.y;
result.z = cross.z; result.z = cross.z;
result.w = 1.0f + cos2Theta; result.w = sqrtf(cross.x*cross.x + cross.y*cross.y + cross.z*cross.z + cos2Theta*cos2Theta) + cos2Theta;
// QuaternionNormalize(q); // QuaternionNormalize(q);
// NOTE: Normalize to essentially nlerp the original and identity to 0.5 // NOTE: Normalize to essentially nlerp the original and identity to 0.5

View File

@ -267,9 +267,15 @@
#define MAX_AUTOMATION_EVENTS 16384 // Maximum number of automation events to record #define MAX_AUTOMATION_EVENTS 16384 // Maximum number of automation events to record
#endif #endif
#ifndef DIRECTORY_FILTER_TAG #ifndef FILE_FILTER_TAG_ALL
#define DIRECTORY_FILTER_TAG "DIR" // Name tag used to request directory inclusion on directory scan #define FILE_FILTER_TAG_ALL "*.*" // Filter to include all file types and directories on directory scan
#endif // NOTE: Used in ScanDirectoryFiles(), ScanDirectoryFilesRecursively() and LoadDirectoryFilesEx() #endif // NOTE: Used in ScanDirectoryFiles(), LoadDirectoryFilesEx() and GetDirectoryFileCountEx()
#ifndef FILE_FILTER_TAG_FILE_ONLY
#define FILE_FILTER_TAG_FILE_ONLY "FILES*" // Filter to include all file types on directory scan
#endif // NOTE: Used in ScanDirectoryFiles(), LoadDirectoryFilesEx() and GetDirectoryFileCountEx()
#ifndef FILE_FILTER_TAG_DIR_ONLY
#define FILE_FILTER_TAG_DIR_ONLY "DIR*" // Filter to include directories on directory scan
#endif // NOTE: Used in ScanDirectoryFiles(), LoadDirectoryFilesEx() and GetDirectoryFileCountEx()
// Flags operation macros // Flags operation macros
#define FLAG_SET(n, f) ((n) |= (f)) #define FLAG_SET(n, f) ((n) |= (f))
@ -505,8 +511,7 @@ extern void ClosePlatform(void); // Close platform
static void InitTimer(void); // Initialize timer, hi-resolution if available (required by InitPlatform()) static void InitTimer(void); // Initialize timer, hi-resolution if available (required by InitPlatform())
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 ScanDirectoryFiles(const char *basePath, FilePathList *list, const char *filter); // Scan all files and directories in a base path static void ScanDirectoryFiles(const char *basePath, FilePathList *list, const char *filter, unsigned int expectedFileCount, bool scanSubdirs); // Scan all files and directories in a base path
static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *list, const char *filter); // Scan all files and directories recursively from a base path
#if defined(SUPPORT_AUTOMATION_EVENTS) #if defined(SUPPORT_AUTOMATION_EVENTS)
static void RecordAutomationEvent(void); // Record frame events (to internal events array) static void RecordAutomationEvent(void); // Record frame events (to internal events array)
@ -525,7 +530,7 @@ const char *TextFormat(const char *text, ...); // Formatting of text with variab
#define PLATFORM_DESKTOP_GLFW #define PLATFORM_DESKTOP_GLFW
#endif #endif
// We're using '#pragma message' because '#warning' is not adopted by MSVC // Using '#pragma message' because '#warning' is not adopted by MSVC
#if defined(SUPPORT_CLIPBOARD_IMAGE) #if defined(SUPPORT_CLIPBOARD_IMAGE)
#if !defined(SUPPORT_MODULE_RTEXTURES) #if !defined(SUPPORT_MODULE_RTEXTURES)
#pragma message ("WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly") #pragma message ("WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly")
@ -1499,7 +1504,7 @@ Matrix GetCameraMatrix2D(Camera2D camera)
// When setting higher scale, it's more intuitive for the world to become bigger (= camera become smaller), // When setting higher scale, it's more intuitive for the world to become bigger (= camera become smaller),
// not for the camera getting bigger, hence the invert. Same deal with rotation // not for the camera getting bigger, hence the invert. Same deal with rotation
// 3. Move it by (-offset); // 3. Move it by (-offset);
// Offset defines target transform relative to screen, but since we're effectively "moving" screen (camera) // Offset defines target transform relative to screen, but since effectively "moving" screen (camera)
// we need to do it into opposite direction (inverse transform) // we need to do it into opposite direction (inverse transform)
// Having camera transform in world-space, inverse of it gives the modelview transform // Having camera transform in world-space, inverse of it gives the modelview transform
@ -2753,53 +2758,36 @@ const char *GetApplicationDirectory(void)
// No recursive scanning is done! // No recursive scanning is done!
FilePathList LoadDirectoryFiles(const char *dirPath) FilePathList LoadDirectoryFiles(const char *dirPath)
{ {
FilePathList files = { 0 }; return LoadDirectoryFilesEx(dirPath, FILE_FILTER_TAG_ALL, false);
unsigned int fileCounter = 0;
struct dirent *entity;
DIR *dir = opendir(dirPath);
if (dir != NULL) // It's a directory
{
// SCAN 1: Count files
while ((entity = readdir(dir)) != NULL)
{
// NOTE: We skip '.' (current dir) and '..' (parent dir) filepaths
if ((strcmp(entity->d_name, ".") != 0) && (strcmp(entity->d_name, "..") != 0)) fileCounter++;
}
// Memory allocation for dirFileCount
files.capacity = fileCounter;
files.paths = (char **)RL_CALLOC(files.capacity, sizeof(char *));
for (unsigned int i = 0; i < files.capacity; i++) files.paths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
closedir(dir);
// SCAN 2: Read filepaths
// NOTE: Directory paths are also registered
ScanDirectoryFiles(dirPath, &files, NULL);
// Security check: read files.count should match fileCounter
if (files.count != files.capacity) TRACELOG(LOG_WARNING, "FILEIO: Read files count do not match capacity allocated");
}
else TRACELOG(LOG_WARNING, "FILEIO: Failed to open requested directory"); // Maybe it's a file...
return files;
} }
// Load directory filepaths with extension filtering and recursive directory scan // Load directory filepaths with extension filtering and recursive directory scan
// NOTE: On recursive loading we do not pre-scan for file count, we use MAX_FILEPATH_CAPACITY // WARNING: Directory is scanned twice, first time to get files count
FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs) FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs)
{ {
FilePathList files = { 0 }; FilePathList files = { 0 };
files.capacity = MAX_FILEPATH_CAPACITY; if (DirectoryExists(basePath)) // It's a directory
files.paths = (char **)RL_CALLOC(files.capacity, sizeof(char *)); {
for (unsigned int i = 0; i < files.capacity; i++) files.paths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); // SCAN 1: Count files
unsigned int fileCounter = GetDirectoryFileCountEx(basePath, filter, scanSubdirs);
// Memory allocation for dirFileCount
files.paths = (char **)RL_CALLOC(fileCounter, sizeof(char *));
for (unsigned int i = 0; i < fileCounter; i++) files.paths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
// SCAN 2: Read filepaths
// WARNING: basePath is always prepended to scanned paths // WARNING: basePath is always prepended to scanned paths
if (scanSubdirs) ScanDirectoryFilesRecursively(basePath, &files, filter); ScanDirectoryFiles(basePath, &files, filter, fileCounter, scanSubdirs);
else ScanDirectoryFiles(basePath, &files, filter);
// Security check: read files.count should match fileCounter
if (files.count != fileCounter)
{
TRACELOG(LOG_WARNING, "FILEIO: Read files count (%u) does not match capacity allocated (%u)", files.count, fileCounter);
files.count = fileCounter; // Avoid memory leak when unloading this FilePathList
}
}
else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath); // Maybe it's a file...
return files; return files;
} }
@ -2810,7 +2798,7 @@ void UnloadDirectoryFiles(FilePathList files)
{ {
if (files.paths != NULL) if (files.paths != NULL)
{ {
for (unsigned int i = 0; i < files.capacity; i++) RL_FREE(files.paths[i]); for (unsigned int i = 0; i < files.count; i++) RL_FREE(files.paths[i]);
RL_FREE(files.paths); RL_FREE(files.paths);
} }
@ -2966,6 +2954,59 @@ void UnloadDroppedFiles(FilePathList files)
} }
} }
// Get the file count in a directory
unsigned int GetDirectoryFileCount(const char *dirPath)
{
return GetDirectoryFileCountEx(dirPath, FILE_FILTER_TAG_ALL, false);
}
// Get the file count in a directory with extension filtering and recursive directory scan. Use 'FILE_FILTER_TAG_DIR_ONLY' in the filter string to include directories in the result
unsigned int GetDirectoryFileCountEx(const char *basePath, const char *filter, bool scanSubdirs)
{
unsigned int fileCounter = 0;
// WARNING: Path can not be static or it will be reused between recursive function calls!
char path[MAX_FILEPATH_LENGTH] = { 0 };
memset(path, 0, MAX_FILEPATH_LENGTH);
struct dirent *entity;
DIR *dir = opendir(basePath);
if (dir != NULL) // It's a directory
{
while ((entity = readdir(dir)) != NULL)
{
// NOTE: We skip '.' (current dir) and '..' (parent dir) filepaths
if ((strcmp(entity->d_name, ".") != 0) && (strcmp(entity->d_name, "..") != 0))
{
// Construct new path from our base path
#if defined(_WIN32)
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s\\%s", basePath, entity->d_name);
#else
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s/%s", basePath, entity->d_name);
#endif
// Don't add to count if path too long
if ((pathLength < 0) || (pathLength >= MAX_FILEPATH_LENGTH))
{
TRACELOG(LOG_WARNING, "FILEIO: Path longer than %d characters (%s...)", MAX_FILEPATH_LENGTH, basePath);
}
else if (IsPathFile(path))
{
if ((filter == NULL) || (strstr(filter, FILE_FILTER_TAG_ALL) != NULL) ||
(strstr(filter, FILE_FILTER_TAG_FILE_ONLY) != NULL) || IsFileExtension(path, filter)) fileCounter++;
}
else
{
if ((filter != NULL) && ((strstr(filter, FILE_FILTER_TAG_ALL) != NULL) || (strstr(filter, FILE_FILTER_TAG_DIR_ONLY) != NULL))) fileCounter++;
if (scanSubdirs) fileCounter += GetDirectoryFileCountEx(path, filter, scanSubdirs);
}
}
}
}
else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath); // Maybe it's a file...
return fileCounter;
}
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition: Compression and Encoding // Module Functions Definition: Compression and Encoding
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -3790,7 +3831,6 @@ void PlayAutomationEvent(AutomationEvent event)
// Check if a key has been pressed once // Check if a key has been pressed once
bool IsKeyPressed(int key) bool IsKeyPressed(int key)
{ {
bool pressed = false; bool pressed = false;
if ((key > 0) && (key < MAX_KEYBOARD_KEYS)) if ((key > 0) && (key < MAX_KEYBOARD_KEYS))
@ -3932,8 +3972,10 @@ bool IsGamepadButtonPressed(int gamepad, int button)
{ {
bool pressed = false; bool pressed = false;
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
(CORE.Input.Gamepad.previousButtonState[gamepad][button] == 0) && (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 1)) pressed = true; {
if ((CORE.Input.Gamepad.previousButtonState[gamepad][button] == 0) && (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 1)) pressed = true;
}
return pressed; return pressed;
} }
@ -3943,8 +3985,10 @@ bool IsGamepadButtonDown(int gamepad, int button)
{ {
bool down = false; bool down = false;
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
(CORE.Input.Gamepad.currentButtonState[gamepad][button] == 1)) down = true; {
if (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 1) down = true;
}
return down; return down;
} }
@ -3954,8 +3998,10 @@ bool IsGamepadButtonReleased(int gamepad, int button)
{ {
bool released = false; bool released = false;
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
(CORE.Input.Gamepad.previousButtonState[gamepad][button] == 1) && (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 0)) released = true; {
if ((CORE.Input.Gamepad.previousButtonState[gamepad][button] == 1) && (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 0)) released = true;
}
return released; return released;
} }
@ -3965,13 +4011,16 @@ bool IsGamepadButtonUp(int gamepad, int button)
{ {
bool up = false; bool up = false;
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
(CORE.Input.Gamepad.currentButtonState[gamepad][button] == 0)) up = true; {
if (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 0) up = true;
}
return up; return up;
} }
// Get the last gamepad button pressed // Get the last gamepad button pressed
// NOTE: Returns last gamepad button down, down->up change not considered
int GetGamepadButtonPressed(void) int GetGamepadButtonPressed(void)
{ {
return CORE.Input.Gamepad.lastButtonPressed; return CORE.Input.Gamepad.lastButtonPressed;
@ -4011,10 +4060,13 @@ bool IsMouseButtonPressed(int button)
{ {
bool pressed = false; bool pressed = false;
if ((button >= 0) && (button <= MOUSE_BUTTON_BACK))
{
if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) pressed = true; if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) pressed = true;
// Map touches to mouse buttons checking // Map touches to mouse buttons checking
if ((CORE.Input.Touch.currentTouchState[button] == 1) && (CORE.Input.Touch.previousTouchState[button] == 0)) pressed = true; if ((CORE.Input.Touch.currentTouchState[button] == 1) && (CORE.Input.Touch.previousTouchState[button] == 0)) pressed = true;
}
return pressed; return pressed;
} }
@ -4024,10 +4076,13 @@ bool IsMouseButtonDown(int button)
{ {
bool down = false; bool down = false;
if ((button >= 0) && (button <= MOUSE_BUTTON_BACK))
{
if (CORE.Input.Mouse.currentButtonState[button] == 1) down = true; if (CORE.Input.Mouse.currentButtonState[button] == 1) down = true;
// NOTE: Touches are considered like mouse buttons // NOTE: Touches are considered like mouse buttons
if (CORE.Input.Touch.currentTouchState[button] == 1) down = true; if (CORE.Input.Touch.currentTouchState[button] == 1) down = true;
}
return down; return down;
} }
@ -4037,10 +4092,13 @@ bool IsMouseButtonReleased(int button)
{ {
bool released = false; bool released = false;
if ((button >= 0) && (button <= MOUSE_BUTTON_BACK))
{
if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) released = true; if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) released = true;
// Map touches to mouse buttons checking // Map touches to mouse buttons checking
if ((CORE.Input.Touch.currentTouchState[button] == 0) && (CORE.Input.Touch.previousTouchState[button] == 1)) released = true; if ((CORE.Input.Touch.currentTouchState[button] == 0) && (CORE.Input.Touch.previousTouchState[button] == 1)) released = true;
}
return released; return released;
} }
@ -4050,10 +4108,13 @@ bool IsMouseButtonUp(int button)
{ {
bool up = false; bool up = false;
if ((button >= 0) && (button <= MOUSE_BUTTON_BACK))
{
if (CORE.Input.Mouse.currentButtonState[button] == 0) up = true; if (CORE.Input.Mouse.currentButtonState[button] == 0) up = true;
// NOTE: Touches are considered like mouse buttons // NOTE: Touches are considered like mouse buttons
if (CORE.Input.Touch.currentTouchState[button] == 0) up = true; if (CORE.Input.Touch.currentTouchState[button] == 0) up = true;
}
return up; return up;
} }
@ -4062,6 +4123,7 @@ bool IsMouseButtonUp(int button)
int GetMouseX(void) int GetMouseX(void)
{ {
int mouseX = (int)((CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x); int mouseX = (int)((CORE.Input.Mouse.currentPosition.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x);
return mouseX; return mouseX;
} }
@ -4069,6 +4131,7 @@ int GetMouseX(void)
int GetMouseY(void) int GetMouseY(void)
{ {
int mouseY = (int)((CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y); int mouseY = (int)((CORE.Input.Mouse.currentPosition.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y);
return mouseY; return mouseY;
} }
@ -4229,66 +4292,7 @@ void SetupViewport(int width, int height)
// Scan all files and directories in a base path // Scan all files and directories in a base path
// WARNING: files.paths[] must be previously allocated and // WARNING: files.paths[] must be previously allocated and
// contain enough space to store all required paths // contain enough space to store all required paths
static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const char *filter) static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const char *filter, unsigned int expectedFileCount, bool scanSubdirs)
{
static char path[MAX_FILEPATH_LENGTH] = { 0 };
memset(path, 0, MAX_FILEPATH_LENGTH);
struct dirent *dp = NULL;
DIR *dir = opendir(basePath);
if (dir != NULL)
{
while ((dp = readdir(dir)) != NULL)
{
if ((strcmp(dp->d_name, ".") != 0) &&
(strcmp(dp->d_name, "..") != 0))
{
// Construct new path from our base path
#if defined(_WIN32)
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s\\%s", basePath, dp->d_name);
#else
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s/%s", basePath, dp->d_name);
#endif
if ((pathLength < 0) || (pathLength >= MAX_FILEPATH_LENGTH))
{
TRACELOG(LOG_WARNING, "FILEIO: Path longer than %d characters (%s...)", MAX_FILEPATH_LENGTH, basePath);
}
else if (filter != NULL)
{
if (IsPathFile(path))
{
if (IsFileExtension(path, filter))
{
strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
files->count++;
}
}
else
{
if (strstr(filter, DIRECTORY_FILTER_TAG) != NULL)
{
strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
files->count++;
}
}
}
else
{
strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
files->count++;
}
}
}
closedir(dir);
}
else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath);
}
// Scan all files and directories recursively from a base path
static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *files, const char *filter)
{ {
// WARNING: Path can not be static or it will be reused between recursive function calls! // WARNING: Path can not be static or it will be reused between recursive function calls!
char path[MAX_FILEPATH_LENGTH] = { 0 }; char path[MAX_FILEPATH_LENGTH] = { 0 };
@ -4299,7 +4303,7 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
if (dir != NULL) if (dir != NULL)
{ {
while (((dp = readdir(dir)) != NULL) && (files->count < files->capacity)) while (((dp = readdir(dir)) != NULL) && (files->count < expectedFileCount))
{ {
if ((strcmp(dp->d_name, ".") != 0) && (strcmp(dp->d_name, "..") != 0)) if ((strcmp(dp->d_name, ".") != 0) && (strcmp(dp->d_name, "..") != 0))
{ {
@ -4316,9 +4320,8 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
} }
else if (IsPathFile(path)) else if (IsPathFile(path))
{ {
if (filter != NULL) if ((filter == NULL) || (strstr(filter, FILE_FILTER_TAG_ALL) != NULL) ||
{ (strstr(filter, FILE_FILTER_TAG_FILE_ONLY) != NULL) || IsFileExtension(path, filter))
if (IsFileExtension(path, filter))
{ {
strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1); strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
files->count++; files->count++;
@ -4326,38 +4329,20 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
} }
else else
{ {
strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1); if ((filter != NULL) && ((strstr(filter, FILE_FILTER_TAG_DIR_ONLY) != NULL) || (strstr(filter, FILE_FILTER_TAG_ALL) != NULL)))
files->count++;
}
if (files->count >= files->capacity)
{
TRACELOG(LOG_WARNING, "FILEIO: Maximum filepath scan capacity reached (%i files)", files->capacity);
break;
}
}
else
{
if ((filter != NULL) && (strstr(filter, DIRECTORY_FILTER_TAG) != NULL))
{ {
strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1); strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
files->count++; files->count++;
} }
if (files->count >= files->capacity) if (scanSubdirs) ScanDirectoryFiles(path, files, filter, expectedFileCount, scanSubdirs);
{
TRACELOG(LOG_WARNING, "FILEIO: Maximum filepath scan capacity reached (%i files)", files->capacity);
break;
}
ScanDirectoryFilesRecursively(path, files, filter);
} }
} }
} }
closedir(dir); closedir(dir);
} }
else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath); else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath); // Maybe it's a file...
} }
#if defined(SUPPORT_AUTOMATION_EVENTS) #if defined(SUPPORT_AUTOMATION_EVENTS)

View File

@ -113,11 +113,11 @@
// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll // NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
// NOTE: visibility(default) attribute makes symbols "visible" when compiled with -fvisibility=hidden // NOTE: visibility(default) attribute makes symbols "visible" when compiled with -fvisibility=hidden
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED) #if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
#define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) #define RLAPI __declspec(dllexport) // Building the library as a Win32 shared library (.dll)
#elif defined(BUILD_LIBTYPE_SHARED) #elif defined(BUILD_LIBTYPE_SHARED)
#define RLAPI __attribute__((visibility("default"))) // We are building the library as a Unix shared library (.so/.dylib) #define RLAPI __attribute__((visibility("default"))) // Building the library as a Unix shared library (.so/.dylib)
#elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED)
#define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) #define RLAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll)
#endif #endif
// Function specifiers definition // Function specifiers definition
@ -1270,12 +1270,12 @@ void rlLoadIdentity(void)
// Multiply the current matrix by a translation matrix // Multiply the current matrix by a translation matrix
void rlTranslatef(float x, float y, float z) void rlTranslatef(float x, float y, float z)
{ {
Matrix matTranslation = { Matrix matTranslation = rlMatrixIdentity();
1.0f, 0.0f, 0.0f, x,
0.0f, 1.0f, 0.0f, y, // Set translation component of matrix
0.0f, 0.0f, 1.0f, z, matTranslation.m12 = x;
0.0f, 0.0f, 0.0f, 1.0f matTranslation.m13 = y;
}; matTranslation.m14 = z;
// NOTE: We transpose matrix with multiplication order // NOTE: We transpose matrix with multiplication order
*RLGL.State.currentMatrix = rlMatrixMultiply(matTranslation, *RLGL.State.currentMatrix); *RLGL.State.currentMatrix = rlMatrixMultiply(matTranslation, *RLGL.State.currentMatrix);
@ -1329,12 +1329,12 @@ void rlRotatef(float angle, float x, float y, float z)
// Multiply the current matrix by a scaling matrix // Multiply the current matrix by a scaling matrix
void rlScalef(float x, float y, float z) void rlScalef(float x, float y, float z)
{ {
Matrix matScale = { Matrix matScale = rlMatrixIdentity();
x, 0.0f, 0.0f, 0.0f,
0.0f, y, 0.0f, 0.0f, // Set scale component of matrix
0.0f, 0.0f, z, 0.0f, matScale.m0 = x;
0.0f, 0.0f, 0.0f, 1.0f matScale.m5 = y;
}; matScale.m10 = z;
// NOTE: We transpose matrix with multiplication order // NOTE: We transpose matrix with multiplication order
*RLGL.State.currentMatrix = rlMatrixMultiply(matScale, *RLGL.State.currentMatrix); *RLGL.State.currentMatrix = rlMatrixMultiply(matScale, *RLGL.State.currentMatrix);
@ -1344,6 +1344,7 @@ void rlScalef(float x, float y, float z)
void rlMultMatrixf(const float *matf) void rlMultMatrixf(const float *matf)
{ {
// Matrix creation from array // Matrix creation from array
// Conversion from column-major to row-major memory order
Matrix mat = { matf[0], matf[4], matf[8], matf[12], Matrix mat = { matf[0], matf[4], matf[8], matf[12],
matf[1], matf[5], matf[9], matf[13], matf[1], matf[5], matf[9], matf[13],
matf[2], matf[6], matf[10], matf[14], matf[2], matf[6], matf[10], matf[14],
@ -3731,7 +3732,7 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format)
// Two possible Options: // Two possible Options:
// 1 - Bind texture to color fbo attachment and glReadPixels() // 1 - Bind texture to color fbo attachment and glReadPixels()
// 2 - Create an fbo, activate it, render quad with texture, glReadPixels() // 2 - Create an fbo, activate it, render quad with texture, glReadPixels()
// We are using Option 1, just need to care for texture format on retrieval // Using Option 1, just need to care for texture format on retrieval
// NOTE: This behaviour could be conditioned by graphic driver... // NOTE: This behaviour could be conditioned by graphic driver...
unsigned int fboId = rlLoadFramebuffer(); unsigned int fboId = rlLoadFramebuffer();
@ -4463,13 +4464,7 @@ void rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType
void rlSetUniformMatrix(int locIndex, Matrix mat) void rlSetUniformMatrix(int locIndex, Matrix mat)
{ {
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
float matfloat[16] = { glUniformMatrix4fv(locIndex, 1, false, rlMatrixToFloat(mat));
mat.m0, mat.m1, mat.m2, mat.m3,
mat.m4, mat.m5, mat.m6, mat.m7,
mat.m8, mat.m9, mat.m10, mat.m11,
mat.m12, mat.m13, mat.m14, mat.m15
};
glUniformMatrix4fv(locIndex, 1, false, matfloat);
#endif #endif
} }
@ -5255,17 +5250,17 @@ static int rlGetPixelDataSize(int width, int height, int format)
// Get identity matrix // Get identity matrix
static Matrix rlMatrixIdentity(void) static Matrix rlMatrixIdentity(void)
{ {
Matrix result = { Matrix matIdentity = { 0 };
1.0f, 0.0f, 0.0f, 0.0f, matIdentity.m0 = 1.0f;
0.0f, 1.0f, 0.0f, 0.0f, matIdentity.m5 = 1.0f;
0.0f, 0.0f, 1.0f, 0.0f, matIdentity.m10 = 1.0f;
0.0f, 0.0f, 0.0f, 1.0f matIdentity.m15 = 1.0f;
};
return result; return matIdentity;
} }
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Get float array of matrix data // Get float array of matrix data
// Explicit conversion to column-major memory layout
static rl_float16 rlMatrixToFloatV(Matrix mat) static rl_float16 rlMatrixToFloatV(Matrix mat)
{ {
rl_float16 result = { 0 }; rl_float16 result = { 0 };

View File

@ -1754,7 +1754,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
// This could alternatively use a static VBO and either glMapBuffer() or glBufferSubData() // This could alternatively use a static VBO and either glMapBuffer() or glBufferSubData()
// It isn't clear which would be reliably faster in all cases and on all platforms, // It isn't clear which would be reliably faster in all cases and on all platforms,
// anecdotally glMapBuffer() seems very slow (syncs) while glBufferSubData() seems // anecdotally glMapBuffer() seems very slow (syncs) while glBufferSubData() seems
// no faster, since we're transferring all the transform matrices anyway // no faster, since all the transform matrices are transferred anyway
instancesVboId = rlLoadVertexBuffer(instanceTransforms, instances*sizeof(float16), false); instancesVboId = rlLoadVertexBuffer(instanceTransforms, instances*sizeof(float16), false);
// Instances transformation matrices are sent to shader attribute location: SHADER_LOC_VERTEX_INSTANCE_TX // Instances transformation matrices are sent to shader attribute location: SHADER_LOC_VERTEX_INSTANCE_TX
@ -4084,7 +4084,7 @@ RayCollision GetRayCollisionBox(Ray ray, BoundingBox box)
{ {
RayCollision collision = { 0 }; RayCollision collision = { 0 };
// Note: If ray.position is inside the box, the distance is negative (as if the ray was reversed) // NOTE: If ray.position is inside the box, the distance is negative (as if the ray was reversed)
// Reversing ray.direction will give use the correct result // Reversing ray.direction will give use the correct result
bool insideBox = (ray.position.x > box.min.x) && (ray.position.x < box.max.x) && bool insideBox = (ray.position.x > box.min.x) && (ray.position.x < box.max.x) &&
(ray.position.y > box.min.y) && (ray.position.y < box.max.y) && (ray.position.y > box.min.y) && (ray.position.y < box.max.y) &&
@ -6517,7 +6517,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
}; };
} }
Transform* root = &animations[i].framePoses[j][0]; Transform *root = &animations[i].framePoses[j][0];
root->rotation = QuaternionMultiply(worldTransform.rotation, root->rotation); root->rotation = QuaternionMultiply(worldTransform.rotation, root->rotation);
root->scale = Vector3Multiply(root->scale, worldTransform.scale); root->scale = Vector3Multiply(root->scale, worldTransform.scale);
root->translation = Vector3Multiply(root->translation, worldTransform.scale); root->translation = Vector3Multiply(root->translation, worldTransform.scale);

View File

@ -59,9 +59,9 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Error rate to calculate how many segments we need to draw a smooth circle,
// taken from https://stackoverflow.com/a/2244088
#ifndef SMOOTH_CIRCLE_ERROR_RATE #ifndef SMOOTH_CIRCLE_ERROR_RATE
// Define error rate to calculate how many segments are needed to draw a smooth circle
// REF: https://stackoverflow.com/a/2244088
#define SMOOTH_CIRCLE_ERROR_RATE 0.5f // Circle error rate #define SMOOTH_CIRCLE_ERROR_RATE 0.5f // Circle error rate
#endif #endif
#ifndef SPLINE_SEGMENT_DIVISIONS #ifndef SPLINE_SEGMENT_DIVISIONS
@ -318,7 +318,7 @@ void DrawCircle(int centerX, int centerY, float radius, Color color)
} }
// Draw a color-filled circle (Vector version) // Draw a color-filled circle (Vector version)
// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues // NOTE: On OpenGL 3.3 and ES2 using QUADS to avoid drawing order issues
void DrawCircleV(Vector2 center, float radius, Color color) void DrawCircleV(Vector2 center, float radius, Color color)
{ {
DrawCircleSector(center, radius, 0, 360, 36, color); DrawCircleSector(center, radius, 0, 360, 36, color);
@ -379,7 +379,7 @@ void DrawCircleSector(Vector2 center, float radius, float startAngle, float endA
angle += (stepLength*2.0f); angle += (stepLength*2.0f);
} }
// NOTE: In case number of segments is odd, we add one last piece to the cake // NOTE: In case number of segments is odd, adding one last piece to the cake
if ((((unsigned int)segments)%2) == 1) if ((((unsigned int)segments)%2) == 1)
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
@ -722,7 +722,7 @@ void DrawRectangle(int posX, int posY, int width, int height, Color color)
} }
// Draw a color-filled rectangle (Vector version) // Draw a color-filled rectangle (Vector version)
// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues // NOTE: On OpenGL 3.3 and ES2 using QUADS to avoid drawing order issues
void DrawRectangleV(Vector2 position, Vector2 size, Color color) void DrawRectangleV(Vector2 position, Vector2 size, Color color)
{ {
DrawRectanglePro((Rectangle){ position.x, position.y, size.x, size.y }, (Vector2){ 0.0f, 0.0f }, 0.0f, color); DrawRectanglePro((Rectangle){ position.x, position.y, size.x, size.y }, (Vector2){ 0.0f, 0.0f }, 0.0f, color);
@ -968,7 +968,7 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
/* /*
Quick sketch to make sense of all of this, Quick sketch to make sense of all of this,
there are 9 parts to draw, also mark the 12 points we'll use there are 9 parts to draw, also mark the 12 points used
P0____________________P1 P0____________________P1
/| |\ /| |\
@ -1024,7 +1024,7 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
angle += (stepLength*2); angle += (stepLength*2);
} }
// NOTE: In case number of segments is odd, we add one last piece to the cake // NOTE: In case number of segments is odd, adding one last piece to the cake
if (segments%2) if (segments%2)
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
@ -1168,7 +1168,7 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
// Draw rectangle with rounded edges // Draw rectangle with rounded edges
void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color) void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color)
{ {
// NOTE: For line thicknes <=1.0f we use RL_LINES, otherwise wee use RL_QUADS/RL_TRIANGLES // NOTE: For line thicknes <=1.0f using RL_LINES, otherwise using RL_QUADS/RL_TRIANGLES
DrawRectangleRoundedLinesEx(rec, roundness, segments, 1.0f, color); DrawRectangleRoundedLinesEx(rec, roundness, segments, 1.0f, color);
} }
@ -1204,7 +1204,7 @@ void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, f
/* /*
Quick sketch to make sense of all of this, Quick sketch to make sense of all of this,
marks the 16 + 4(corner centers P16-19) points we'll use marks the 16 + 4(corner centers P16-19) points used
P0 ================== P1 P0 ================== P1
// P8 P9 \\ // P8 P9 \\
@ -1946,7 +1946,7 @@ void DrawSplineBezierCubic(const Vector2 *points, int pointCount, float thick, C
// Draw spline segment: Linear, 2 points // Draw spline segment: Linear, 2 points
void DrawSplineSegmentLinear(Vector2 p1, Vector2 p2, float thick, Color color) void DrawSplineSegmentLinear(Vector2 p1, Vector2 p2, float thick, Color color)
{ {
// NOTE: For the linear spline we don't use subdivisions, just a single quad // NOTE: For the linear spline no subdivisions are used, just a single quad
Vector2 delta = { p2.x - p1.x, p2.y - p1.y }; Vector2 delta = { p2.x - p1.x, p2.y - p1.y };
float length = sqrtf(delta.x*delta.x + delta.y*delta.y); float length = sqrtf(delta.x*delta.x + delta.y*delta.y);

View File

@ -1727,7 +1727,6 @@ char *GetTextBetween(const char *text, const char *begin, const char *end)
// Replace text string // Replace text string
// REQUIRES: strstr(), strncpy() // REQUIRES: strstr(), strncpy()
// TODO: If (replacement == "") remove "search" text
// WARNING: Allocated memory must be manually freed // WARNING: Allocated memory must be manually freed
char *TextReplace(const char *text, const char *search, const char *replacement) char *TextReplace(const char *text, const char *search, const char *replacement)
{ {
@ -1735,6 +1734,8 @@ char *TextReplace(const char *text, const char *search, const char *replacement)
if ((text != NULL) && (search != NULL)) if ((text != NULL) && (search != NULL))
{ {
if (replacement == NULL) replacement = "";
char *insertPoint = NULL; // Next insert point char *insertPoint = NULL; // Next insert point
char *temp = NULL; // Temp pointer char *temp = NULL; // Temp pointer
int textLen = 0; // Text string length int textLen = 0; // Text string length
@ -1768,15 +1769,14 @@ char *TextReplace(const char *text, const char *search, const char *replacement)
insertPoint = (char *)strstr(text, search); insertPoint = (char *)strstr(text, search);
lastReplacePos = (int)(insertPoint - text); lastReplacePos = (int)(insertPoint - text);
// TODO: Review logic to avoid strcpy() memcpy(temp, text, lastReplacePos);
// OK - Those lines work temp += lastReplacePos;
temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
temp = strcpy(temp, replacement) + replaceLen; if (replaceLen > 0)
// WRONG - But not those ones {
//temp = strncpy(temp, text, tempLen - 1) + lastReplacePos; memcpy(temp, replacement, replaceLen);
//tempLen -= lastReplacePos; temp += replaceLen;
//temp = strncpy(temp, replacement, tempLen - 1) + replaceLen; }
//tempLen -= replaceLen;
text += lastReplacePos + searchLen; // Move to next "end of replace" text += lastReplacePos + searchLen; // Move to next "end of replace"
} }

View File

@ -3625,7 +3625,7 @@ void ImageDrawLineEx(Image *dst, Vector2 start, Vector2 end, int thick, Color co
} }
// Draw circle within an image // Draw circle within an image
void ImageDrawCircle(Image* dst, int centerX, int centerY, int radius, Color color) void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color)
{ {
int x = 0; int x = 0;
int y = radius; int y = radius;
@ -3649,7 +3649,7 @@ void ImageDrawCircle(Image* dst, int centerX, int centerY, int radius, Color col
} }
// Draw circle within an image (Vector version) // Draw circle within an image (Vector version)
void ImageDrawCircleV(Image* dst, Vector2 center, int radius, Color color) void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color)
{ {
ImageDrawCircle(dst, (int)center.x, (int)center.y, radius, color); ImageDrawCircle(dst, (int)center.x, (int)center.y, radius, color);
} }

View File

@ -1556,7 +1556,7 @@ int main(int argc, char *argv[])
"#include <string.h>\n" "#include <string.h>\n"
"#include <stdlib.h>\n" "#include <stdlib.h>\n"
"#include <emscripten/emscripten.h>\n\n" "#include <emscripten/emscripten.h>\n\n"
"static char logText[4096] = {0};\n" "static char logText[4096] = { 0 };\n"
"static int logTextOffset = 0;\n\n" "static int logTextOffset = 0;\n\n"
"void CustomTraceLog(int msgType, const char *text, va_list args)\n{\n" "void CustomTraceLog(int msgType, const char *text, va_list args)\n{\n"
" if (logTextOffset < 3800)\n {\n" " if (logTextOffset < 3800)\n {\n"

View File

@ -1324,11 +1324,6 @@
"name": "FilePathList", "name": "FilePathList",
"description": "File path list", "description": "File path list",
"fields": [ "fields": [
{
"type": "unsigned int",
"name": "capacity",
"description": "Filepaths max entries"
},
{ {
"type": "unsigned int", "type": "unsigned int",
"name": "count", "name": "count",
@ -4734,6 +4729,36 @@
} }
] ]
}, },
{
"name": "GetDirectoryFileCount",
"description": "Get the file count in a directory",
"returnType": "unsigned int",
"params": [
{
"type": "const char *",
"name": "dirPath"
}
]
},
{
"name": "GetDirectoryFileCountEx",
"description": "Get the file count in a directory with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result",
"returnType": "unsigned int",
"params": [
{
"type": "const char *",
"name": "basePath"
},
{
"type": "const char *",
"name": "filter"
},
{
"type": "bool",
"name": "scanSubdirs"
}
]
},
{ {
"name": "CompressData", "name": "CompressData",
"description": "Compress data (DEFLATE algorithm), memory must be MemFree()", "description": "Compress data (DEFLATE algorithm), memory must be MemFree()",

View File

@ -1324,11 +1324,6 @@ return {
name = "FilePathList", name = "FilePathList",
description = "File path list", description = "File path list",
fields = { fields = {
{
type = "unsigned int",
name = "capacity",
description = "Filepaths max entries"
},
{ {
type = "unsigned int", type = "unsigned int",
name = "count", name = "count",
@ -4230,6 +4225,24 @@ return {
{type = "FilePathList", name = "files"} {type = "FilePathList", name = "files"}
} }
}, },
{
name = "GetDirectoryFileCount",
description = "Get the file count in a directory",
returnType = "unsigned int",
params = {
{type = "const char *", name = "dirPath"}
}
},
{
name = "GetDirectoryFileCountEx",
description = "Get the file count in a directory with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result",
returnType = "unsigned int",
params = {
{type = "const char *", name = "basePath"},
{type = "const char *", name = "filter"},
{type = "bool", name = "scanSubdirs"}
}
},
{ {
name = "CompressData", name = "CompressData",
description = "Compress data (DEFLATE algorithm), memory must be MemFree()", description = "Compress data (DEFLATE algorithm), memory must be MemFree()",

File diff suppressed because it is too large Load Diff

View File

@ -280,8 +280,7 @@
<Field type="float[2]" name="scale" desc="VR distortion scale" /> <Field type="float[2]" name="scale" desc="VR distortion scale" />
<Field type="float[2]" name="scaleIn" desc="VR distortion scale in" /> <Field type="float[2]" name="scaleIn" desc="VR distortion scale in" />
</Struct> </Struct>
<Struct name="FilePathList" fieldCount="3" desc="File path list"> <Struct name="FilePathList" fieldCount="2" desc="File path list">
<Field type="unsigned int" name="capacity" desc="Filepaths max entries" />
<Field type="unsigned int" name="count" desc="Filepaths entries count" /> <Field type="unsigned int" name="count" desc="Filepaths entries count" />
<Field type="char **" name="paths" desc="Filepaths entries" /> <Field type="char **" name="paths" desc="Filepaths entries" />
</Struct> </Struct>
@ -679,7 +678,7 @@
<Param type="unsigned int" name="frames" desc="" /> <Param type="unsigned int" name="frames" desc="" />
</Callback> </Callback>
</Callbacks> </Callbacks>
<Functions count="597"> <Functions count="599">
<Function name="InitWindow" retType="void" paramCount="3" desc="Initialize window and OpenGL context"> <Function name="InitWindow" retType="void" paramCount="3" desc="Initialize window and OpenGL context">
<Param type="int" name="width" desc="" /> <Param type="int" name="width" desc="" />
<Param type="int" name="height" desc="" /> <Param type="int" name="height" desc="" />
@ -1137,6 +1136,14 @@
<Function name="UnloadDroppedFiles" retType="void" paramCount="1" desc="Unload dropped filepaths"> <Function name="UnloadDroppedFiles" retType="void" paramCount="1" desc="Unload dropped filepaths">
<Param type="FilePathList" name="files" desc="" /> <Param type="FilePathList" name="files" desc="" />
</Function> </Function>
<Function name="GetDirectoryFileCount" retType="unsigned int" paramCount="1" desc="Get the file count in a directory">
<Param type="const char *" name="dirPath" desc="" />
</Function>
<Function name="GetDirectoryFileCountEx" retType="unsigned int" paramCount="3" desc="Get the file count in a directory with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result">
<Param type="const char *" name="basePath" desc="" />
<Param type="const char *" name="filter" desc="" />
<Param type="bool" name="scanSubdirs" desc="" />
</Function>
<Function name="CompressData" retType="unsigned char *" paramCount="3" desc="Compress data (DEFLATE algorithm), memory must be MemFree()"> <Function name="CompressData" retType="unsigned char *" paramCount="3" desc="Compress data (DEFLATE algorithm), memory must be MemFree()">
<Param type="const unsigned char *" name="data" desc="" /> <Param type="const unsigned char *" name="data" desc="" />
<Param type="int" name="dataSize" desc="" /> <Param type="int" name="dataSize" desc="" />

View File

@ -198,7 +198,7 @@ static void ExportParsedData(const char *fileName, int format); // Export parsed
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Program main entry point // Program main entry point
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
int main(int argc, char* argv[]) int main(int argc, char *argv[])
{ {
if (argc > 1) ProcessCommandLine(argc, argv); if (argc > 1) ProcessCommandLine(argc, argv);