diff --git a/examples/Makefile b/examples/Makefile index f57888ace..ce02d55fa 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -471,7 +471,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) del *.o *.exe /s endif ifeq ($(PLATFORM_OS),LINUX) - find -type f -executable | xargs file -i | grep -E 'x-object|x-archive|x-sharedlib|x-executable' | rev | cut -d ':' -f 2- | rev | xargs rm -fv + find -type f -executable | xargs file -i | grep -E 'x-object|x-archive|x-sharedlib|x-executable|x-pie-executable' | rev | cut -d ':' -f 2- | rev | xargs rm -fv endif ifeq ($(PLATFORM_OS),OSX) find . -type f -perm +ugo+x -delete diff --git a/examples/core/core_2d_camera.c b/examples/core/core_2d_camera.c index 81f580ad3..d6c85079e 100644 --- a/examples/core/core_2d_camera.c +++ b/examples/core/core_2d_camera.c @@ -42,7 +42,7 @@ int main(void) Camera2D camera = { 0 }; camera.target = (Vector2){ player.x + 20, player.y + 20 }; - camera.offset = (Vector2){ 0, 0 }; + camera.offset = (Vector2){ screenWidth/2, screenHeight/2 }; camera.rotation = 0.0f; camera.zoom = 1.0f; @@ -54,16 +54,10 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - if (IsKeyDown(KEY_RIGHT)) - { - player.x += 2; // Player movement - camera.offset.x -= 2; // Camera displacement with player movement - } - else if (IsKeyDown(KEY_LEFT)) - { - player.x -= 2; // Player movement - camera.offset.x += 2; // Camera displacement with player movement - } + + // Player movement + if (IsKeyDown(KEY_RIGHT)) player.x += 2; + else if (IsKeyDown(KEY_LEFT)) player.x -= 2; // Camera target follows player camera.target = (Vector2){ player.x + 20, player.y + 20 }; @@ -135,4 +129,4 @@ int main(void) //-------------------------------------------------------------------------------------- return 0; -} \ No newline at end of file +} diff --git a/examples/core/core_2d_camera_ext.c b/examples/core/core_2d_camera_ext.c new file mode 100644 index 000000000..330e39ef9 --- /dev/null +++ b/examples/core/core_2d_camera_ext.c @@ -0,0 +1,284 @@ +/******************************************************************************************* +* +* raylib [core] example - 2d camera extended +* +* This example has been created using raylib 1.5 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2016 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" +#include "raymath.h" + +#define G 400 +#define PLAYER_JUMP_SPD 350.f +#define PLAYER_HOR_SPD 200.f + +typedef struct Player { + Vector2 pos; + float vel; + int canJump; +} Player; + +typedef struct EnvItem { + Rectangle rect; + int blocking; + Color color; +} EnvItem; + +void updateCameraCenter( + float delta, + Camera2D *camera, + Player *player, + EnvItem *envItems, + int envItemsLength, + int width, int height +) { + camera->offset = (Vector2){ width/2, height/2 }; + camera->target = player->pos; +} + +void updateCameraCenterInsideMap( + float delta, + Camera2D *camera, + Player *player, + EnvItem *envItems, + int envItemsLength, + int width, int height +) { + camera->target = player->pos; + camera->offset = (Vector2){ width/2, height/2 }; + float minX = 1000, minY = 1000, maxX = -1000, maxY = -1000; + for (int i = 0; i < envItemsLength; i++) { + EnvItem *ei = envItems + i; + minX = fminf(ei->rect.x, minX); + maxX = fmaxf(ei->rect.x + ei->rect.width, maxX); + minY = fminf(ei->rect.y, minY); + maxY = fmaxf(ei->rect.y + ei->rect.height, maxY); + } + Vector2 max = GetWorldToScreen2D((Vector2){ maxX, maxY }, *camera); + Vector2 min = GetWorldToScreen2D((Vector2){ minX, minY }, *camera); + if (max.x < width) { + camera->offset.x = width - (max.x - width/2); + } + if (max.y < height) { + camera->offset.y = height - (max.y - height/2); + } + if (min.x > 0) { + camera->offset.x = width/2 - min.x; + } + if (min.y > 0) { + camera->offset.y = height/2- min.y; + } +} + +void updateCameraCenterSmoothFollow( + float delta, + Camera2D *camera, + Player *player, + EnvItem *envItems, + int envItemsLength, + int width, int height +) { + static float minSpeed = 30; + static float minEffectLength = 10; + static float fractionSpeed = 0.8f; + camera->offset = (Vector2){ width/2, height/2 }; + Vector2 diff = Vector2Subtract(player->pos, camera->target); + float length = Vector2Length(diff); + if (length > minEffectLength) { + float speed = fmaxf(fractionSpeed * length, minSpeed); + camera->target = Vector2Add(camera->target, Vector2Scale(diff, speed*delta/length)); + } +} + +void updateCameraEvenOutOnLanding( + float delta, + Camera2D *camera, + Player *player, + EnvItem *envItems, + int envItemsLength, + int width, int height +) { + static float evenOutSpeed = 700; + static int eveningOut = false; + static float evenOutTarget; + camera->offset = (Vector2){ width/2, height/2 }; + camera->target.x = player->pos.x; + if (eveningOut) { + if (evenOutTarget > camera->target.y) { + camera->target.y += evenOutSpeed * delta; + if (camera->target.y > evenOutTarget) { + camera->target.y = evenOutTarget; + eveningOut = 0; + } + } else { + camera->target.y -= evenOutSpeed * delta; + if (camera->target.y < evenOutTarget) { + camera->target.y = evenOutTarget; + eveningOut = 0; + } + } + } else { + if (player->canJump && + player->vel == 0 && + player->pos.y != camera->target.y + ) { + eveningOut = 1; + evenOutTarget = player->pos.y; + } + } +} + +void updateCameraPlayerBoundsPush( + float delta, + Camera2D *camera, + Player *player, + EnvItem *envItems, + int envItemsLength, + int width, int height +) { + static Vector2 bbox = { 0.2f, 0.2f }; + + Vector2 bboxWorldMin = GetScreenToWorld2D((Vector2){ (1 - bbox.x) * 0.5 * width, (1 - bbox.y) * 0.5 * height }, *camera); + Vector2 bboxWorldMax = GetScreenToWorld2D((Vector2){ (1 + bbox.x) * 0.5 * width, (1 + bbox.y) * 0.5 * height }, *camera); + camera->offset = (Vector2){ (1 - bbox.x) * 0.5 * width, (1 - bbox.y) * 0.5 * height }; + + if (player->pos.x < bboxWorldMin.x) { + camera->target.x = player->pos.x; + } + if (player->pos.y < bboxWorldMin.y) { + camera->target.y = player->pos.y; + } + if (player->pos.x > bboxWorldMax.x) { + camera->target.x = bboxWorldMin.x + (player->pos.x - bboxWorldMax.x); + } + if (player->pos.y > bboxWorldMax.y) { + camera->target.y = bboxWorldMin.y + (player->pos.y - bboxWorldMax.y); + } +} + + +void updatePlayer(float delta, Player *player, EnvItem *envItems, int envItemsLength) { + if (IsKeyDown(KEY_LEFT)) player->pos.x -= PLAYER_HOR_SPD*delta; + if (IsKeyDown(KEY_RIGHT)) player->pos.x += PLAYER_HOR_SPD*delta; + if (IsKeyDown(KEY_SPACE) && player->canJump) { + player->vel = -PLAYER_JUMP_SPD; + player->canJump = 0; + } + + int hitObstacle = 0; + for (int i = 0; i < envItemsLength; i++) { + EnvItem *ei = envItems + i; + Vector2 *p = &(player->pos); + if (ei->blocking && + ei->rect.x <= p->x && + ei->rect.x + ei->rect.width >= p->x && + ei->rect.y >= p->y && + ei->rect.y < p->y + player->vel * delta) + { + hitObstacle = 1; + player->vel = 0.0f; + p->y = ei->rect.y; + } + } + if (!hitObstacle) { + player->pos.y += player->vel * delta; + player->vel += G * delta; + player->canJump = 0; + } else { + player->canJump = 1; + } +} + +void renderWorld(Player *player, EnvItem *envItems, int envItemsLength) { + for (int i = 0; i < envItemsLength; i++) { + DrawRectangleRec(envItems[i].rect, envItems[i].color); + } + Rectangle playerRect = { player->pos.x - 20, player->pos.y - 40, 40, 40 }; + DrawRectangleRec(playerRect, RED); +} + +int main(void) +{ + const int screenWidth = 800; + const int screenHeight = 450; + InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera"); + SetTargetFPS(60); + + Player player; + player.pos = (Vector2){ 400, 280 }; + player.vel = 0; + player.canJump = 0; + EnvItem envItems[] = { + {{ 0, 0, 1000, 400 }, 0, LIGHTGRAY }, + {{ 0, 400, 1000, 200 }, 1, GRAY }, + {{ 300, 200, 400, 10 }, 1, GRAY }, + {{ 250, 300, 100, 10 }, 1, GRAY }, + {{ 650, 300, 100, 10 }, 1, GRAY } + }; + int envItemsLength = sizeof(envItems) / sizeof (envItems[0]); + + Camera2D camera = { 0 }; + camera.target = player.pos; + camera.offset = (Vector2){ screenWidth/2, screenHeight/2 }; + camera.rotation = 0.0f; + camera.zoom = 1.0f; + + int cameraOption = 0; + void (*cameraUpdaters[])(float, Camera2D*, Player*, EnvItem*, int, int, int) = { + updateCameraCenter, + updateCameraCenterInsideMap, + updateCameraCenterSmoothFollow, + updateCameraEvenOutOnLanding, + updateCameraPlayerBoundsPush + }; + int cameraUpdatersLength = sizeof(cameraUpdaters) / sizeof(cameraUpdaters[0]); + char* cameraDescriptions[] = { + "Follow player center", + "Follow player center, but clamp to map edges", + "Follow player center; smoothed", + "Follow player center horizontally; updateplayer center vertically after landing", + "Player push camera on getting too close to screen edge" + }; + + while (!WindowShouldClose()) { + float delta = GetFrameTime(); + updatePlayer(delta, &player, envItems, envItemsLength); + + camera.zoom += ((float)GetMouseWheelMove()*0.05f); + if (camera.zoom > 3.0f) camera.zoom = 3.0f; + else if (camera.zoom < 0.25f) camera.zoom = 0.25f; + if (IsKeyPressed(KEY_R)) + { + camera.zoom = 1.0f; + } + + if (IsKeyPressed(KEY_C)) { + cameraOption = (cameraOption + 1) % cameraUpdatersLength; + } + cameraUpdaters[cameraOption](delta, &camera, &player, envItems, envItemsLength, screenWidth, screenHeight); + + BeginDrawing(); + ClearBackground(RAYWHITE); + + BeginMode2D(camera); + renderWorld(&player, envItems, envItemsLength); + EndMode2D(); + + DrawText("Controls:", 20, 20, 10, BLACK); + DrawText("- Right/Left to move", 40, 40, 10, DARKGRAY); + DrawText("- Space to jump", 40, 60, 10, DARKGRAY); + DrawText("- Mouse Wheel to Zoom in-out, R to reset zoom", 40, 80, 10, DARKGRAY); + DrawText("- C to change camera mode", 40, 100, 10, DARKGRAY); + DrawText("Current camera mode:", 20, 120, 10, BLACK); + DrawText(cameraDescriptions[cameraOption], 40, 140, 10, DARKGRAY); + EndDrawing(); + } + + CloseWindow(); // Close window and OpenGL context + + return 0; +} diff --git a/examples/core/resources/distortion100.fs b/examples/core/resources/distortion100.fs index 6bfe252b3..112cbcb5c 100644 --- a/examples/core/resources/distortion100.fs +++ b/examples/core/resources/distortion100.fs @@ -11,14 +11,14 @@ uniform sampler2D texture0; uniform vec4 colDiffuse; // NOTE: Add here your custom variables -uniform vec2 leftLensCenter = vec2(0.288, 0.5); -uniform vec2 rightLensCenter = vec2(0.712, 0.5); -uniform vec2 leftScreenCenter = vec2(0.25, 0.5); -uniform vec2 rightScreenCenter = vec2(0.75, 0.5); -uniform vec2 scale = vec2(0.25, 0.45); -uniform vec2 scaleIn = vec2(4, 2.2222); -uniform vec4 hmdWarpParam = vec4(1, 0.22, 0.24, 0); -uniform vec4 chromaAbParam = vec4(0.996, -0.004, 1.014, 0.0); +uniform vec2 leftLensCenter; +uniform vec2 rightLensCenter; +uniform vec2 leftScreenCenter; +uniform vec2 rightScreenCenter; +uniform vec2 scale; +uniform vec2 scaleIn; +uniform vec4 hmdWarpParam; +uniform vec4 chromaAbParam; void main() { diff --git a/examples/models/models_animation.c b/examples/models/models_animation.c index 5e7c8cf54..2aa321cf7 100644 --- a/examples/models/models_animation.c +++ b/examples/models/models_animation.c @@ -98,6 +98,8 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- + UnloadTexture(texture); // Unload texture + // Unload model animations data for (int i = 0; i < animsCount; i++) UnloadModelAnimation(anims[i]); RL_FREE(anims); diff --git a/examples/models/models_material_pbr.c b/examples/models/models_material_pbr.c index 8d51eefd2..0f896f21c 100644 --- a/examples/models/models_material_pbr.c +++ b/examples/models/models_material_pbr.c @@ -100,7 +100,8 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- - UnloadModel(model); // Unload skybox model + UnloadMaterial(model.materials[0]); // Unload material: shader and textures + UnloadModel(model); // Unload model CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_mesh_generation.c b/examples/models/models_mesh_generation.c index 6c0ae6530..eaecb2712 100644 --- a/examples/models/models_mesh_generation.c +++ b/examples/models/models_mesh_generation.c @@ -115,11 +115,12 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- + UnloadTexture(texture); // Unload texture // Unload models data (GPU VRAM) for (int i = 0; i < NUM_MODELS; i++) UnloadModel(models[i]); - CloseWindow(); // Close window and OpenGL context + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; diff --git a/examples/models/models_obj_viewer.c b/examples/models/models_obj_viewer.c index 3f43e1c89..1d15fdd9c 100644 --- a/examples/models/models_obj_viewer.c +++ b/examples/models/models_obj_viewer.c @@ -116,6 +116,7 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- + UnloadTexture(texture); // Unload texture UnloadModel(model); // Unload model ClearDroppedFiles(); // Clear internal buffers diff --git a/examples/models/models_skybox.c b/examples/models/models_skybox.c index bad29b96a..c2849032d 100644 --- a/examples/models/models_skybox.c +++ b/examples/models/models_skybox.c @@ -89,7 +89,10 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- - UnloadModel(skybox); // Unload skybox model (and textures) + UnloadShader(skybox.materials[0].shader); + UnloadTexture(skybox.materials[0].maps[MAP_CUBEMAP].texture); + + UnloadModel(skybox); // Unload skybox model CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_yaw_pitch_roll.c b/examples/models/models_yaw_pitch_roll.c index 72529d892..652738113 100644 --- a/examples/models/models_yaw_pitch_roll.c +++ b/examples/models/models_yaw_pitch_roll.c @@ -169,6 +169,7 @@ int main(void) //-------------------------------------------------------------------------------------- // Unload all loaded data + UnloadTexture(model.materials[0].maps[MAP_DIFFUSE].texture); UnloadModel(model); UnloadRenderTexture(framebuffer); diff --git a/examples/shaders/resources/shaders/glsl330/fog.fs b/examples/shaders/resources/shaders/glsl330/fog.fs new file mode 100644 index 000000000..57ed14807 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/fog.fs @@ -0,0 +1,99 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; +in vec3 fragPosition; +in vec3 fragNormal; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Output fragment color +out vec4 finalColor; + +// NOTE: Add here your custom variables + +#define MAX_LIGHTS 4 +#define LIGHT_DIRECTIONAL 0 +#define LIGHT_POINT 1 + +struct MaterialProperty { + vec3 color; + int useSampler; + sampler2D sampler; +}; + +struct Light { + int enabled; + int type; + vec3 position; + vec3 target; + vec4 color; +}; + +// Input lighting values +uniform Light lights[MAX_LIGHTS]; +uniform vec4 ambient; +uniform vec3 viewPos; +uniform float fogDensity; + +void main() +{ + // Texel color fetching from texture sampler + vec4 texelColor = texture(texture0, fragTexCoord); + vec3 lightDot = vec3(0.0); + vec3 normal = normalize(fragNormal); + vec3 viewD = normalize(viewPos - fragPosition); + vec3 specular = vec3(0.0); + + // NOTE: Implement here your fragment shader code + + for (int i = 0; i < MAX_LIGHTS; i++) + { + if (lights[i].enabled == 1) + { + vec3 light = vec3(0.0); + if (lights[i].type == LIGHT_DIRECTIONAL) { + light = -normalize(lights[i].target - lights[i].position); + } + if (lights[i].type == LIGHT_POINT) { + light = normalize(lights[i].position - fragPosition); + } + float NdotL = max(dot(normal, light), 0.0); + lightDot += lights[i].color.rgb * NdotL; + + float specCo = 0.0; + if(NdotL > 0.0) + specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16);//16 =shine + specular += specCo; + + } + } + + finalColor = (texelColor * ((colDiffuse+vec4(specular,1)) * vec4(lightDot, 1.0))); + finalColor += texelColor * (ambient/10.0); + + // Gamma correction + finalColor = pow(finalColor, vec4(1.0/2.2)); + + // Fog calculation + float dist = length(viewPos - fragPosition); + + // these could be parameters... + const vec4 fogColor = vec4(0.5, 0.5, 0.5, 1.0); + //const float fogDensity = 0.16; + + // Exponential fog + float fogFactor = 1.0/exp((dist*fogDensity)*(dist*fogDensity)); + + // Linear fog (less nice) + //const float fogStart = 2.0; + //const float fogEnd = 10.0; + //float fogFactor = (fogEnd - dist)/(fogEnd - fogStart); + + fogFactor = clamp(fogFactor, 0.0, 1.0); + + finalColor = mix(fogColor, finalColor, fogFactor); +} diff --git a/examples/shaders/resources/shaders/glsl330/fog.vs b/examples/shaders/resources/shaders/glsl330/fog.vs new file mode 100644 index 000000000..00779cfa3 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/fog.vs @@ -0,0 +1,32 @@ +#version 330 + +// Input vertex attributes +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec3 vertexNormal; +in vec4 vertexColor; + +// Input uniform values +uniform mat4 mvp; +uniform mat4 matModel; + +// Output vertex attributes (to fragment shader) +out vec2 fragTexCoord; +out vec4 fragColor; +out vec3 fragPosition; +out vec3 fragNormal; + +// NOTE: Add here your custom variables + +void main() +{ + // Send vertex attributes to fragment shader + fragTexCoord = vertexTexCoord; + fragColor = vertexColor; + fragPosition = vec3(matModel*vec4(vertexPosition, 1.0f)); + mat3 normalMatrix = transpose(inverse(mat3(matModel))); + fragNormal = normalize(normalMatrix*vertexNormal); + + // Calculate final vertex position + gl_Position = mvp*vec4(vertexPosition, 1.0); +} diff --git a/examples/shaders/shaders_fog.c b/examples/shaders/shaders_fog.c new file mode 100644 index 000000000..e8f2691d2 --- /dev/null +++ b/examples/shaders/shaders_fog.c @@ -0,0 +1,153 @@ +/******************************************************************************************* +* +* raylib [shaders] example - fog +* +* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support, +* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version. +* +* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3). +* +* This example has been created using raylib 2.5 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Example contributed by Chris Camacho (@codifies) and reviewed by Ramon Santamaria (@raysan5) +* +* Chris Camacho (@codifies - http://bedroomcoders.co.uk/) notes: +* +* This is based on the PBR lighting example, but greatly simplified to aid learning... +* actually there is very little of the PBR example left! +* When I first looked at the bewildering complexity of the PBR example I feared +* I would never understand how I could do simple lighting with raylib however its +* a testement to the authors of raylib (including rlights.h) that the example +* came together fairly quickly. +* +* Copyright (c) 2019 Chris Camacho (@codifies) and Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include "raymath.h" + +#define RLIGHTS_IMPLEMENTATION +#include "rlights.h" + +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + SetConfigFlags(FLAG_MSAA_4X_HINT); // Enable Multi Sampling Anti Aliasing 4x (if available) + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - fog"); + + // Define the camera to look into our 3d world + Camera camera = { + (Vector3){ 2.0f, 2.0f, 6.0f }, // position + (Vector3){ 0.0f, 0.5f, 0.0f }, // target + (Vector3){ 0.0f, 1.0f, 0.0f }, // up + 45.0f, CAMERA_PERSPECTIVE }; // fov, type + + // Load models and texture + Model modelA = LoadModelFromMesh(GenMeshTorus(0.4f, 1.0f, 16, 32)); + Model modelB = LoadModelFromMesh(GenMeshCube(1.0f, 1.0f, 1.0f)); + Model modelC = LoadModelFromMesh(GenMeshSphere(0.5f, 32, 32)); + Texture texture = LoadTexture("resources/texel_checker.png"); + + // Assign texture to default model material + modelA.materials[0].maps[MAP_DIFFUSE].texture = texture; + modelB.materials[0].maps[MAP_DIFFUSE].texture = texture; + modelC.materials[0].maps[MAP_DIFFUSE].texture = texture; + + // Load shader and set up some uniforms + Shader shader = LoadShader("resources/shaders/glsl330/fog.vs", "resources/shaders/glsl330/fog.fs"); + shader.locs[LOC_MATRIX_MODEL] = GetShaderLocation(shader, "matModel"); + shader.locs[LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos"); + + // Ambient light level + int ambientLoc = GetShaderLocation(shader, "ambient"); + SetShaderValue(shader, ambientLoc, (float[4]){ 0.2f, 0.2f, 0.2f, 1.0f }, UNIFORM_VEC4); + + float fogDensity = 0.15f; + int fogDensityLoc = GetShaderLocation(shader, "fogDensity"); + SetShaderValue(shader, fogDensityLoc, &fogDensity, UNIFORM_FLOAT); + + // NOTE: All models share the same shader + modelA.materials[0].shader = shader; + modelB.materials[0].shader = shader; + modelC.materials[0].shader = shader; + + // Using just 1 point lights + CreateLight(LIGHT_POINT, (Vector3){ 0, 2, 6 }, Vector3Zero(), WHITE, shader); + + SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera); // Update camera + + if (IsKeyDown(KEY_UP)) + { + fogDensity += 0.001; + if (fogDensity > 1.0) fogDensity = 1.0; + } + + if (IsKeyDown(KEY_DOWN)) + { + fogDensity -= 0.001; + if (fogDensity < 0.0) fogDensity = 0.0; + } + + SetShaderValue(shader, fogDensityLoc, &fogDensity, UNIFORM_FLOAT); + + // Rotate the torus + modelA.transform = MatrixMultiply(modelA.transform, MatrixRotateX(-0.025)); + modelA.transform = MatrixMultiply(modelA.transform, MatrixRotateZ(0.012)); + + // Update the light shader with the camera view position + SetShaderValue(shader, shader.locs[LOC_VECTOR_VIEW], &camera.position.x, UNIFORM_VEC3); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(GRAY); + + BeginMode3D(camera); + + // Draw the three models + DrawModel(modelA, Vector3Zero(), 1.0f, WHITE); + DrawModel(modelB, (Vector3){ -2.6, 0, 0 }, 1.0f, WHITE); + DrawModel(modelC, (Vector3){ 2.6, 0, 0 }, 1.0f, WHITE); + + for (int i = -20; i < 20; i += 2) DrawModel(modelA,(Vector3){ i, 0, 2 }, 1.0f, WHITE); + + EndMode3D(); + + DrawText(TextFormat("Use KEY_UP/KEY_DOWN to change fog density [%.2f]", fogDensity), 10, 10, 20, RAYWHITE); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadModel(modelA); // Unload the model A + UnloadModel(modelB); // Unload the model B + UnloadModel(modelC); // Unload the model C + UnloadTexture(texture); // Unload the texture + UnloadShader(shader); // Unload shader + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/shaders/shaders_fog.png b/examples/shaders/shaders_fog.png new file mode 100644 index 000000000..52008e8a1 Binary files /dev/null and b/examples/shaders/shaders_fog.png differ diff --git a/examples/textures/textures_bunnymark.c b/examples/textures/textures_bunnymark.c index 784417d21..86605b901 100644 --- a/examples/textures/textures_bunnymark.c +++ b/examples/textures/textures_bunnymark.c @@ -13,7 +13,7 @@ #include // Required for: malloc(), free() -#define MAX_BUNNIES 100000 // 100K bunnies limit +#define MAX_BUNNIES 50000 // 50K bunnies limit // This is the maximum amount of elements (quads) per batch // NOTE: This value is defined in [rlgl] module and can be changed there diff --git a/projects/README.md b/projects/README.md index 4009a09b9..2f0e0f3d1 100644 --- a/projects/README.md +++ b/projects/README.md @@ -4,14 +4,17 @@ This folder contains raylib templates for some common IDEs. IDE | Platform | Template type | State ----| ---------| ------------- | ----- +[4coder](http://4coder.net/) | Windows | example compiling | DONE [Builder](https://wiki.gnome.org/Apps/Builder) | Linux | example compiling | DONE [CMake](https://cmake.org/) | n/a | example compiling and raylib source downloading/building if necessary | DONE [CodeBlocks](http://www.codeblocks.org/) | Linux, Windows | example compiling | DONE -[Geany](https://www.geany.org/) | Linux, Windows | - | INCOMPLETE +[Geany](https://www.geany.org/) | Linux, Windows | - | DONE [KDevelop](https://www.kdevelop.org/) | Linux, Windows, macOS | - | INCOMPLETE [Notepad++](https://notepad-plus-plus.org/) | Windows | source/example compiling | DONE +[Sublime Text](https://www.sublimetext.com/) | Windows, Linux, macOS | source and example | DONE [VS2015](https://www.visualstudio.com) | Windows | source/example compiling | DONE [VS2017](https://www.visualstudio.com) | Windows | source/example compiling | DONE [VSCode](https://code.visualstudio.com/) | Windows, macOS | example compiling | DONE +scripts | Windows, Linux, macOS | source and example | DONE *New IDEs config files are welcome!* diff --git a/src/config.h b/src/config.h index 050cce183..398b5e9ad 100644 --- a/src/config.h +++ b/src/config.h @@ -44,6 +44,8 @@ #define SUPPORT_MOUSE_GESTURES 1 // Reconfigure standard input to receive key inputs, works with SSH connection. #define SUPPORT_SSH_KEYBOARD_RPI 1 +// Draw a mouse reference on screen (square cursor box) +#define SUPPORT_MOUSE_CURSOR_RPI 1 // Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used //#define SUPPORT_BUSY_WAIT_LOOP 1 // Wait for events passively (sleeping while no events) instead of polling them actively every frame diff --git a/src/core.c b/src/core.c index ac0ddd294..9e26a6399 100644 --- a/src/core.c +++ b/src/core.c @@ -55,6 +55,9 @@ * WARNING: Reconfiguring standard input could lead to undesired effects, like breaking other running processes or * blocking the device is not restored properly. Use with care. * +* #define SUPPORT_MOUSE_CURSOR_RPI (Raspberry Pi only) +* Draw a mouse reference on screen (square cursor box) +* * #define SUPPORT_BUSY_WAIT_LOOP * Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used * @@ -105,7 +108,7 @@ #if !defined(EXTERNAL_CONFIG_FLAGS) #include "config.h" // Defines module configuration flags #else - #define RAYLIB_VERSION "2.5" + #define RAYLIB_VERSION "2.6-dev" #endif #if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_C_SOURCE < 199309L @@ -423,7 +426,6 @@ static double targetTime = 0.0; // Desired time for one frame, if 0 // Config internal variables //----------------------------------------------------------------------------------- static unsigned int configFlags = 0; // Configuration flags (bit based) -static bool showLogo = false; // Track if showing logo at init is enabled static char **dropFilesPath; // Store dropped files paths as strings static int dropFilesCount = 0; // Count dropped files strings @@ -466,8 +468,6 @@ static int GetGamepadButton(int button); // Get gamepad button ge static int GetGamepadAxis(int axis); // Get gamepad axis generic to all platforms static void PollInputEvents(void); // Register user events -static void LogoAnimation(void); // Plays raylib logo appearing animation - #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed @@ -697,13 +697,6 @@ void InitWindow(int width, int height, const char *title) mousePosition.x = (float)screenWidth/2.0f; mousePosition.y = (float)screenHeight/2.0f; - - // raylib logo appearing animation (if enabled) - if (showLogo) - { - SetTargetFPS(60); - LogoAnimation(); - } #endif // PLATFORM_ANDROID } @@ -1187,6 +1180,12 @@ void BeginDrawing(void) // End canvas drawing and swap buffers (double buffering) void EndDrawing(void) { +#if defined(PLATFORM_RPI) && defined(SUPPORT_MOUSE_CURSOR_RPI) + // On RPI native mode we have no system mouse cursor, so, + // we draw a small rectangle for user reference + DrawRectangle(mousePosition.x, mousePosition.y, 3, 3, MAROON); +#endif + rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) #if defined(SUPPORT_GIF_RECORDING) @@ -1249,17 +1248,12 @@ void BeginMode2D(Camera2D camera) rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) rlLoadIdentity(); // Reset current matrix (MODELVIEW) - rlMultMatrixf(MatrixToFloat(screenScaling)); // Apply screen scaling if required - - // Camera rotation and scaling is always relative to target - Matrix matOrigin = MatrixTranslate(-camera.target.x, -camera.target.y, 0.0f); - Matrix matRotation = MatrixRotate((Vector3){ 0.0f, 0.0f, 1.0f }, camera.rotation*DEG2RAD); - Matrix matScale = MatrixScale(camera.zoom, camera.zoom, 1.0f); - Matrix matTranslation = MatrixTranslate(camera.offset.x + camera.target.x, camera.offset.y + camera.target.y, 0.0f); - - Matrix matTransform = MatrixMultiply(MatrixMultiply(matOrigin, MatrixMultiply(matScale, matRotation)), matTranslation); - - rlMultMatrixf(MatrixToFloat(matTransform)); // Apply transformation to modelview + + // Apply screen scaling if required + rlMultMatrixf(MatrixToFloat(screenScaling)); + + // Apply 2d camera transformation to modelview + rlMultMatrixf(MatrixToFloat(GetCameraMatrix2D(camera))); } // Ends 2D mode with custom camera @@ -1370,6 +1364,23 @@ void EndTextureMode(void) currentHeight = GetScreenHeight(); } +// Begin scissor mode (define screen area for following drawing) +// NOTE: Scissor rec refers to bottom-left corner, we change it to upper-left +void BeginScissorMode(int x, int y, int width, int height) +{ + rlglDraw(); // Force drawing elements + + rlEnableScissorTest(); + rlScissor(x, GetScreenHeight() - (y + height), width, height); +} + +// End scissor mode +void EndScissorMode(void) +{ + rlglDraw(); // Force drawing elements + rlDisableScissorTest(); +} + // Returns a ray trace from mouse position Ray GetMouseRay(Vector2 mousePosition, Camera camera) { @@ -1425,6 +1436,40 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) return ray; } +// Get transform matrix for camera +Matrix GetCameraMatrix(Camera camera) +{ + return MatrixLookAt(camera.position, camera.target, camera.up); +} + +// Returns camera 2d transform matrix +Matrix GetCameraMatrix2D(Camera2D camera) +{ + Matrix matTransform = { 0 }; + // The camera in world-space is set by + // 1. Move it to target + // 2. Rotate by -rotation and scale by (1/zoom) + // 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. + // 3. Move it by (-offset); + // Offset defines target transform relative to screen, but since we're effectively "moving" screen (camera) + // we need to do it into opposite direction (inverse transform) + + // Having camera transform in world-space, inverse of it gives the modelview transform. + // Since (A*B*C)' = C'*B'*A', the modelview is + // 1. Move to offset + // 2. Rotate and Scale + // 3. Move by -target + Matrix matOrigin = MatrixTranslate(-camera.target.x, -camera.target.y, 0.0f); + Matrix matRotation = MatrixRotate((Vector3){ 0.0f, 0.0f, 1.0f }, camera.rotation*DEG2RAD); + Matrix matScale = MatrixScale(camera.zoom, camera.zoom, 1.0f); + Matrix matTranslation = MatrixTranslate(camera.offset.x, camera.offset.y, 0.0f); + + matTransform = MatrixMultiply(MatrixMultiply(matOrigin, MatrixMultiply(matScale, matRotation)), matTranslation); + + return matTransform; +} + // Returns the screen space position from a 3d world space position Vector2 GetWorldToScreen(Vector3 position, Camera camera) { @@ -1467,10 +1512,22 @@ Vector2 GetWorldToScreen(Vector3 position, Camera camera) return screenPosition; } -// Get transform matrix for camera -Matrix GetCameraMatrix(Camera camera) +// Returns the screen space position for a 2d camera world space position +Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera) { - return MatrixLookAt(camera.position, camera.target, camera.up); + Matrix matCamera = GetCameraMatrix2D(camera); + Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, matCamera); + + return (Vector2){ transform.x, transform.y }; +} + +// Returns the world space position for a 2d camera screen space position +Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera) +{ + Matrix invMatCamera = MatrixInvert(GetCameraMatrix2D(camera)); + Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, invMatCamera); + + return (Vector2){ transform.x, transform.y }; } // Set target FPS (maximum) @@ -1664,7 +1721,6 @@ void SetConfigFlags(unsigned int flags) { configFlags = flags; - if (configFlags & FLAG_SHOW_LOGO) showLogo = true; if (configFlags & FLAG_FULLSCREEN_MODE) fullscreen = true; if (configFlags & FLAG_WINDOW_ALWAYS_RUN) alwaysRun = true; } @@ -1789,10 +1845,10 @@ const char *GetFileName(const char *filePath) return fileName + 1; } -// Get filename string without extension (memory should be freed) +// Get filename string without extension (uses static string) const char *GetFileNameWithoutExt(const char *filePath) { - #define MAX_FILENAMEWITHOUTEXT_LENGTH 64 + #define MAX_FILENAMEWITHOUTEXT_LENGTH 128 static char fileName[MAX_FILENAMEWITHOUTEXT_LENGTH]; memset(fileName, 0, MAX_FILENAMEWITHOUTEXT_LENGTH); @@ -2494,9 +2550,6 @@ static bool InitGraphicsDevice(int width, int height) if (screenHeight <= 0) screenHeight = displayHeight; #endif // PLATFORM_DESKTOP - currentWidth = screenWidth; - currentHeight = screenHeight; - #if defined(PLATFORM_WEB) displayWidth = screenWidth; displayHeight = screenHeight; @@ -3027,6 +3080,9 @@ static bool InitGraphicsDevice(int width, int height) // Setup default viewport SetupViewport(fbWidth, fbHeight); + currentWidth = screenWidth; + currentHeight = screenHeight; + ClearBackground(RAYWHITE); // Default background color for raylib games :P #if defined(PLATFORM_ANDROID) @@ -3935,13 +3991,6 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) } } */ - - // raylib logo appearing animation (if enabled) - if (showLogo) - { - SetTargetFPS(60); // Not required on Android - LogoAnimation(); - } } } } break; @@ -4272,8 +4321,8 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state", gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping); - for(int i = 0; i < gamepadEvent->numAxes; ++i) TraceLog(LOG_DEBUG, "Axis %d: %g", i, gamepadEvent->axis[i]); - for(int i = 0; i < gamepadEvent->numButtons; ++i) TraceLog(LOG_DEBUG, "Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]); + for (int i = 0; i < gamepadEvent->numAxes; ++i) TraceLog(LOG_DEBUG, "Axis %d: %g", i, gamepadEvent->axis[i]); + for (int i = 0; i < gamepadEvent->numButtons; ++i) TraceLog(LOG_DEBUG, "Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]); */ if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS)) gamepadReady[gamepadEvent->index] = true; @@ -4989,117 +5038,3 @@ static void *GamepadThread(void *arg) return NULL; } #endif // PLATFORM_RPI - -// Plays raylib logo appearing animation -static void LogoAnimation(void) -{ -#if !defined(PLATFORM_WEB) && !defined(PLATFORM_UWP) - int logoPositionX = screenWidth/2 - 128; - int logoPositionY = screenHeight/2 - 128; - - int framesCounter = 0; - int lettersCount = 0; - - int topSideRecWidth = 16; - int leftSideRecHeight = 16; - - int bottomSideRecWidth = 16; - int rightSideRecHeight = 16; - - int state = 0; // Tracking animation states (State Machine) - float alpha = 1.0f; // Useful for fading - - while (!WindowShouldClose() && (state != 4)) // Detect window close button or ESC key - { - // Update - //---------------------------------------------------------------------------------- - if (state == 0) // State 0: Small box blinking - { - framesCounter++; - - if (framesCounter == 84) - { - state = 1; - framesCounter = 0; // Reset counter... will be used later... - } - } - else if (state == 1) // State 1: Top and left bars growing - { - topSideRecWidth += 4; - leftSideRecHeight += 4; - - if (topSideRecWidth == 256) state = 2; - } - else if (state == 2) // State 2: Bottom and right bars growing - { - bottomSideRecWidth += 4; - rightSideRecHeight += 4; - - if (bottomSideRecWidth == 256) state = 3; - } - else if (state == 3) // State 3: Letters appearing (one by one) - { - framesCounter++; - - if (framesCounter/12) // Every 12 frames, one more letter! - { - lettersCount++; - framesCounter = 0; - } - - if (lettersCount >= 10) // When all letters have appeared, just fade out everything - { - alpha -= 0.02f; - - if (alpha <= 0.0f) - { - alpha = 0.0f; - state = 4; - } - } - } - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - if (state == 0) - { - if ((framesCounter/12)%2) DrawRectangle(logoPositionX, logoPositionY, 16, 16, BLACK); - } - else if (state == 1) - { - DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK); - DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK); - } - else if (state == 2) - { - DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK); - DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK); - - DrawRectangle(logoPositionX + 240, logoPositionY, 16, rightSideRecHeight, BLACK); - DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, BLACK); - } - else if (state == 3) - { - DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, Fade(BLACK, alpha)); - DrawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, Fade(BLACK, alpha)); - - DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, Fade(BLACK, alpha)); - DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, Fade(BLACK, alpha)); - - DrawRectangle(screenWidth/2 - 112, screenHeight/2 - 112, 224, 224, Fade(RAYWHITE, alpha)); - - DrawText(TextSubtext("raylib", 0, lettersCount), screenWidth/2 - 44, screenHeight/2 + 48, 50, Fade(BLACK, alpha)); - } - - EndDrawing(); - //---------------------------------------------------------------------------------- - } -#endif - - showLogo = false; // Prevent for repeating when reloading window (Android) -} diff --git a/src/external/miniaudio.h b/src/external/miniaudio.h index 528ff5746..7eb4beeeb 100644 --- a/src/external/miniaudio.h +++ b/src/external/miniaudio.h @@ -1,6 +1,6 @@ /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio (formerly mini_al) - v0.9.6 - 2019-xx-xx +miniaudio (formerly mini_al) - v0.9.6 - 2019-08-04 David Reid - davidreidsoftware@gmail.com @@ -33361,7 +33361,7 @@ Device /* REVISION HISTORY ================ -v0.9.6 - 2019-xx-xx +v0.9.6 - 2019-08-04 - Add support for loading decoders using a wchar_t string for file paths. - Don't trigger an assert when ma_device_start() is called on a device that is already started. This will now log a warning and return MA_INVALID_OPERATION. The same applies for ma_device_stop(). diff --git a/src/models.c b/src/models.c index 5dce17678..b3a50f403 100644 --- a/src/models.c +++ b/src/models.c @@ -686,14 +686,14 @@ Model LoadModelFromMesh(Mesh mesh) model.transform = MatrixIdentity(); model.meshCount = 1; - model.meshes = (Mesh *)RL_MALLOC(model.meshCount*sizeof(Mesh)); + model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); model.meshes[0] = mesh; model.materialCount = 1; - model.materials = (Material *)RL_MALLOC(model.materialCount*sizeof(Material)); + model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); model.materials[0] = LoadMaterialDefault(); - model.meshMaterial = (int *)RL_MALLOC(model.meshCount*sizeof(int)); + model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); model.meshMaterial[0] = 0; // First material index return model; @@ -829,7 +829,7 @@ Material *LoadMaterials(const char *fileName, int *materialCount) Material LoadMaterialDefault(void) { Material material = { 0 }; - material.maps = (MaterialMap *)RL_CALLOC(MAX_MATERIAL_MAPS*sizeof(MaterialMap), 1); + material.maps = (MaterialMap *)RL_CALLOC(MAX_MATERIAL_MAPS, sizeof(MaterialMap)); material.shader = GetShaderDefault(); material.maps[MAP_DIFFUSE].texture = GetTextureDefault(); // White texture (1x1 pixel) @@ -919,7 +919,7 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) TraceLog(LOG_ERROR, "[%s] Unable to open file", filename); } - // header + // Read IQM header fread(&iqm, sizeof(IQMHeader), 1, iqmFile); if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC))) @@ -934,34 +934,30 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) fclose(iqmFile); } - // bones - IQMPose *poses; - poses = RL_MALLOC(sizeof(IQMPose)*iqm.num_poses); + // Get bones data + IQMPose *poses = RL_MALLOC(iqm.num_poses*sizeof(IQMPose)); fseek(iqmFile, iqm.ofs_poses, SEEK_SET); - fread(poses, sizeof(IQMPose)*iqm.num_poses, 1, iqmFile); + fread(poses, iqm.num_poses*sizeof(IQMPose), 1, iqmFile); - // animations + // Get animations data *animCount = iqm.num_anims; IQMAnim *anim = RL_MALLOC(iqm.num_anims*sizeof(IQMAnim)); fseek(iqmFile, iqm.ofs_anims, SEEK_SET); fread(anim, iqm.num_anims*sizeof(IQMAnim), 1, iqmFile); ModelAnimation *animations = RL_MALLOC(iqm.num_anims*sizeof(ModelAnimation)); - // frameposes - unsigned short *framedata = RL_MALLOC(sizeof(unsigned short)*iqm.num_frames*iqm.num_framechannels); + unsigned short *framedata = RL_MALLOC(iqm.num_frames*iqm.num_framechannels*sizeof(unsigned short)); fseek(iqmFile, iqm.ofs_frames, SEEK_SET); - fread(framedata, sizeof(unsigned short)*iqm.num_frames*iqm.num_framechannels, 1, iqmFile); + fread(framedata, iqm.num_frames*iqm.num_framechannels*sizeof(unsigned short), 1, iqmFile); - for(int a=0;a= anim.frameCount) frame = frame%anim.frameCount; - - for (int m = 0; m < model.meshCount; m++) + if ((anim.frameCount > 0) && (anim.bones != NULL) && (anim.framePoses != NULL)) { - Vector3 animVertex = { 0 }; - Vector3 animNormal = { 0 }; + if (frame >= anim.frameCount) frame = frame%anim.frameCount; - Vector3 inTranslation = { 0 }; - Quaternion inRotation = { 0 }; - Vector3 inScale = { 0 }; - - Vector3 outTranslation = { 0 }; - Quaternion outRotation = { 0 }; - Vector3 outScale = { 0 }; - - int vCounter = 0; - int boneCounter = 0; - int boneId = 0; - - for (int i = 0; i < model.meshes[m].vertexCount; i++) + for (int m = 0; m < model.meshCount; m++) { - boneId = model.meshes[m].boneIds[boneCounter]; - inTranslation = model.bindPose[boneId].translation; - inRotation = model.bindPose[boneId].rotation; - inScale = model.bindPose[boneId].scale; - outTranslation = anim.framePoses[frame][boneId].translation; - outRotation = anim.framePoses[frame][boneId].rotation; - outScale = anim.framePoses[frame][boneId].scale; + Vector3 animVertex = { 0 }; + Vector3 animNormal = { 0 }; - // Vertices processing - // NOTE: We use meshes.vertices (default vertex position) to calculate meshes.animVertices (animated vertex position) - animVertex = (Vector3){ model.meshes[m].vertices[vCounter], model.meshes[m].vertices[vCounter + 1], model.meshes[m].vertices[vCounter + 2] }; - animVertex = Vector3MultiplyV(animVertex, outScale); - animVertex = Vector3Subtract(animVertex, inTranslation); - animVertex = Vector3RotateByQuaternion(animVertex, QuaternionMultiply(outRotation, QuaternionInvert(inRotation))); - animVertex = Vector3Add(animVertex, outTranslation); - model.meshes[m].animVertices[vCounter] = animVertex.x; - model.meshes[m].animVertices[vCounter + 1] = animVertex.y; - model.meshes[m].animVertices[vCounter + 2] = animVertex.z; + Vector3 inTranslation = { 0 }; + Quaternion inRotation = { 0 }; + Vector3 inScale = { 0 }; - // Normals processing - // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals) - animNormal = (Vector3){ model.meshes[m].normals[vCounter], model.meshes[m].normals[vCounter + 1], model.meshes[m].normals[vCounter + 2] }; - animNormal = Vector3RotateByQuaternion(animNormal, QuaternionMultiply(outRotation, QuaternionInvert(inRotation))); - model.meshes[m].animNormals[vCounter] = animNormal.x; - model.meshes[m].animNormals[vCounter + 1] = animNormal.y; - model.meshes[m].animNormals[vCounter + 2] = animNormal.z; - vCounter += 3; + Vector3 outTranslation = { 0 }; + Quaternion outRotation = { 0 }; + Vector3 outScale = { 0 }; - boneCounter += 4; + int vCounter = 0; + int boneCounter = 0; + int boneId = 0; + + for (int i = 0; i < model.meshes[m].vertexCount; i++) + { + boneId = model.meshes[m].boneIds[boneCounter]; + inTranslation = model.bindPose[boneId].translation; + inRotation = model.bindPose[boneId].rotation; + inScale = model.bindPose[boneId].scale; + outTranslation = anim.framePoses[frame][boneId].translation; + outRotation = anim.framePoses[frame][boneId].rotation; + outScale = anim.framePoses[frame][boneId].scale; + + // Vertices processing + // NOTE: We use meshes.vertices (default vertex position) to calculate meshes.animVertices (animated vertex position) + animVertex = (Vector3){ model.meshes[m].vertices[vCounter], model.meshes[m].vertices[vCounter + 1], model.meshes[m].vertices[vCounter + 2] }; + animVertex = Vector3MultiplyV(animVertex, outScale); + animVertex = Vector3Subtract(animVertex, inTranslation); + animVertex = Vector3RotateByQuaternion(animVertex, QuaternionMultiply(outRotation, QuaternionInvert(inRotation))); + animVertex = Vector3Add(animVertex, outTranslation); + model.meshes[m].animVertices[vCounter] = animVertex.x; + model.meshes[m].animVertices[vCounter + 1] = animVertex.y; + model.meshes[m].animVertices[vCounter + 2] = animVertex.z; + + // Normals processing + // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals) + animNormal = (Vector3){ model.meshes[m].normals[vCounter], model.meshes[m].normals[vCounter + 1], model.meshes[m].normals[vCounter + 2] }; + animNormal = Vector3RotateByQuaternion(animNormal, QuaternionMultiply(outRotation, QuaternionInvert(inRotation))); + model.meshes[m].animNormals[vCounter] = animNormal.x; + model.meshes[m].animNormals[vCounter + 1] = animNormal.y; + model.meshes[m].animNormals[vCounter + 2] = animNormal.z; + vCounter += 3; + + boneCounter += 4; + } + + // Upload new vertex data to GPU for model drawing + rlUpdateBuffer(model.meshes[m].vboId[0], model.meshes[m].animVertices, model.meshes[m].vertexCount*3*sizeof(float)); // Update vertex position + rlUpdateBuffer(model.meshes[m].vboId[2], model.meshes[m].animVertices, model.meshes[m].vertexCount*3*sizeof(float)); // Update vertex normals } - - // Upload new vertex data to GPU for model drawing - rlUpdateBuffer(model.meshes[m].vboId[0], model.meshes[m].animVertices, model.meshes[m].vertexCount*3*sizeof(float)); // Update vertex position - rlUpdateBuffer(model.meshes[m].vboId[2], model.meshes[m].animVertices, model.meshes[m].vertexCount*3*sizeof(float)); // Update vertex normals } } @@ -1181,7 +1179,7 @@ bool IsModelAnimationValid(Model model, ModelAnimation anim) Mesh GenMeshPoly(int sides, float radius) { Mesh mesh = { 0 }; - mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO*sizeof(unsigned int), 1); + mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); int vertexCount = sides*3; // Vertices definition @@ -1244,7 +1242,7 @@ Mesh GenMeshPoly(int sides, float radius) Mesh GenMeshPlane(float width, float length, int resX, int resZ) { Mesh mesh = { 0 }; - mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO*sizeof(unsigned int), 1); + mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); #define CUSTOM_MESH_GEN_PLANE #if defined(CUSTOM_MESH_GEN_PLANE) @@ -1347,7 +1345,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) mesh.vertices = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float)); mesh.texcoords = (float *)RL_MALLOC(plane->ntriangles*3*2*sizeof(float)); mesh.normals = (float *)RL_MALLOC(plane->ntriangles*3*3*sizeof(float)); - mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO*sizeof(unsigned int)); + mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); mesh.vertexCount = plane->ntriangles*3; mesh.triangleCount = plane->ntriangles; @@ -1379,7 +1377,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ) Mesh GenMeshCube(float width, float height, float length) { Mesh mesh = { 0 }; - mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO*sizeof(unsigned int), 1); + mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); #define CUSTOM_MESH_GEN_CUBE #if defined(CUSTOM_MESH_GEN_CUBE) @@ -1545,7 +1543,7 @@ par_shapes_mesh* par_shapes_create_icosahedron(); // 20 sides polyhedron RLAPI Mesh GenMeshSphere(float radius, int rings, int slices) { Mesh mesh = { 0 }; - mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO*sizeof(unsigned int), 1); + mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); par_shapes_mesh *sphere = par_shapes_create_parametric_sphere(slices, rings); par_shapes_scale(sphere, radius, radius, radius); @@ -1584,7 +1582,7 @@ RLAPI Mesh GenMeshSphere(float radius, int rings, int slices) RLAPI Mesh GenMeshHemiSphere(float radius, int rings, int slices) { Mesh mesh = { 0 }; - mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO*sizeof(unsigned int), 1); + mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); par_shapes_mesh *sphere = par_shapes_create_hemisphere(slices, rings); par_shapes_scale(sphere, radius, radius, radius); @@ -1623,7 +1621,7 @@ RLAPI Mesh GenMeshHemiSphere(float radius, int rings, int slices) Mesh GenMeshCylinder(float radius, float height, int slices) { Mesh mesh = { 0 }; - mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO*sizeof(unsigned int), 1); + mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); // Instance a cylinder that sits on the Z=0 plane using the given tessellation // levels across the UV domain. Think of "slices" like a number of pizza @@ -1682,7 +1680,7 @@ Mesh GenMeshCylinder(float radius, float height, int slices) Mesh GenMeshTorus(float radius, float size, int radSeg, int sides) { Mesh mesh = { 0 }; - mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO*sizeof(unsigned int), 1); + mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); if (radius > 1.0f) radius = 1.0f; else if (radius < 0.1f) radius = 0.1f; @@ -1725,7 +1723,7 @@ Mesh GenMeshTorus(float radius, float size, int radSeg, int sides) Mesh GenMeshKnot(float radius, float size, int radSeg, int sides) { Mesh mesh = { 0 }; - mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO*sizeof(unsigned int), 1); + mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); if (radius > 3.0f) radius = 3.0f; else if (radius < 0.5f) radius = 0.5f; @@ -1769,6 +1767,7 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size) #define GRAY_VALUE(c) ((c.r+c.g+c.b)/3) Mesh mesh = { 0 }; + mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); int mapX = heightmap.width; int mapZ = heightmap.height; @@ -1877,7 +1876,7 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size) Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) { Mesh mesh = { 0 }; - mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO*sizeof(unsigned int), 1); + mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); Color *cubicmapPixels = GetImageData(cubicmap); @@ -2791,11 +2790,15 @@ static Model LoadOBJ(const char *fileName) // TODO: Support multiple meshes... in the meantime, only one mesh is returned //model.meshCount = meshCount; model.meshCount = 1; - model.meshes = (Mesh *)RL_MALLOC(model.meshCount*sizeof(Mesh)); + model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); // Init model materials array - model.materialCount = materialCount; - model.materials = (Material *)RL_MALLOC(model.materialCount*sizeof(Material)); + if (materialCount > 0) + { + model.materialCount = materialCount; + model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); + } + model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); /* @@ -2815,10 +2818,10 @@ static Model LoadOBJ(const char *fileName) memset(&mesh, 0, sizeof(Mesh)); mesh.vertexCount = attrib.num_faces*3; mesh.triangleCount = attrib.num_faces; - mesh.vertices = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); - mesh.texcoords = (float *)RL_MALLOC(mesh.vertexCount*2*sizeof(float)); - mesh.normals = (float *)RL_MALLOC(mesh.vertexCount*3*sizeof(float)); - mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO*sizeof(unsigned int), 1); + mesh.vertices = (float *)RL_CALLOC(mesh.vertexCount*3, sizeof(float)); + mesh.texcoords = (float *)RL_CALLOC(mesh.vertexCount*2, sizeof(float)); + mesh.normals = (float *)RL_CALLOC(mesh.vertexCount*3, sizeof(float)); + mesh.vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); int vCount = 0; int vtCount = 0; @@ -3065,36 +3068,36 @@ static Model LoadIQM(const char *fileName) model.meshCount = iqm.num_meshes; model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh)); - char name[MESH_NAME_LENGTH]; + char name[MESH_NAME_LENGTH] = { 0 }; for (int i = 0; i < model.meshCount; i++) { - fseek(iqmFile,iqm.ofs_text+imesh[i].name,SEEK_SET); + fseek(iqmFile, iqm.ofs_text + imesh[i].name, SEEK_SET); fread(name, sizeof(char)*MESH_NAME_LENGTH, 1, iqmFile); // Mesh name not used... model.meshes[i].vertexCount = imesh[i].num_vertexes; - model.meshes[i].vertices = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex positions - model.meshes[i].normals = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*3); // Default vertex normals - model.meshes[i].texcoords = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*2); // Default vertex texcoords + model.meshes[i].vertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex positions + model.meshes[i].normals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex normals + model.meshes[i].texcoords = RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float)); // Default vertex texcoords - model.meshes[i].boneIds = RL_MALLOC(sizeof(int)*model.meshes[i].vertexCount*4); // Up-to 4 bones supported! - model.meshes[i].boneWeights = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*4); // Up-to 4 bones supported! + model.meshes[i].boneIds = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float)); // Up-to 4 bones supported! + model.meshes[i].boneWeights = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float)); // Up-to 4 bones supported! model.meshes[i].triangleCount = imesh[i].num_triangles; - model.meshes[i].indices = RL_MALLOC(sizeof(unsigned short)*model.meshes[i].triangleCount*3); + model.meshes[i].indices = RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short)); // Animated verted data, what we actually process for rendering // NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning) - model.meshes[i].animVertices = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*3); - model.meshes[i].animNormals = RL_MALLOC(sizeof(float)*model.meshes[i].vertexCount*3); + model.meshes[i].animVertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); + model.meshes[i].animNormals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); - model.meshes[i].vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO*sizeof(unsigned int), 1); + model.meshes[i].vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); } // Triangles data processing - tri = RL_MALLOC(sizeof(IQMTriangle)*iqm.num_triangles); + tri = RL_MALLOC(iqm.num_triangles*sizeof(IQMTriangle)); fseek(iqmFile, iqm.ofs_triangles, SEEK_SET); - fread(tri, sizeof(IQMTriangle)*iqm.num_triangles, 1, iqmFile); + fread(tri, iqm.num_triangles*sizeof(IQMTriangle), 1, iqmFile); for (int m = 0; m < model.meshCount; m++) { @@ -3111,9 +3114,9 @@ static Model LoadIQM(const char *fileName) } // Vertex arrays data processing - va = RL_MALLOC(sizeof(IQMVertexArray)*iqm.num_vertexarrays); + va = RL_MALLOC(iqm.num_vertexarrays*sizeof(IQMVertexArray)); fseek(iqmFile, iqm.ofs_vertexarrays, SEEK_SET); - fread(va, sizeof(IQMVertexArray)*iqm.num_vertexarrays, 1, iqmFile); + fread(va, iqm.num_vertexarrays*sizeof(IQMVertexArray), 1, iqmFile); for (int i = 0; i < iqm.num_vertexarrays; i++) { @@ -3121,9 +3124,9 @@ static Model LoadIQM(const char *fileName) { case IQM_POSITION: { - vertex = RL_MALLOC(sizeof(float)*iqm.num_vertexes*3); + vertex = RL_MALLOC(iqm.num_vertexes*3*sizeof(float)); fseek(iqmFile, va[i].offset, SEEK_SET); - fread(vertex, sizeof(float)*iqm.num_vertexes*3, 1, iqmFile); + fread(vertex, iqm.num_vertexes*3*sizeof(float), 1, iqmFile); for (int m = 0; m < iqm.num_meshes; m++) { @@ -3138,9 +3141,9 @@ static Model LoadIQM(const char *fileName) } break; case IQM_NORMAL: { - normal = RL_MALLOC(sizeof(float)*iqm.num_vertexes*3); + normal = RL_MALLOC(iqm.num_vertexes*3*sizeof(float)); fseek(iqmFile, va[i].offset, SEEK_SET); - fread(normal, sizeof(float)*iqm.num_vertexes*3, 1, iqmFile); + fread(normal, iqm.num_vertexes*3*sizeof(float), 1, iqmFile); for (int m = 0; m < iqm.num_meshes; m++) { @@ -3155,9 +3158,9 @@ static Model LoadIQM(const char *fileName) } break; case IQM_TEXCOORD: { - text = RL_MALLOC(sizeof(float)*iqm.num_vertexes*2); + text = RL_MALLOC(iqm.num_vertexes*2*sizeof(float)); fseek(iqmFile, va[i].offset, SEEK_SET); - fread(text, sizeof(float)*iqm.num_vertexes*2, 1, iqmFile); + fread(text, iqm.num_vertexes*2*sizeof(float), 1, iqmFile); for (int m = 0; m < iqm.num_meshes; m++) { @@ -3171,9 +3174,9 @@ static Model LoadIQM(const char *fileName) } break; case IQM_BLENDINDEXES: { - blendi = RL_MALLOC(sizeof(char)*iqm.num_vertexes*4); + blendi = RL_MALLOC(iqm.num_vertexes*4*sizeof(char)); fseek(iqmFile, va[i].offset, SEEK_SET); - fread(blendi, sizeof(char)*iqm.num_vertexes*4, 1, iqmFile); + fread(blendi, iqm.num_vertexes*4*sizeof(char), 1, iqmFile); for (int m = 0; m < iqm.num_meshes; m++) { @@ -3187,9 +3190,9 @@ static Model LoadIQM(const char *fileName) } break; case IQM_BLENDWEIGHTS: { - blendw = RL_MALLOC(sizeof(unsigned char)*iqm.num_vertexes*4); - fseek(iqmFile,va[i].offset,SEEK_SET); - fread(blendw,sizeof(unsigned char)*iqm.num_vertexes*4,1,iqmFile); + blendw = RL_MALLOC(iqm.num_vertexes*4*sizeof(unsigned char)); + fseek(iqmFile, va[i].offset, SEEK_SET); + fread(blendw, iqm.num_vertexes*4*sizeof(unsigned char), 1, iqmFile); for (int m = 0; m < iqm.num_meshes; m++) { @@ -3205,20 +3208,20 @@ static Model LoadIQM(const char *fileName) } // Bones (joints) data processing - ijoint = RL_MALLOC(sizeof(IQMJoint)*iqm.num_joints); + ijoint = RL_MALLOC(iqm.num_joints*sizeof(IQMJoint)); fseek(iqmFile, iqm.ofs_joints, SEEK_SET); - fread(ijoint, sizeof(IQMJoint)*iqm.num_joints, 1, iqmFile); + fread(ijoint, iqm.num_joints*sizeof(IQMJoint), 1, iqmFile); model.boneCount = iqm.num_joints; - model.bones = RL_MALLOC(sizeof(BoneInfo)*iqm.num_joints); - model.bindPose = RL_MALLOC(sizeof(Transform)*iqm.num_joints); + model.bones = RL_MALLOC(iqm.num_joints*sizeof(BoneInfo)); + model.bindPose = RL_MALLOC(iqm.num_joints*sizeof(Transform)); for (int i = 0; i < iqm.num_joints; i++) { // Bones model.bones[i].parent = ijoint[i].parent; fseek(iqmFile, iqm.ofs_text + ijoint[i].name, SEEK_SET); - fread(model.bones[i].name,sizeof(char)*BONE_NAME_LENGTH, 1, iqmFile); + fread(model.bones[i].name, BONE_NAME_LENGTH*sizeof(char), 1, iqmFile); // Bind pose (base pose) model.bindPose[i].translation.x = ijoint[i].translate[0]; @@ -3410,7 +3413,7 @@ static Model LoadGLTF(const char *fileName) model.materials = RL_MALLOC(model.materialCount*sizeof(Material)); model.meshMaterial = RL_MALLOC(model.meshCount*sizeof(int)); - for (int i = 0; i < model.meshCount; i++) model.meshes[i].vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO*sizeof(unsigned int), 1); + for (int i = 0; i < model.meshCount; i++) model.meshes[i].vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); for (int i = 0; i < model.materialCount - 1; i++) { @@ -3418,7 +3421,7 @@ static Model LoadGLTF(const char *fileName) Texture2D texture = { 0 }; const char *texPath = GetDirectoryPath(fileName); - if (data->materials[i].pbr_metallic_roughness.base_color_factor) + if (data->materials[i].has_pbr_metallic_roughness) { tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255.99f); tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255.99f); @@ -3427,13 +3430,13 @@ static Model LoadGLTF(const char *fileName) } else { - tint.r = 1.f; - tint.g = 1.f; - tint.b = 1.f; - tint.a = 1.f; + tint.r = 1.0f; + tint.g = 1.0f; + tint.b = 1.0f; + tint.a = 1.0f; } - if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture) + if (data->materials[i].has_pbr_metallic_roughness) { cgltf_image *img = data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image; diff --git a/src/raudio.c b/src/raudio.c index 576190deb..43e63bc99 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -591,7 +591,7 @@ void SetMasterVolume(float volume) // Create a new audio buffer. Initially filled with silence AudioBuffer *InitAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 bufferSizeInFrames, int usage) { - AudioBuffer *audioBuffer = (AudioBuffer *)RL_CALLOC(sizeof(*audioBuffer), 1); + AudioBuffer *audioBuffer = (AudioBuffer *)RL_CALLOC(1, sizeof(AudioBuffer)); audioBuffer->buffer = RL_CALLOC((bufferSizeInFrames*channels*ma_get_bytes_per_sample(format)), 1); if (audioBuffer == NULL) diff --git a/src/raudio.h b/src/raudio.h index 8bbbe8613..302993a9f 100644 --- a/src/raudio.h +++ b/src/raudio.h @@ -182,7 +182,7 @@ float GetMusicTimePlayed(Music music); // Get current m AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream raw audio pcm data) void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data void CloseAudioStream(AudioStream stream); // Close audio stream and free memory -bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill +bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill void PlayAudioStream(AudioStream stream); // Play audio stream void PauseAudioStream(AudioStream stream); // Pause audio stream void ResumeAudioStream(AudioStream stream); // Resume audio stream diff --git a/src/raylib.h b/src/raylib.h index 6cf6fd23b..ec6fd8a11 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -460,7 +460,7 @@ typedef struct VrDeviceInfo { // System config flags // NOTE: Used for bit masks typedef enum { - FLAG_SHOW_LOGO = 1, // Set to show raylib logo at startup + FLAG_RESERVED = 1, // Reserved FLAG_FULLSCREEN_MODE = 2, // Set to run program in fullscreen FLAG_WINDOW_RESIZABLE = 4, // Set to allow resizable window FLAG_WINDOW_UNDECORATED = 8, // Set to disable window decoration (frame and buttons) @@ -904,11 +904,16 @@ RLAPI void BeginMode3D(Camera3D camera); // Initializes RLAPI void EndMode3D(void); // Ends 3D mode and returns to default 2D orthographic mode RLAPI void BeginTextureMode(RenderTexture2D target); // Initializes render texture for drawing RLAPI void EndTextureMode(void); // Ends drawing to render texture +RLAPI void BeginScissorMode(int x, int y, int width, int height); // Begin scissor mode (define screen area for following drawing) +RLAPI void EndScissorMode(void); // End scissor mode // Screen-space-related functions RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position -RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position for a 3d world space position RLAPI Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix) +RLAPI Matrix GetCameraMatrix2D(Camera2D camera); // Returns camera 2d transform matrix +RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position for a 3d world space position +RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Returns the screen space position for a 2d camera world space position +RLAPI Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera); // Returns the world space position for a 2d camera screen space position // Timing-related functions RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) @@ -939,7 +944,7 @@ RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists RLAPI const char *GetExtension(const char *fileName); // Get pointer to extension for a filename string RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string -RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (memory should be freed) +RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string) RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string) RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string) RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) @@ -1324,8 +1329,6 @@ RLAPI void BeginShaderMode(Shader shader); // Beg RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader) RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied) RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending) -RLAPI void BeginScissorMode(int x, int y, int width, int height); // Begin scissor mode (define screen area for following drawing) -RLAPI void EndScissorMode(void); // End scissor mode // VR control functions RLAPI void InitVrSimulator(void); // Init VR simulator for selected device parameters diff --git a/src/rlgl.h b/src/rlgl.h index 5e7312bde..85d60fe19 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -457,6 +457,9 @@ RLAPI void rlEnableDepthTest(void); // Enable depth te RLAPI void rlDisableDepthTest(void); // Disable depth test RLAPI void rlEnableBackfaceCulling(void); // Enable backface culling RLAPI void rlDisableBackfaceCulling(void); // Disable backface culling +RLAPI void rlEnableScissorTest(void); // Enable scissor test +RLAPI void rlDisableScissorTest(void); // Disable scissor test +RLAPI void rlScissor(int x, int y, int width, int height); // Scissor test RLAPI void rlEnableWireMode(void); // Enable wire mode RLAPI void rlDisableWireMode(void); // Disable wire mode RLAPI void rlDeleteTextures(unsigned int id); // Delete OpenGL texture from GPU @@ -1344,28 +1347,25 @@ void rlDisableRenderTexture(void) } // Enable depth test -void rlEnableDepthTest(void) -{ - glEnable(GL_DEPTH_TEST); -} +void rlEnableDepthTest(void) { glEnable(GL_DEPTH_TEST); } // Disable depth test -void rlDisableDepthTest(void) -{ - glDisable(GL_DEPTH_TEST); -} +void rlDisableDepthTest(void) { glDisable(GL_DEPTH_TEST); } // Enable backface culling -void rlEnableBackfaceCulling(void) -{ - glEnable(GL_CULL_FACE); -} +void rlEnableBackfaceCulling(void) { glEnable(GL_CULL_FACE); } // Disable backface culling -void rlDisableBackfaceCulling(void) -{ - glDisable(GL_CULL_FACE); -} +void rlDisableBackfaceCulling(void) { glDisable(GL_CULL_FACE); } + +// Enable scissor test +RLAPI void rlEnableScissorTest(void) { glEnable(GL_SCISSOR_TEST); } + +// Disable scissor test +RLAPI void rlDisableScissorTest(void) { glDisable(GL_SCISSOR_TEST); } + +// Scissor test +RLAPI void rlScissor(int x, int y, int width, int height) { glScissor(x, y, width, height); } // Enable wire mode void rlEnableWireMode(void) @@ -1529,24 +1529,33 @@ void rlglInit(int width, int height) const char **extList = RL_MALLOC(sizeof(const char *)*numExt); // Get extensions strings - for (int i = 0; i < numExt; i++) extList[i] = (char *)glGetStringi(GL_EXTENSIONS, i); + for (int i = 0; i < numExt; i++) extList[i] = (const char *)glGetStringi(GL_EXTENSIONS, i); #elif defined(GRAPHICS_API_OPENGL_ES2) // Allocate 512 strings pointers (2 KB) const char **extList = RL_MALLOC(sizeof(const char *)*512); + + const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string + + // NOTE: We have to duplicate string because glGetString() returns a const string + int len = strlen(extensions) + 1; + char *extensionsDup = (char *)RL_CALLOC(len, sizeof(char)); + strcpy(extensionsDup, extensions); - // Get extensions strings - char *extensions = (char *)glGetString(GL_EXTENSIONS); // One big static const string returned - int len = strlen(extensions); + extList[numExt] = extensionsDup; for (int i = 0; i < len; i++) { - if (i == ' ') + if (extensionsDup[i] == ' ') { - extList[numExt] = &extensions[i + 1]; + extensionsDup[i] = '\0'; + numExt++; + extList[numExt] = &extensionsDup[i + 1]; } } + + // NOTE: Duplicated string (extensionsDup) must be deallocated #endif TraceLog(LOG_INFO, "Number of supported extensions: %i", numExt); @@ -1622,6 +1631,8 @@ void rlglInit(int width, int height) RL_FREE(extList); #if defined(GRAPHICS_API_OPENGL_ES2) + RL_FREE(extensionsDup); // Duplicated string must be deallocated + if (vaoSupported) TraceLog(LOG_INFO, "[EXTENSION] VAO extension detected, VAO functions initialized successfully"); else TraceLog(LOG_WARNING, "[EXTENSION] VAO extension not found, VAO usage not supported"); @@ -1687,7 +1698,6 @@ void rlglInit(int width, int height) // Initialize OpenGL default states //---------------------------------------------------------- - // Init state: Depth test glDepthFunc(GL_LEQUAL); // Type of depth testing to apply glDisable(GL_DEPTH_TEST); // Disable depth testing for 2D (only used for 3D) @@ -2957,7 +2967,7 @@ char *LoadText(const char *fileName) Shader LoadShader(const char *vsFileName, const char *fsFileName) { Shader shader = { 0 }; - shader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS*sizeof(int), 1); + shader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS, sizeof(int)); char *vShaderStr = NULL; char *fShaderStr = NULL; @@ -2978,7 +2988,7 @@ Shader LoadShader(const char *vsFileName, const char *fsFileName) Shader LoadShaderCode(char *vsCode, char *fsCode) { Shader shader = { 0 }; - shader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS*sizeof(int), 1); + shader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS, sizeof(int)); // NOTE: All locations must be reseted to -1 (no location) for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1; @@ -3014,7 +3024,7 @@ Shader LoadShaderCode(char *vsCode, char *fsCode) glGetProgramiv(shader.id, GL_ACTIVE_UNIFORMS, &uniformCount); - for(int i = 0; i < uniformCount; i++) + for (int i = 0; i < uniformCount; i++) { int namelen = -1; int num = -1; @@ -3513,24 +3523,6 @@ void EndBlendMode(void) BeginBlendMode(BLEND_ALPHA); } -// Begin scissor mode (define screen area for following drawing) -// NOTE: Scissor rec refers to bottom-left corner, we change it to upper-left -void BeginScissorMode(int x, int y, int width, int height) -{ - rlglDraw(); // Force drawing elements - - glEnable(GL_SCISSOR_TEST); - glScissor(x, framebufferHeight - (y + height), width, height); -} - -// End scissor mode -void EndScissorMode(void) -{ - rlglDraw(); // Force drawing elements - - glDisable(GL_SCISSOR_TEST); -} - #if defined(SUPPORT_VR_SIMULATOR) // Init VR simulator for selected device parameters // NOTE: It modifies the global variable: stereoFbo @@ -3869,7 +3861,7 @@ static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShad static Shader LoadShaderDefault(void) { Shader shader = { 0 }; - shader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS*sizeof(int), 1); + shader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS, sizeof(int)); // NOTE: All locations must be reseted to -1 (no location) for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1; diff --git a/src/shapes.c b/src/shapes.c index 6217d2ada..a9fafccc7 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -1392,8 +1392,8 @@ bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2) { bool collision = false; - if ((rec1.x <= (rec2.x + rec2.width) && (rec1.x + rec1.width) >= rec2.x) && - (rec1.y <= (rec2.y + rec2.height) && (rec1.y + rec1.height) >= rec2.y)) collision = true; + if ((rec1.x < (rec2.x + rec2.width) && (rec1.x + rec1.width) > rec2.x) && + (rec1.y < (rec2.y + rec2.height) && (rec1.y + rec1.height) > rec2.y)) collision = true; return collision; } diff --git a/src/text.c b/src/text.c index 1c775c8db..4eb1b4b04 100644 --- a/src/text.c +++ b/src/text.c @@ -586,7 +586,7 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo *charRecs = NULL; // In case no chars count provided we suppose default of 95 - charsCount = (charsCount > 0) ? charsCount : 95; + charsCount = (charsCount > 0)? charsCount : 95; // NOTE: Rectangles memory is loaded here! Rectangle *recs = (Rectangle *)RL_MALLOC(charsCount*sizeof(Rectangle)); @@ -597,7 +597,7 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo // so image size would result bigger than default font type float requiredArea = 0; for (int i = 0; i < charsCount; i++) requiredArea += ((chars[i].image.width + 2*padding)*(chars[i].image.height + 2*padding)); - float guessSize = sqrtf(requiredArea)*1.25f; + float guessSize = sqrtf(requiredArea)*1.3f; int imageSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT atlas.width = imageSize; // Atlas bitmap width @@ -1372,20 +1372,25 @@ const char **TextSplit(const char *text, char delimiter, int *count) memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); result[0] = buffer; - int counter = 1; - - // Count how many substrings we have on text and point to every one - for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) + int counter = 0; + + if (text != NULL) { - buffer[i] = text[i]; - if (buffer[i] == '\0') break; - else if (buffer[i] == delimiter) + counter = 1; + + // Count how many substrings we have on text and point to every one + for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) { - buffer[i] = '\0'; // Set an end of string at this point - result[counter] = buffer + i + 1; - counter++; + buffer[i] = text[i]; + if (buffer[i] == '\0') break; + else if (buffer[i] == delimiter) + { + buffer[i] = '\0'; // Set an end of string at this point + result[counter] = buffer + i + 1; + counter++; - if (counter == MAX_SUBSTRINGS_COUNT) break; + if (counter == MAX_SUBSTRINGS_COUNT) break; + } } }