Merge branch 'master' into i-cant-think-of-a-name

This commit is contained in:
Leandro Gabriel 2019-08-02 21:22:19 -03:00
commit 50786b655b
33 changed files with 2296 additions and 815 deletions

2
.github/FUNDING.yml vendored
View File

@ -1,6 +1,6 @@
# These are supported funding model platforms # These are supported funding model platforms
github: # soon github: raysan5
patreon: raylib patreon: raylib
open_collective: # Replace with a single Open Collective username open_collective: # Replace with a single Open Collective username
ko_fi: raysan ko_fi: raysan

View File

@ -243,7 +243,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
# logic to a self contained function: UpdateDrawFrame(), check core_basic_window_web.c for reference. # logic to a self contained function: UpdateDrawFrame(), check core_basic_window_web.c for reference.
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif
@ -365,6 +365,7 @@ EXAMPLES = \
core/core_window_letterbox \ core/core_window_letterbox \
core/core_drop_files \ core/core_drop_files \
core/core_random_values \ core/core_random_values \
core/core_scissor_test \
core/core_storage_values \ core/core_storage_values \
core/core_vr_simulator \ core/core_vr_simulator \
core/core_loading_thread \ core/core_loading_thread \
@ -394,6 +395,7 @@ EXAMPLES = \
text/text_rectangle_bounds \ text/text_rectangle_bounds \
text/text_unicode \ text/text_unicode \
textures/textures_logo_raylib \ textures/textures_logo_raylib \
textures/textures_mouse_painting \
textures/textures_rectangle \ textures/textures_rectangle \
textures/textures_srcrec_dstrec \ textures/textures_srcrec_dstrec \
textures/textures_image_drawing \ textures/textures_image_drawing \

View File

@ -0,0 +1,71 @@
/*******************************************************************************************
*
* raylib [core] example - Scissor test
*
* 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 Dill (@MysteriousSpace) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2019 Chris Dill (@MysteriousSpace)
*
********************************************************************************************/
#include "raylib.h"
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - scissor test");
Rectangle scissorArea = { 0, 0, 300, 300 };
bool scissorMode = true;
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
//----------------------------------------------------------------------------------
if (IsKeyPressed(KEY_S)) scissorMode = !scissorMode;
// Centre the scissor area around the mouse position
scissorArea.x = GetMouseX() - scissorArea.width/2;
scissorArea.y = GetMouseY() - scissorArea.height/2;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
if (scissorMode) BeginScissorMode(scissorArea.x, scissorArea.y, scissorArea.width, scissorArea.height);
// Draw full screen rectangle and some text
// NOTE: Only part defined by scissor area will be rendered
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), RED);
DrawText("Move the mouse around to reveal this text!", 190, 200, 20, LIGHTGRAY);
if (scissorMode) EndScissorMode();
DrawRectangleLinesEx(scissorArea, 1, BLACK);
DrawText("Press S to toggle scissor test", 10, 10, 20, BLACK);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -29,7 +29,7 @@ int main(void)
int gameScreenWidth = 640; int gameScreenWidth = 640;
int gameScreenHeight = 480; int gameScreenHeight = 480;
// Render texture initialization // Render texture initialization, used to hold the rendering result so we can easily resize it
RenderTexture2D target = LoadRenderTexture(gameScreenWidth, gameScreenHeight); RenderTexture2D target = LoadRenderTexture(gameScreenWidth, gameScreenHeight);
SetTextureFilter(target.texture, FILTER_BILINEAR); // Texture scale filter to use SetTextureFilter(target.texture, FILTER_BILINEAR); // Texture scale filter to use
@ -59,7 +59,7 @@ int main(void)
BeginDrawing(); BeginDrawing();
ClearBackground(BLACK); ClearBackground(BLACK);
// Draw everything in the render texture // Draw everything in the render texture, note this will not be rendered on screen, yet
BeginTextureMode(target); BeginTextureMode(target);
ClearBackground(RAYWHITE); // Clear render texture background color ClearBackground(RAYWHITE); // Clear render texture background color

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,210 @@
/*******************************************************************************************
*
* raylib [textures] example - Mouse painting
*
* 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 Dill (@MysteriousSpace) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2019 Chris Dill (@MysteriousSpace) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include "raylib.h"
#define MAX_COLORS_COUNT 23 // Number of colors available
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [textures] example - mouse painting");
// Colours to choose from
Color colors[MAX_COLORS_COUNT] = {
RAYWHITE, YELLOW, GOLD, ORANGE, PINK, RED, MAROON, GREEN, LIME, DARKGREEN,
SKYBLUE, BLUE, DARKBLUE, PURPLE, VIOLET, DARKPURPLE, BEIGE, BROWN, DARKBROWN,
LIGHTGRAY, GRAY, DARKGRAY, BLACK };
// Define colorsRecs data (for every rectangle)
Rectangle colorsRecs[MAX_COLORS_COUNT] = { 0 };
for (int i = 0; i < MAX_COLORS_COUNT; i++)
{
colorsRecs[i].x = 10 + 30*i + 2*i;
colorsRecs[i].y = 10;
colorsRecs[i].width = 30;
colorsRecs[i].height = 30;
}
int colorSelected = 0;
int colorSelectedPrev = colorSelected;
int colorMouseHover = 0;
int brushSize = 20;
Rectangle btnSaveRec = { 750, 10, 40, 30 };
bool btnSaveMouseHover = false;
bool showSaveMessage = false;
int saveMessageCounter = 0;
// Create a RenderTexture2D to use as a canvas
RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight);
// Clear render texture before entering the game loop
BeginTextureMode(target);
ClearBackground(colors[0]);
EndTextureMode();
SetTargetFPS(120); // Set our game to run at 120 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
Vector2 mousePos = GetMousePosition();
// Move between colors with keys
if (IsKeyPressed(KEY_RIGHT)) colorSelected++;
else if (IsKeyPressed(KEY_LEFT)) colorSelected--;
if (colorSelected >= MAX_COLORS_COUNT) colorSelected = MAX_COLORS_COUNT - 1;
else if (colorSelected < 0) colorSelected = 0;
// Choose color with mouse
for (int i = 0; i < MAX_COLORS_COUNT; i++)
{
if (CheckCollisionPointRec(mousePos, colorsRecs[i]))
{
colorMouseHover = i;
break;
}
else colorMouseHover = -1;
}
if ((colorMouseHover >= 0) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
{
colorSelected = colorMouseHover;
colorSelectedPrev = colorSelected;
}
// Change brush size
brushSize += GetMouseWheelMove()*5;
if (brushSize < 2) brushSize = 2;
if (brushSize > 50) brushSize = 50;
if (IsKeyPressed(KEY_C))
{
// Clear render texture to clear color
BeginTextureMode(target);
ClearBackground(colors[0]);
EndTextureMode();
}
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
{
// Paint circle into render texture
// NOTE: To avoid discontinuous circles, we could store
// previous-next mouse points and just draw a line using brush size
BeginTextureMode(target);
if (mousePos.y > 50) DrawCircle(mousePos.x, mousePos.y, brushSize, colors[colorSelected]);
EndTextureMode();
}
if (IsMouseButtonDown(MOUSE_RIGHT_BUTTON))
{
colorSelected = 0;
// Erase circle from render texture
BeginTextureMode(target);
if (mousePos.y > 50) DrawCircle(mousePos.x, mousePos.y, brushSize, colors[0]);
EndTextureMode();
}
else colorSelected = colorSelectedPrev;
// Check mouse hover save button
if (CheckCollisionPointRec(mousePos, btnSaveRec)) btnSaveMouseHover = true;
else btnSaveMouseHover = false;
// Image saving logic
// NOTE: Saving painted texture to a default named image
if ((btnSaveMouseHover && IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) || IsKeyPressed(KEY_S))
{
Image image = GetTextureData(target.texture);
ImageFlipVertical(&image);
ExportImage(image, "my_amazing_texture_painting.png");
UnloadImage(image);
showSaveMessage = true;
}
if (showSaveMessage)
{
// On saving, show a full screen message for 2 seconds
saveMessageCounter++;
if (saveMessageCounter > 240)
{
showSaveMessage = false;
saveMessageCounter = 0;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
// NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom)
DrawTextureRec(target.texture, (Rectangle){ 0, 0, target.texture.width, -target.texture.height }, (Vector2){ 0, 0 }, WHITE);
// Draw drawing circle for reference
if (mousePos.y > 50)
{
if (IsMouseButtonDown(MOUSE_RIGHT_BUTTON)) DrawCircleLines(mousePos.x, mousePos.y, brushSize, colors[colorSelected]);
else DrawCircle(GetMouseX(), GetMouseY(), brushSize, colors[colorSelected]);
}
// Draw top panel
DrawRectangle(0, 0, GetScreenWidth(), 50, RAYWHITE);
DrawLine(0, 50, GetScreenWidth(), 50, LIGHTGRAY);
// Draw color selection rectangles
for (int i = 0; i < MAX_COLORS_COUNT; i++) DrawRectangleRec(colorsRecs[i], colors[i]);
DrawRectangleLines(10, 10, 30, 30, LIGHTGRAY);
if (colorMouseHover >= 0) DrawRectangleRec(colorsRecs[colorMouseHover], Fade(WHITE, 0.6f));
DrawRectangleLinesEx((Rectangle){ colorsRecs[colorSelected].x - 2, colorsRecs[colorSelected].y - 2,
colorsRecs[colorSelected].width + 4, colorsRecs[colorSelected].height + 4 }, 2, BLACK);
// Draw save image button
DrawRectangleLinesEx(btnSaveRec, 2, btnSaveMouseHover? RED : BLACK);
DrawText("SAVE!", 755, 20, 10, btnSaveMouseHover? RED : BLACK);
// Draw save image message
if (showSaveMessage)
{
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(RAYWHITE, 0.8f));
DrawRectangle(0, 150, GetScreenWidth(), 80, BLACK);
DrawText("IMAGE SAVED: my_amazing_texture_painting.png", 150, 180, 20, RAYWHITE);
}
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadRenderTexture(target); // Unload render texture
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif

View File

@ -200,7 +200,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
ifeq ($(PLATFORM_OS),WINDOWS) ifeq ($(PLATFORM_OS),WINDOWS)
# resource file contains windows executable icon and properties # resource file contains windows executable icon and properties
# -Wl,--subsystem,windows hides the console window # -Wl,--subsystem,windows hides the console window
CFLAGS += $(RAYLIB_PATH)/raylib.rc.data -Wl,--subsystem,windows CFLAGS += $(RAYLIB_PATH)/src/raylib.rc.data -Wl,--subsystem,windows
endif endif
ifeq ($(PLATFORM_OS),LINUX) ifeq ($(PLATFORM_OS),LINUX)
ifeq ($(RAYLIB_LIBTYPE),STATIC) ifeq ($(RAYLIB_LIBTYPE),STATIC)
@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif

View File

@ -59,9 +59,9 @@ int main(void)
atlas02 = LoadTexture("resources/graphics/atlas02.png"); atlas02 = LoadTexture("resources/graphics/atlas02.png");
#if defined(PLATFORM_WEB) || defined(PLATFORM_RPI) || defined(PLATFORM_ANDROID) #if defined(PLATFORM_WEB) || defined(PLATFORM_RPI) || defined(PLATFORM_ANDROID)
colorBlend = LoadShader("resources/shaders/glsl100/base.vs", "resources/shaders/glsl100/blend_color.fs"); colorBlend = LoadShader(0, "resources/shaders/glsl100/blend_color.fs");
#else #else
colorBlend = LoadShader("resources/shaders/glsl330/base.vs", "resources/shaders/glsl330/blend_color.fs"); colorBlend = LoadShader(0, "resources/shaders/glsl330/blend_color.fs");
#endif #endif
InitAudioDevice(); InitAudioDevice();
@ -76,20 +76,14 @@ int main(void)
fxDieDingo = LoadSound("resources/audio/dingo_die.ogg"); fxDieDingo = LoadSound("resources/audio/dingo_die.ogg");
fxDieOwl = LoadSound("resources/audio/owl_die.ogg"); fxDieOwl = LoadSound("resources/audio/owl_die.ogg");
music = LoadMusicStream("resources/audio/jngl.xm"); music = LoadMusicStream("resources/audio/jngl.xm");
PlayMusicStream(music); PlayMusicStream(music);
SetMusicVolume(music, 1.0f); SetMusicVolume(music, 2.0f);
// Define and init first screen // Define and init first screen
// NOTE: currentScreen is defined in screens.h as a global variable // NOTE: currentScreen is defined in screens.h as a global variable
currentScreen = TITLE; currentScreen = TITLE;
InitLogoScreen();
//InitOptionsScreen();
InitTitleScreen(); InitTitleScreen();
InitGameplayScreen();
InitEndingScreen();
#if defined(PLATFORM_WEB) #if defined(PLATFORM_WEB)
emscripten_set_main_loop(UpdateDrawFrame, 0, 1); emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
@ -258,8 +252,6 @@ void UpdateDrawFrame(void)
if (onTransition) DrawTransition(); if (onTransition) DrawTransition();
DrawFPS(20, GetScreenHeight() - 30);
DrawRectangle(GetScreenWidth() - 200, GetScreenHeight() - 50, 200, 40, Fade(WHITE, 0.6f)); DrawRectangle(GetScreenWidth() - 200, GetScreenHeight() - 50, 200, 40, Fade(WHITE, 0.6f));
DrawText("ALPHA VERSION", GetScreenWidth() - 180, GetScreenHeight() - 40, 20, DARKGRAY); DrawText("ALPHA VERSION", GetScreenWidth() - 180, GetScreenHeight() - 40, 20, DARKGRAY);

View File

@ -38,7 +38,6 @@
//#define DEBUG //#define DEBUG
// DONE: Review MAX_* limits, don't waste memory!!!
#define MAX_ENEMIES 16 #define MAX_ENEMIES 16
#define MAX_BAMBOO 16 #define MAX_BAMBOO 16
#define MAX_LEAVES 14 #define MAX_LEAVES 14
@ -343,7 +342,6 @@ static Rectangle leftButton = {0, 0, 0, 0};
static Rectangle rightButton = {0, 0, 0, 0}; static Rectangle rightButton = {0, 0, 0, 0};
static Rectangle powerButton = {0, 0, 0, 0}; static Rectangle powerButton = {0, 0, 0, 0};
static Rectangle fire[MAX_FIRE]; static Rectangle fire[MAX_FIRE];
//static Rectangle flames[MAX_FLAMES];
static Rectangle ice[MAX_ICE]; static Rectangle ice[MAX_ICE];
static Rectangle resin[MAX_RESIN]; static Rectangle resin[MAX_RESIN];
static Rectangle wind[MAX_WIND]; static Rectangle wind[MAX_WIND];
@ -351,7 +349,7 @@ static Rectangle bamboo[MAX_BAMBOO];
static Rectangle snake[MAX_ENEMIES]; static Rectangle snake[MAX_ENEMIES];
static Rectangle dingo[MAX_ENEMIES]; static Rectangle dingo[MAX_ENEMIES];
static Rectangle owl[MAX_ENEMIES]; static Rectangle owl[MAX_ENEMIES];
static Rectangle leaf[MAX_LEAVES]; // DONE: Review name! static Rectangle leaf[MAX_LEAVES];
static Rectangle powerBar; static Rectangle powerBar;
static Rectangle backBar; static Rectangle backBar;
static Rectangle fireAnimation; static Rectangle fireAnimation;
@ -387,7 +385,7 @@ static Vector2 textSize;
static Vector2 clockPosition; static Vector2 clockPosition;
static Particle enemyHit[MAX_ENEMIES]; static Particle enemyHit[MAX_ENEMIES];
static ParticleSystem leafParticles[MAX_LEAVES]; // DONE: Review!!! Creating 40 ParticleSystem!!! -> 40*128 = 5120 Particles! Maybe better create a struct Leaf? static ParticleSystem leafParticles[MAX_LEAVES];
static ParticleSystem snowParticle; static ParticleSystem snowParticle;
static ParticleSystem backSnowParticle; static ParticleSystem backSnowParticle;
static ParticleSystem dandelionParticle; static ParticleSystem dandelionParticle;
@ -1043,12 +1041,8 @@ void UpdateGameplayScreen(void)
#endif #endif
} }
#if defined(DEBUG) #if defined(DEBUG)
if (currentLeaves < LEAVESTOTRANSFORM && (IsKeyPressed(KEY_ENTER))) if ((currentLeaves < LEAVESTOTRANSFORM) && (IsKeyPressed(KEY_ENTER))) currentLeaves += LEAVESTOTRANSFORM;
{
currentLeaves += LEAVESTOTRANSFORM;
}
#endif #endif
if (coolDown) if (coolDown)
{ {
power += 20; power += 20;
@ -1427,10 +1421,6 @@ void UpdateGameplayScreen(void)
if (CheckCollisionRecs(player, leaf[j]) && leafActive[j]) if (CheckCollisionRecs(player, leaf[j]) && leafActive[j])
{ {
//power += 20;
//printf("coin %c", coinType[j]);
// DONE: Review
popupLeaves[j].position = (Vector2){ leaf[j].x, leaf[j].y }; popupLeaves[j].position = (Vector2){ leaf[j].x, leaf[j].y };
popupLeaves[j].scale = 1.0f; popupLeaves[j].scale = 1.0f;
popupLeaves[j].alpha = 1.0f; popupLeaves[j].alpha = 1.0f;
@ -2232,7 +2222,6 @@ void UpdateGameplayScreen(void)
player.x -= speed; player.x -= speed;
grabCounter += 1*TIME_FACTOR; grabCounter += 1*TIME_FACTOR;
// DONE: Review, before checking collision with ALL enemies, check if they are active!
for (int i = 0; i < MAX_ENEMIES; i++) for (int i = 0; i < MAX_ENEMIES; i++)
{ {
if (CheckCollisionRecs(player, snake[i]) && !isHitSnake[i] && snakeActive[i]) if (CheckCollisionRecs(player, snake[i]) && !isHitSnake[i] && snakeActive[i])
@ -2286,7 +2275,6 @@ void UpdateGameplayScreen(void)
enemyHit[i].speed = (Vector2){ dingo[i].x, dingo[i].y }; enemyHit[i].speed = (Vector2){ dingo[i].x, dingo[i].y };
enemyHit[i].size = (float)GetRandomValue(5, 10)/30; enemyHit[i].size = (float)GetRandomValue(5, 10)/30;
enemyHit[i].rotation = 0.0f; enemyHit[i].rotation = 0.0f;
//enemyHit[i].color = (Color){ GetRandomValue(0, 255), GetRandomValue(0, 255), GetRandomValue(0, 255), 255 };
enemyHit[i].alpha = 1.0f; enemyHit[i].alpha = 1.0f;
enemyHit[i].active = true; enemyHit[i].active = true;
@ -2317,7 +2305,6 @@ void UpdateGameplayScreen(void)
enemyHit[i].speed = (Vector2){ owl[i].x, owl[i].y }; enemyHit[i].speed = (Vector2){ owl[i].x, owl[i].y };
enemyHit[i].size = (float)GetRandomValue(5, 10)/30; enemyHit[i].size = (float)GetRandomValue(5, 10)/30;
enemyHit[i].rotation = 0.0f; enemyHit[i].rotation = 0.0f;
//enemyHit[i].color = (Color){ GetRandomValue(0, 255), GetRandomValue(0, 255), GetRandomValue(0, 255), 255 };
enemyHit[i].alpha = 1.0f; enemyHit[i].alpha = 1.0f;
enemyHit[i].active = true; enemyHit[i].active = true;
@ -2392,8 +2379,6 @@ void UpdateGameplayScreen(void)
thisFrameKoala = 0; thisFrameKoala = 0;
} }
//if (curFrameKoala > 1) curFrameKoala = ;
if (curFrameKoala <= 1) koalaAnimationTransform.x = gameplay_koala_transform.x + koalaAnimationTransform.width*curFrameKoala; if (curFrameKoala <= 1) koalaAnimationTransform.x = gameplay_koala_transform.x + koalaAnimationTransform.width*curFrameKoala;
if (transAniCounter >= 5) if (transAniCounter >= 5)
@ -2407,8 +2392,7 @@ void UpdateGameplayScreen(void)
finalColor = RED; finalColor = RED;
finalColor2 = WHITE; finalColor2 = WHITE;
} }
else
if (!transBackAnim)
{ {
finalColor = WHITE; finalColor = WHITE;
finalColor2 = RED; finalColor2 = RED;
@ -2420,9 +2404,7 @@ void UpdateGameplayScreen(void)
thisFrameKoala = 0; thisFrameKoala = 0;
curFrameKoala = 0; curFrameKoala = 0;
speedFX.active = true; speedFX.active = true;
//speedMod = 2;
transCount = 0; transCount = 0;
//printf ("THIS ISN'T EVEN MY FINAL FORM");
bambooTimer += 15*TIME_FACTOR; bambooTimer += 15*TIME_FACTOR;
} }
} }

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif

View File

@ -14,9 +14,9 @@
"PLATFORM_DESKTOP" "PLATFORM_DESKTOP"
], ],
"compilerPath": "C:/raylib/mingw/bin/gcc.exe", "compilerPath": "C:/raylib/mingw/bin/gcc.exe",
"cStandard": "c11", "cStandard": "c99",
"cppStandard": "c++14", "cppStandard": "c++14",
"intelliSenseMode": "clang-x64" "intelliSenseMode": "gcc-x64"
}, },
{ {
"name": "Mac", "name": "Mac",

View File

@ -26,7 +26,10 @@
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": true "isDefault": true
} },
"problemMatcher": [
"$gcc"
]
}, },
{ {
"label": "build release", "label": "build release",
@ -47,7 +50,10 @@
"RAYLIB_PATH=<path_to_raylib>/raylib", "RAYLIB_PATH=<path_to_raylib>/raylib",
], ],
}, },
"group": "build" "group": "build",
"problemMatcher": [
"$gcc"
]
} }
] ]
} }

View File

@ -29,8 +29,10 @@ RAYLIB_VERSION ?= 2.5.0
RAYLIB_API_VERSION ?= 251 RAYLIB_API_VERSION ?= 251
RAYLIB_PATH ?= ..\.. RAYLIB_PATH ?= ..\..
# Define default options # Define compiler path on Windows
COMPILER_PATH ?= C:/raylib/mingw/bin
# Define default options
# One of PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB # One of PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB
PLATFORM ?= PLATFORM_DESKTOP PLATFORM ?= PLATFORM_DESKTOP
@ -68,6 +70,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
# ifeq ($(UNAME),Msys) -> Windows # ifeq ($(UNAME),Msys) -> Windows
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
PLATFORM_OS=WINDOWS PLATFORM_OS=WINDOWS
export PATH := $(COMPILER_PATH):$(PATH)
else else
UNAMEOS=$(shell uname) UNAMEOS=$(shell uname)
ifeq ($(UNAMEOS),Linux) ifeq ($(UNAMEOS),Linux)
@ -236,7 +239,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif

View File

@ -251,10 +251,6 @@ void SetCameraMode(Camera camera, int mode)
cameraAngle.x = asinf( (float)fabs(dx)/distance.x); // Camera angle in plane XZ (0 aligned with Z, move positive CCW) cameraAngle.x = asinf( (float)fabs(dx)/distance.x); // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
cameraAngle.y = -asinf( (float)fabs(dy)/distance.y); // Camera angle in plane XY (0 aligned with X, move positive CW) cameraAngle.y = -asinf( (float)fabs(dy)/distance.y); // Camera angle in plane XY (0 aligned with X, move positive CW)
// NOTE: Just testing what cameraAngle means
//cameraAngle.x = 0.0f*DEG2RAD; // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
//cameraAngle.y = -60.0f*DEG2RAD; // Camera angle in plane XY (0 aligned with X, move positive CW)
playerEyesPosition = camera.position.y; playerEyesPosition = camera.position.y;
// Lock cursor for first person and third person cameras // Lock cursor for first person and third person cameras

View File

@ -126,7 +126,7 @@
#include "gestures.h" // Gestures detection functionality #include "gestures.h" // Gestures detection functionality
#endif #endif
#if defined(SUPPORT_CAMERA_SYSTEM) && !defined(PLATFORM_ANDROID) #if defined(SUPPORT_CAMERA_SYSTEM)
#define CAMERA_IMPLEMENTATION #define CAMERA_IMPLEMENTATION
#include "camera.h" // Camera system functionality #include "camera.h" // Camera system functionality
#endif #endif

View File

@ -236,16 +236,16 @@ static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 fr
// AudioBuffer management functions declaration // AudioBuffer management functions declaration
// NOTE: Those functions are not exposed by raylib... for the moment // NOTE: Those functions are not exposed by raylib... for the moment
AudioBuffer *InitAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 bufferSizeInFrames, int usage); AudioBuffer *InitAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 bufferSizeInFrames, int usage);
void CloseAudioBuffer(AudioBuffer *audioBuffer); void CloseAudioBuffer(AudioBuffer *buffer);
bool IsAudioBufferPlaying(AudioBuffer *audioBuffer); bool IsAudioBufferPlaying(AudioBuffer *buffer);
void PlayAudioBuffer(AudioBuffer *audioBuffer); void PlayAudioBuffer(AudioBuffer *buffer);
void StopAudioBuffer(AudioBuffer *audioBuffer); void StopAudioBuffer(AudioBuffer *buffer);
void PauseAudioBuffer(AudioBuffer *audioBuffer); void PauseAudioBuffer(AudioBuffer *buffer);
void ResumeAudioBuffer(AudioBuffer *audioBuffer); void ResumeAudioBuffer(AudioBuffer *buffer);
void SetAudioBufferVolume(AudioBuffer *audioBuffer, float volume); void SetAudioBufferVolume(AudioBuffer *buffer, float volume);
void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch); void SetAudioBufferPitch(AudioBuffer *buffer, float pitch);
void TrackAudioBuffer(AudioBuffer *audioBuffer); void TrackAudioBuffer(AudioBuffer *buffer);
void UntrackAudioBuffer(AudioBuffer *audioBuffer); void UntrackAudioBuffer(AudioBuffer *buffer);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Multi channel playback globals // Multi channel playback globals
@ -644,151 +644,127 @@ AudioBuffer *InitAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
} }
// Delete an audio buffer // Delete an audio buffer
void CloseAudioBuffer(AudioBuffer *audioBuffer) void CloseAudioBuffer(AudioBuffer *buffer)
{ {
if (audioBuffer == NULL) if (buffer != NULL)
{ {
TraceLog(LOG_ERROR, "CloseAudioBuffer() : No audio buffer"); UntrackAudioBuffer(buffer);
return; RL_FREE(buffer->buffer);
RL_FREE(buffer);
} }
else TraceLog(LOG_ERROR, "CloseAudioBuffer() : No audio buffer");
UntrackAudioBuffer(audioBuffer);
RL_FREE(audioBuffer->buffer);
RL_FREE(audioBuffer);
} }
// Check if an audio buffer is playing // Check if an audio buffer is playing
bool IsAudioBufferPlaying(AudioBuffer *audioBuffer) bool IsAudioBufferPlaying(AudioBuffer *buffer)
{ {
if (audioBuffer == NULL) bool result = false;
{
TraceLog(LOG_ERROR, "IsAudioBufferPlaying() : No audio buffer");
return false;
}
return audioBuffer->playing && !audioBuffer->paused; if (buffer != NULL) result = (buffer->playing && !buffer->paused);
else TraceLog(LOG_ERROR, "IsAudioBufferPlaying() : No audio buffer");
return result;
} }
// Play an audio buffer // Play an audio buffer
// NOTE: Buffer is restarted to the start. // NOTE: Buffer is restarted to the start.
// Use PauseAudioBuffer() and ResumeAudioBuffer() if the playback position should be maintained. // Use PauseAudioBuffer() and ResumeAudioBuffer() if the playback position should be maintained.
void PlayAudioBuffer(AudioBuffer *audioBuffer) void PlayAudioBuffer(AudioBuffer *buffer)
{ {
if (audioBuffer == NULL) if (buffer != NULL)
{ {
TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); buffer->playing = true;
return; buffer->paused = false;
buffer->frameCursorPos = 0;
} }
else TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer");
audioBuffer->playing = true;
audioBuffer->paused = false;
audioBuffer->frameCursorPos = 0;
} }
// Stop an audio buffer // Stop an audio buffer
void StopAudioBuffer(AudioBuffer *audioBuffer) void StopAudioBuffer(AudioBuffer *buffer)
{ {
if (audioBuffer == NULL) if (buffer != NULL)
{ {
TraceLog(LOG_ERROR, "StopAudioBuffer() : No audio buffer"); if (IsAudioBufferPlaying(buffer))
return; {
buffer->playing = false;
buffer->paused = false;
buffer->frameCursorPos = 0;
buffer->isSubBufferProcessed[0] = true;
buffer->isSubBufferProcessed[1] = true;
} }
}
// Don't do anything if the audio buffer is already stopped. else TraceLog(LOG_ERROR, "StopAudioBuffer() : No audio buffer");
if (!IsAudioBufferPlaying(audioBuffer)) return;
audioBuffer->playing = false;
audioBuffer->paused = false;
audioBuffer->frameCursorPos = 0;
audioBuffer->isSubBufferProcessed[0] = true;
audioBuffer->isSubBufferProcessed[1] = true;
} }
// Pause an audio buffer // Pause an audio buffer
void PauseAudioBuffer(AudioBuffer *audioBuffer) void PauseAudioBuffer(AudioBuffer *buffer)
{ {
if (audioBuffer == NULL) if (buffer != NULL) buffer->paused = true;
{ else TraceLog(LOG_ERROR, "PauseAudioBuffer() : No audio buffer");
TraceLog(LOG_ERROR, "PauseAudioBuffer() : No audio buffer");
return;
}
audioBuffer->paused = true;
} }
// Resume an audio buffer // Resume an audio buffer
void ResumeAudioBuffer(AudioBuffer *audioBuffer) void ResumeAudioBuffer(AudioBuffer *buffer)
{ {
if (audioBuffer == NULL) if (buffer != NULL) buffer->paused = false;
{ else TraceLog(LOG_ERROR, "ResumeAudioBuffer() : No audio buffer");
TraceLog(LOG_ERROR, "ResumeAudioBuffer() : No audio buffer");
return;
}
audioBuffer->paused = false;
} }
// Set volume for an audio buffer // Set volume for an audio buffer
void SetAudioBufferVolume(AudioBuffer *audioBuffer, float volume) void SetAudioBufferVolume(AudioBuffer *buffer, float volume)
{ {
if (audioBuffer == NULL) if (buffer != NULL) buffer->volume = volume;
{ else TraceLog(LOG_WARNING, "SetAudioBufferVolume() : No audio buffer");
TraceLog(LOG_WARNING, "SetAudioBufferVolume() : No audio buffer");
return;
}
audioBuffer->volume = volume;
} }
// Set pitch for an audio buffer // Set pitch for an audio buffer
void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch) void SetAudioBufferPitch(AudioBuffer *buffer, float pitch)
{ {
if (audioBuffer == NULL) if (buffer != NULL)
{ {
TraceLog(LOG_WARNING, "SetAudioBufferPitch() : No audio buffer"); float pitchMul = pitch/buffer->pitch;
return;
}
float pitchMul = pitch/audioBuffer->pitch;
// Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches // Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches
// will make the sound faster; lower pitches make it slower. // will make the sound faster; lower pitches make it slower.
ma_uint32 newOutputSampleRate = (ma_uint32)((float)audioBuffer->dsp.src.config.sampleRateOut / pitchMul); ma_uint32 newOutputSampleRate = (ma_uint32)((float)buffer->dsp.src.config.sampleRateOut/pitchMul);
audioBuffer->pitch *= (float)audioBuffer->dsp.src.config.sampleRateOut / newOutputSampleRate; buffer->pitch *= (float)buffer->dsp.src.config.sampleRateOut/newOutputSampleRate;
ma_pcm_converter_set_output_sample_rate(&audioBuffer->dsp, newOutputSampleRate); ma_pcm_converter_set_output_sample_rate(&buffer->dsp, newOutputSampleRate);
}
else TraceLog(LOG_WARNING, "SetAudioBufferPitch() : No audio buffer");
} }
// Track audio buffer to linked list next position // Track audio buffer to linked list next position
void TrackAudioBuffer(AudioBuffer *audioBuffer) void TrackAudioBuffer(AudioBuffer *buffer)
{ {
ma_mutex_lock(&audioLock); ma_mutex_lock(&audioLock);
{ {
if (firstAudioBuffer == NULL) firstAudioBuffer = audioBuffer; if (firstAudioBuffer == NULL) firstAudioBuffer = buffer;
else else
{ {
lastAudioBuffer->next = audioBuffer; lastAudioBuffer->next = buffer;
audioBuffer->prev = lastAudioBuffer; buffer->prev = lastAudioBuffer;
} }
lastAudioBuffer = audioBuffer; lastAudioBuffer = buffer;
} }
ma_mutex_unlock(&audioLock); ma_mutex_unlock(&audioLock);
} }
// Untrack audio buffer from linked list // Untrack audio buffer from linked list
void UntrackAudioBuffer(AudioBuffer *audioBuffer) void UntrackAudioBuffer(AudioBuffer *buffer)
{ {
ma_mutex_lock(&audioLock); ma_mutex_lock(&audioLock);
{ {
if (audioBuffer->prev == NULL) firstAudioBuffer = audioBuffer->next; if (buffer->prev == NULL) firstAudioBuffer = buffer->next;
else audioBuffer->prev->next = audioBuffer->next; else buffer->prev->next = buffer->next;
if (audioBuffer->next == NULL) lastAudioBuffer = audioBuffer->prev; if (buffer->next == NULL) lastAudioBuffer = buffer->prev;
else audioBuffer->next->prev = audioBuffer->prev; else buffer->next->prev = buffer->prev;
audioBuffer->prev = NULL; buffer->prev = NULL;
audioBuffer->next = NULL; buffer->next = NULL;
} }
ma_mutex_unlock(&audioLock); ma_mutex_unlock(&audioLock);
} }
@ -802,10 +778,9 @@ Wave LoadWave(const char *fileName)
{ {
Wave wave = { 0 }; Wave wave = { 0 };
#if defined(SUPPORT_FILEFORMAT_WAV)
if (IsFileExtension(fileName, ".wav")) wave = LoadWAV(fileName);
#else
if (false) { } if (false) { }
#if defined(SUPPORT_FILEFORMAT_WAV)
else if (IsFileExtension(fileName, ".wav")) wave = LoadWAV(fileName);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
else if (IsFileExtension(fileName, ".ogg")) wave = LoadOGG(fileName); else if (IsFileExtension(fileName, ".ogg")) wave = LoadOGG(fileName);
@ -821,25 +796,6 @@ Wave LoadWave(const char *fileName)
return wave; return wave;
} }
// Load wave data from raw array data
Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels)
{
Wave wave;
wave.data = data;
wave.sampleCount = sampleCount;
wave.sampleRate = sampleRate;
wave.sampleSize = sampleSize;
wave.channels = channels;
// NOTE: Copy wave data to work with, user is responsible of input data to free
Wave cwave = WaveCopy(wave);
WaveFormat(&cwave, sampleRate, sampleSize, channels);
return cwave;
}
// Load sound from file // Load sound from file
// NOTE: The entire file is loaded to memory to be played (no-streaming) // NOTE: The entire file is loaded to memory to be played (no-streaming)
Sound LoadSound(const char *fileName) Sound LoadSound(const char *fileName)
@ -903,7 +859,7 @@ void UnloadWave(Wave wave)
// Unload sound // Unload sound
void UnloadSound(Sound sound) void UnloadSound(Sound sound)
{ {
CloseAudioBuffer((AudioBuffer *)sound.stream.buffer); CloseAudioBuffer(sound.stream.buffer);
TraceLog(LOG_INFO, "Unloaded sound data from RAM"); TraceLog(LOG_INFO, "Unloaded sound data from RAM");
} }
@ -911,7 +867,7 @@ void UnloadSound(Sound sound)
// Update sound buffer with new data // Update sound buffer with new data
void UpdateSound(Sound sound, const void *data, int samplesCount) void UpdateSound(Sound sound, const void *data, int samplesCount)
{ {
AudioBuffer *audioBuffer = (AudioBuffer *)sound.stream.buffer; AudioBuffer *audioBuffer = sound.stream.buffer;
if (audioBuffer == NULL) if (audioBuffer == NULL)
{ {
@ -930,10 +886,9 @@ void ExportWave(Wave wave, const char *fileName)
{ {
bool success = false; bool success = false;
#if defined(SUPPORT_FILEFORMAT_WAV)
if (IsFileExtension(fileName, ".wav")) success = SaveWAV(wave, fileName);
#else
if (false) { } if (false) { }
#if defined(SUPPORT_FILEFORMAT_WAV)
else if (IsFileExtension(fileName, ".wav")) success = SaveWAV(wave, fileName);
#endif #endif
else if (IsFileExtension(fileName, ".raw")) else if (IsFileExtension(fileName, ".raw"))
{ {
@ -994,7 +949,7 @@ void ExportWaveAsCode(Wave wave, const char *fileName)
// Play a sound // Play a sound
void PlaySound(Sound sound) void PlaySound(Sound sound)
{ {
PlayAudioBuffer((AudioBuffer *)sound.stream.buffer); PlayAudioBuffer(sound.stream.buffer);
} }
// Play a sound in the multichannel buffer pool // Play a sound in the multichannel buffer pool
@ -1046,17 +1001,16 @@ void PlaySoundMulti(Sound sound)
audioBufferPoolChannels[index] = audioBufferPoolCounter; audioBufferPoolChannels[index] = audioBufferPoolCounter;
audioBufferPoolCounter++; audioBufferPoolCounter++;
audioBufferPool[index]->volume = ((AudioBuffer*)sound.stream.buffer)->volume; audioBufferPool[index]->volume = sound.stream.buffer->volume;
audioBufferPool[index]->pitch = ((AudioBuffer*)sound.stream.buffer)->pitch; audioBufferPool[index]->pitch = sound.stream.buffer->pitch;
audioBufferPool[index]->looping = ((AudioBuffer*)sound.stream.buffer)->looping; audioBufferPool[index]->looping = sound.stream.buffer->looping;
audioBufferPool[index]->usage = ((AudioBuffer*)sound.stream.buffer)->usage; audioBufferPool[index]->usage = sound.stream.buffer->usage;
audioBufferPool[index]->isSubBufferProcessed[0] = false; audioBufferPool[index]->isSubBufferProcessed[0] = false;
audioBufferPool[index]->isSubBufferProcessed[1] = false; audioBufferPool[index]->isSubBufferProcessed[1] = false;
audioBufferPool[index]->bufferSizeInFrames = ((AudioBuffer*)sound.stream.buffer)->bufferSizeInFrames; audioBufferPool[index]->bufferSizeInFrames = sound.stream.buffer->bufferSizeInFrames;
audioBufferPool[index]->buffer = ((AudioBuffer*)sound.stream.buffer)->buffer; audioBufferPool[index]->buffer = sound.stream.buffer->buffer;
PlayAudioBuffer(audioBufferPool[index]); PlayAudioBuffer(audioBufferPool[index]);
} }
// Stop any sound played with PlaySoundMulti() // Stop any sound played with PlaySoundMulti()
@ -1081,37 +1035,37 @@ int GetSoundsPlaying(void)
// Pause a sound // Pause a sound
void PauseSound(Sound sound) void PauseSound(Sound sound)
{ {
PauseAudioBuffer((AudioBuffer *)sound.stream.buffer); PauseAudioBuffer(sound.stream.buffer);
} }
// Resume a paused sound // Resume a paused sound
void ResumeSound(Sound sound) void ResumeSound(Sound sound)
{ {
ResumeAudioBuffer((AudioBuffer *)sound.stream.buffer); ResumeAudioBuffer(sound.stream.buffer);
} }
// Stop reproducing a sound // Stop reproducing a sound
void StopSound(Sound sound) void StopSound(Sound sound)
{ {
StopAudioBuffer((AudioBuffer *)sound.stream.buffer); StopAudioBuffer(sound.stream.buffer);
} }
// Check if a sound is playing // Check if a sound is playing
bool IsSoundPlaying(Sound sound) bool IsSoundPlaying(Sound sound)
{ {
return IsAudioBufferPlaying((AudioBuffer *)sound.stream.buffer); return IsAudioBufferPlaying(sound.stream.buffer);
} }
// Set volume for a sound // Set volume for a sound
void SetSoundVolume(Sound sound, float volume) void SetSoundVolume(Sound sound, float volume)
{ {
SetAudioBufferVolume((AudioBuffer *)sound.stream.buffer, volume); SetAudioBufferVolume(sound.stream.buffer, volume);
} }
// Set pitch for a sound // Set pitch for a sound
void SetSoundPitch(Sound sound, float pitch) void SetSoundPitch(Sound sound, float pitch)
{ {
SetAudioBufferPitch((AudioBuffer *)sound.stream.buffer, pitch); SetAudioBufferPitch(sound.stream.buffer, pitch);
} }
// Convert wave data to desired format // Convert wave data to desired format
@ -1212,53 +1166,52 @@ float *GetWaveData(Wave wave)
// Load music stream from file // Load music stream from file
Music LoadMusicStream(const char *fileName) Music LoadMusicStream(const char *fileName)
{ {
Music music = (MusicStream *)RL_MALLOC(sizeof(MusicStream)); Music music = { 0 };
bool musicLoaded = true; bool musicLoaded = false;
if (false) { }
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
if (IsFileExtension(fileName, ".ogg")) else if (IsFileExtension(fileName, ".ogg"))
{ {
// Open ogg audio stream // Open ogg audio stream
music->ctxData = stb_vorbis_open_filename(fileName, NULL, NULL); music.ctxData = stb_vorbis_open_filename(fileName, NULL, NULL);
if (music->ctxData == NULL) musicLoaded = false; if (music.ctxData != NULL)
else
{ {
stb_vorbis_info info = stb_vorbis_get_info((stb_vorbis *)music->ctxData); // Get Ogg file info music.ctxType = MUSIC_AUDIO_OGG;
stb_vorbis_info info = stb_vorbis_get_info((stb_vorbis *)music.ctxData); // Get Ogg file info
// OGG bit rate defaults to 16 bit, it's enough for compressed format // OGG bit rate defaults to 16 bit, it's enough for compressed format
music->stream = InitAudioStream(info.sample_rate, 16, info.channels); music.stream = InitAudioStream(info.sample_rate, 16, info.channels);
music->sampleCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music->ctxData)*info.channels; music.sampleCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData)*info.channels;
music->sampleLeft = music->sampleCount; music.sampleLeft = music.sampleCount;
music->ctxType = MUSIC_AUDIO_OGG; music.loopCount = 0; // Infinite loop by default
music->loopCount = 0; // Infinite loop by default musicLoaded = true;
TraceLog(LOG_DEBUG, "[%s] OGG total samples: %i", fileName, music->sampleCount); TraceLog(LOG_DEBUG, "[%s] OGG total samples: %i", fileName, music.sampleCount);
TraceLog(LOG_DEBUG, "[%s] OGG sample rate: %i", fileName, info.sample_rate); TraceLog(LOG_DEBUG, "[%s] OGG sample rate: %i", fileName, info.sample_rate);
TraceLog(LOG_DEBUG, "[%s] OGG channels: %i", fileName, info.channels); TraceLog(LOG_DEBUG, "[%s] OGG channels: %i", fileName, info.channels);
TraceLog(LOG_DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required); TraceLog(LOG_DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required);
} }
} }
#else
if (false) {}
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
else if (IsFileExtension(fileName, ".flac")) else if (IsFileExtension(fileName, ".flac"))
{ {
music->ctxData = drflac_open_file(fileName); music.ctxData = drflac_open_file(fileName);
if (music->ctxData == NULL) musicLoaded = false; if (music.ctxData != NULL)
else
{ {
drflac *ctxFlac = (drflac *)music->ctxData; music.ctxType = MUSIC_AUDIO_FLAC;
drflac *ctxFlac = (drflac *)music.ctxData;
music->stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels); music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels);
music->sampleCount = (unsigned int)ctxFlac->totalSampleCount; music.sampleCount = (unsigned int)ctxFlac->totalSampleCount;
music->sampleLeft = music->sampleCount; music.sampleLeft = music.sampleCount;
music->ctxType = MUSIC_AUDIO_FLAC; music.loopCount = 0; // Infinite loop by default
music->loopCount = 0; // Infinite loop by default musicLoaded = true;
TraceLog(LOG_DEBUG, "[%s] FLAC total samples: %i", fileName, music->sampleCount); TraceLog(LOG_DEBUG, "[%s] FLAC total samples: %i", fileName, music.sampleCount);
TraceLog(LOG_DEBUG, "[%s] FLAC sample rate: %i", fileName, ctxFlac->sampleRate); TraceLog(LOG_DEBUG, "[%s] FLAC sample rate: %i", fileName, ctxFlac->sampleRate);
TraceLog(LOG_DEBUG, "[%s] FLAC bits per sample: %i", fileName, ctxFlac->bitsPerSample); TraceLog(LOG_DEBUG, "[%s] FLAC bits per sample: %i", fileName, ctxFlac->bitsPerSample);
TraceLog(LOG_DEBUG, "[%s] FLAC channels: %i", fileName, ctxFlac->channels); TraceLog(LOG_DEBUG, "[%s] FLAC channels: %i", fileName, ctxFlac->channels);
@ -1269,24 +1222,24 @@ Music LoadMusicStream(const char *fileName)
else if (IsFileExtension(fileName, ".mp3")) else if (IsFileExtension(fileName, ".mp3"))
{ {
drmp3 *ctxMp3 = RL_MALLOC(sizeof(drmp3)); drmp3 *ctxMp3 = RL_MALLOC(sizeof(drmp3));
music->ctxData = ctxMp3; music.ctxData = ctxMp3;
int result = drmp3_init_file(ctxMp3, fileName, NULL); int result = drmp3_init_file(ctxMp3, fileName, NULL);
if (!result) musicLoaded = false; if (result > 0)
else
{ {
music.ctxType = MUSIC_AUDIO_MP3;
music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels);
music.sampleCount = drmp3_get_pcm_frame_count(ctxMp3)*ctxMp3->channels;
music.sampleLeft = music.sampleCount;
music.loopCount = 0; // Infinite loop by default
musicLoaded = true;
TraceLog(LOG_INFO, "[%s] MP3 sample rate: %i", fileName, ctxMp3->sampleRate); TraceLog(LOG_INFO, "[%s] MP3 sample rate: %i", fileName, ctxMp3->sampleRate);
TraceLog(LOG_INFO, "[%s] MP3 bits per sample: %i", fileName, 32); TraceLog(LOG_INFO, "[%s] MP3 bits per sample: %i", fileName, 32);
TraceLog(LOG_INFO, "[%s] MP3 channels: %i", fileName, ctxMp3->channels); TraceLog(LOG_INFO, "[%s] MP3 channels: %i", fileName, ctxMp3->channels);
TraceLog(LOG_INFO, "[%s] MP3 total samples: %i", fileName, music.sampleCount);
music->stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels);
music->sampleCount = drmp3_get_pcm_frame_count(ctxMp3)*ctxMp3->channels;
music->sampleLeft = music->sampleCount;
music->ctxType = MUSIC_AUDIO_MP3;
music->loopCount = 0; // Infinite loop by default
TraceLog(LOG_INFO, "[%s] MP3 total samples: %i", fileName, music->sampleCount);
} }
} }
#endif #endif
@ -1297,73 +1250,70 @@ Music LoadMusicStream(const char *fileName)
int result = jar_xm_create_context_from_file(&ctxXm, 48000, fileName); int result = jar_xm_create_context_from_file(&ctxXm, 48000, fileName);
if (!result) // XM context created successfully if (result > 0) // XM context created successfully
{ {
music.ctxType = MUSIC_MODULE_XM;
jar_xm_set_max_loop_count(ctxXm, 0); // Set infinite number of loops jar_xm_set_max_loop_count(ctxXm, 0); // Set infinite number of loops
// NOTE: Only stereo is supported for XM // NOTE: Only stereo is supported for XM
music->stream = InitAudioStream(48000, 16, 2); music.stream = InitAudioStream(48000, 16, 2);
music->sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm); music.sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm);
music->sampleLeft = music->sampleCount; music.sampleLeft = music.sampleCount;
music->ctxType = MUSIC_MODULE_XM; music.loopCount = 0; // Infinite loop by default
music->loopCount = 0; // Infinite loop by default musicLoaded = true;
TraceLog(LOG_INFO, "[%s] XM number of samples: %i", fileName, music->sampleCount); music.ctxData = ctxXm;
TraceLog(LOG_INFO, "[%s] XM track length: %11.6f sec", fileName, (float)music->sampleCount/48000.0f);
music->ctxData = ctxXm; TraceLog(LOG_INFO, "[%s] XM number of samples: %i", fileName, music.sampleCount);
TraceLog(LOG_INFO, "[%s] XM track length: %11.6f sec", fileName, (float)music.sampleCount/48000.0f);
} }
else musicLoaded = false;
} }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MOD) #if defined(SUPPORT_FILEFORMAT_MOD)
else if (IsFileExtension(fileName, ".mod")) else if (IsFileExtension(fileName, ".mod"))
{ {
jar_mod_context_t *ctxMod = RL_MALLOC(sizeof(jar_mod_context_t)); jar_mod_context_t *ctxMod = RL_MALLOC(sizeof(jar_mod_context_t));
music->ctxData = ctxMod; music.ctxData = ctxMod;
jar_mod_init(ctxMod); jar_mod_init(ctxMod);
int result = jar_mod_load_file(ctxMod, fileName);
if (jar_mod_load_file(ctxMod, fileName)) if (result > 0)
{ {
// NOTE: Only stereo is supported for MOD music.ctxType = MUSIC_MODULE_MOD;
music->stream = InitAudioStream(48000, 16, 2);
music->sampleCount = (unsigned int)jar_mod_max_samples(ctxMod);
music->sampleLeft = music->sampleCount;
music->ctxType = MUSIC_MODULE_MOD;
music->loopCount = 0; // Infinite loop by default
TraceLog(LOG_INFO, "[%s] MOD number of samples: %i", fileName, music->sampleLeft); // NOTE: Only stereo is supported for MOD
TraceLog(LOG_INFO, "[%s] MOD track length: %11.6f sec", fileName, (float)music->sampleCount/48000.0f); music.stream = InitAudioStream(48000, 16, 2);
music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod);
music.sampleLeft = music.sampleCount;
music.loopCount = 0; // Infinite loop by default
musicLoaded = true;
TraceLog(LOG_INFO, "[%s] MOD number of samples: %i", fileName, music.sampleLeft);
TraceLog(LOG_INFO, "[%s] MOD track length: %11.6f sec", fileName, (float)music.sampleCount/48000.0f);
} }
else musicLoaded = false;
} }
#endif #endif
else musicLoaded = false;
if (!musicLoaded) if (!musicLoaded)
{ {
#if defined(SUPPORT_FILEFORMAT_OGG)
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music->ctxData);
#else
if (false) { } if (false) { }
#if defined(SUPPORT_FILEFORMAT_OGG)
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music->ctxData); else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
else if (music->ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music->ctxData); RL_FREE(music->ctxData); } else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_XM) #if defined(SUPPORT_FILEFORMAT_XM)
else if (music->ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music->ctxData); else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MOD) #if defined(SUPPORT_FILEFORMAT_MOD)
else if (music->ctxType == MUSIC_MODULE_MOD) { jar_mod_unload((jar_mod_context_t *)music->ctxData); RL_FREE(music->ctxData); } else if (music.ctxType == MUSIC_MODULE_MOD) { jar_mod_unload((jar_mod_context_t *)music.ctxData); RL_FREE(music.ctxData); }
#endif #endif
RL_FREE(music);
music = NULL;
TraceLog(LOG_WARNING, "[%s] Music file could not be opened", fileName); TraceLog(LOG_WARNING, "[%s] Music file could not be opened", fileName);
} }
@ -1373,37 +1323,30 @@ Music LoadMusicStream(const char *fileName)
// Unload music stream // Unload music stream
void UnloadMusicStream(Music music) void UnloadMusicStream(Music music)
{ {
if (music == NULL) return; CloseAudioStream(music.stream);
CloseAudioStream(music->stream);
#if defined(SUPPORT_FILEFORMAT_OGG)
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music->ctxData);
#else
if (false) { } if (false) { }
#if defined(SUPPORT_FILEFORMAT_OGG)
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music->ctxData); else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
else if (music->ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music->ctxData); RL_FREE(music->ctxData); } else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_XM) #if defined(SUPPORT_FILEFORMAT_XM)
else if (music->ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music->ctxData); else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MOD) #if defined(SUPPORT_FILEFORMAT_MOD)
else if (music->ctxType == MUSIC_MODULE_MOD) { jar_mod_unload((jar_mod_context_t *)music->ctxData); RL_FREE(music->ctxData); } else if (music.ctxType == MUSIC_MODULE_MOD) { jar_mod_unload((jar_mod_context_t *)music.ctxData); RL_FREE(music.ctxData); }
#endif #endif
RL_FREE(music);
} }
// Start music playing (open stream) // Start music playing (open stream)
void PlayMusicStream(Music music) void PlayMusicStream(Music music)
{ {
if (music != NULL) AudioBuffer *audioBuffer = music.stream.buffer;
{
AudioBuffer *audioBuffer = (AudioBuffer *)music->stream.buffer;
if (audioBuffer == NULL) if (audioBuffer == NULL)
{ {
@ -1417,81 +1360,76 @@ void PlayMusicStream(Music music)
// if (IsMusicPlaying(music)) PlayMusicStream(music); // if (IsMusicPlaying(music)) PlayMusicStream(music);
ma_uint32 frameCursorPos = audioBuffer->frameCursorPos; ma_uint32 frameCursorPos = audioBuffer->frameCursorPos;
PlayAudioStream(music->stream); // <-- This resets the cursor position. PlayAudioStream(music.stream); // <-- This resets the cursor position.
audioBuffer->frameCursorPos = frameCursorPos; audioBuffer->frameCursorPos = frameCursorPos;
} }
}
// Pause music playing // Pause music playing
void PauseMusicStream(Music music) void PauseMusicStream(Music music)
{ {
if (music != NULL) PauseAudioStream(music->stream); PauseAudioStream(music.stream);
} }
// Resume music playing // Resume music playing
void ResumeMusicStream(Music music) void ResumeMusicStream(Music music)
{ {
if (music != NULL) ResumeAudioStream(music->stream); ResumeAudioStream(music.stream);
} }
// Stop music playing (close stream) // Stop music playing (close stream)
void StopMusicStream(Music music) void StopMusicStream(Music music)
{ {
if (music == NULL) return; StopAudioStream(music.stream);
StopAudioStream(music->stream);
// Restart music context // Restart music context
switch (music->ctxType) switch (music.ctxType)
{ {
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music->ctxData); break; case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break;
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_AUDIO_FLAC: /* TODO: Restart FLAC context */ break; case MUSIC_AUDIO_FLAC: /* TODO: Restart FLAC context */ break;
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
case MUSIC_AUDIO_MP3: drmp3_seek_to_pcm_frame((drmp3 *)music->ctxData, 0); break; case MUSIC_AUDIO_MP3: drmp3_seek_to_pcm_frame((drmp3 *)music.ctxData, 0); break;
#endif #endif
#if defined(SUPPORT_FILEFORMAT_XM) #if defined(SUPPORT_FILEFORMAT_XM)
case MUSIC_MODULE_XM: jar_xm_reset((jar_xm_context_t *)music->ctxData); break; case MUSIC_MODULE_XM: jar_xm_reset((jar_xm_context_t *)music.ctxData); break;
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MOD) #if defined(SUPPORT_FILEFORMAT_MOD)
case MUSIC_MODULE_MOD: jar_mod_seek_start((jar_mod_context_t *)music->ctxData); break; case MUSIC_MODULE_MOD: jar_mod_seek_start((jar_mod_context_t *)music.ctxData); break;
#endif #endif
default: break; default: break;
} }
music->sampleLeft = music->sampleCount; music.sampleLeft = music.sampleCount;
} }
// Update (re-fill) music buffers if data already processed // Update (re-fill) music buffers if data already processed
void UpdateMusicStream(Music music) void UpdateMusicStream(Music music)
{ {
if (music == NULL) return;
bool streamEnding = false; bool streamEnding = false;
unsigned int subBufferSizeInFrames = ((AudioBuffer *)music->stream.buffer)->bufferSizeInFrames/2; unsigned int subBufferSizeInFrames = music.stream.buffer->bufferSizeInFrames/2;
// NOTE: Using dynamic allocation because it could require more than 16KB // NOTE: Using dynamic allocation because it could require more than 16KB
void *pcm = RL_CALLOC(subBufferSizeInFrames*music->stream.channels*music->stream.sampleSize/8, 1); void *pcm = RL_CALLOC(subBufferSizeInFrames*music.stream.channels*music.stream.sampleSize/8, 1);
int samplesCount = 0; // Total size of data steamed in L+R samples for xm floats, individual L or R for ogg shorts int samplesCount = 0; // Total size of data steamed in L+R samples for xm floats, individual L or R for ogg shorts
while (IsAudioBufferProcessed(music->stream)) while (IsAudioBufferProcessed(music.stream))
{ {
if ((music->sampleLeft/music->stream.channels) >= subBufferSizeInFrames) samplesCount = subBufferSizeInFrames*music->stream.channels; if ((music.sampleLeft/music.stream.channels) >= subBufferSizeInFrames) samplesCount = subBufferSizeInFrames*music.stream.channels;
else samplesCount = music->sampleLeft; else samplesCount = music.sampleLeft;
switch (music->ctxType) switch (music.ctxType)
{ {
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
case MUSIC_AUDIO_OGG: case MUSIC_AUDIO_OGG:
{ {
// NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!) // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!)
stb_vorbis_get_samples_short_interleaved((stb_vorbis *)music->ctxData, music->stream.channels, (short *)pcm, samplesCount); stb_vorbis_get_samples_short_interleaved((stb_vorbis *)music.ctxData, music.stream.channels, (short *)pcm, samplesCount);
} break; } break;
#endif #endif
@ -1499,7 +1437,7 @@ void UpdateMusicStream(Music music)
case MUSIC_AUDIO_FLAC: case MUSIC_AUDIO_FLAC:
{ {
// NOTE: Returns the number of samples to process (not required) // NOTE: Returns the number of samples to process (not required)
drflac_read_s16((drflac *)music->ctxData, samplesCount, (short *)pcm); drflac_read_s16((drflac *)music.ctxData, samplesCount, (short *)pcm);
} break; } break;
#endif #endif
@ -1507,7 +1445,7 @@ void UpdateMusicStream(Music music)
case MUSIC_AUDIO_MP3: case MUSIC_AUDIO_MP3:
{ {
// NOTE: samplesCount, actually refers to framesCount and returns the number of frames processed // NOTE: samplesCount, actually refers to framesCount and returns the number of frames processed
drmp3_read_pcm_frames_f32((drmp3 *)music->ctxData, samplesCount/music->stream.channels, (float *)pcm); drmp3_read_pcm_frames_f32((drmp3 *)music.ctxData, samplesCount/music.stream.channels, (float *)pcm);
} break; } break;
#endif #endif
@ -1515,29 +1453,29 @@ void UpdateMusicStream(Music music)
case MUSIC_MODULE_XM: case MUSIC_MODULE_XM:
{ {
// NOTE: Internally this function considers 2 channels generation, so samplesCount/2 // NOTE: Internally this function considers 2 channels generation, so samplesCount/2
jar_xm_generate_samples_16bit((jar_xm_context_t *)music->ctxData, (short *)pcm, samplesCount/2); jar_xm_generate_samples_16bit((jar_xm_context_t *)music.ctxData, (short *)pcm, samplesCount/2);
} break; } break;
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MOD) #if defined(SUPPORT_FILEFORMAT_MOD)
case MUSIC_MODULE_MOD: case MUSIC_MODULE_MOD:
{ {
// NOTE: 3rd parameter (nbsample) specify the number of stereo 16bits samples you want, so sampleCount/2 // NOTE: 3rd parameter (nbsample) specify the number of stereo 16bits samples you want, so sampleCount/2
jar_mod_fillbuffer((jar_mod_context_t *)music->ctxData, (short *)pcm, samplesCount/2, 0); jar_mod_fillbuffer((jar_mod_context_t *)music.ctxData, (short *)pcm, samplesCount/2, 0);
} break; } break;
#endif #endif
default: break; default: break;
} }
UpdateAudioStream(music->stream, pcm, samplesCount); UpdateAudioStream(music.stream, pcm, samplesCount);
if ((music->ctxType == MUSIC_MODULE_XM) || (music->ctxType == MUSIC_MODULE_MOD)) if ((music.ctxType == MUSIC_MODULE_XM) || (music.ctxType == MUSIC_MODULE_MOD))
{ {
if (samplesCount > 1) music->sampleLeft -= samplesCount/2; if (samplesCount > 1) music.sampleLeft -= samplesCount/2;
else music->sampleLeft -= samplesCount; else music.sampleLeft -= samplesCount;
} }
else music->sampleLeft -= samplesCount; else music.sampleLeft -= samplesCount;
if (music->sampleLeft <= 0) if (music.sampleLeft <= 0)
{ {
streamEnding = true; streamEnding = true;
break; break;
@ -1553,14 +1491,14 @@ void UpdateMusicStream(Music music)
StopMusicStream(music); // Stop music (and reset) StopMusicStream(music); // Stop music (and reset)
// Decrease loopCount to stop when required // Decrease loopCount to stop when required
if (music->loopCount > 1) if (music.loopCount > 1)
{ {
music->loopCount--; // Decrease loop count music.loopCount--; // Decrease loop count
PlayMusicStream(music); // Play again PlayMusicStream(music); // Play again
} }
else else
{ {
if (music->loopCount == 0) PlayMusicStream(music); if (music.loopCount == 0) PlayMusicStream(music);
} }
} }
else else
@ -1574,27 +1512,26 @@ void UpdateMusicStream(Music music)
// Check if any music is playing // Check if any music is playing
bool IsMusicPlaying(Music music) bool IsMusicPlaying(Music music)
{ {
if (music == NULL) return false; return IsAudioStreamPlaying(music.stream);
else return IsAudioStreamPlaying(music->stream);
} }
// Set volume for music // Set volume for music
void SetMusicVolume(Music music, float volume) void SetMusicVolume(Music music, float volume)
{ {
if (music != NULL) SetAudioStreamVolume(music->stream, volume); SetAudioStreamVolume(music.stream, volume);
} }
// Set pitch for music // Set pitch for music
void SetMusicPitch(Music music, float pitch) void SetMusicPitch(Music music, float pitch)
{ {
if (music != NULL) SetAudioStreamPitch(music->stream, pitch); SetAudioStreamPitch(music.stream, pitch);
} }
// Set music loop count (loop repeats) // Set music loop count (loop repeats)
// NOTE: If set to -1, means infinite loop // NOTE: If set to -1, means infinite loop
void SetMusicLoopCount(Music music, int count) void SetMusicLoopCount(Music music, int count)
{ {
if (music != NULL) music->loopCount = count; music.loopCount = count;
} }
// Get music time length (in seconds) // Get music time length (in seconds)
@ -1602,7 +1539,7 @@ float GetMusicTimeLength(Music music)
{ {
float totalSeconds = 0.0f; float totalSeconds = 0.0f;
if (music != NULL) totalSeconds = (float)music->sampleCount/(music->stream.sampleRate*music->stream.channels); totalSeconds = (float)music.sampleCount/(music.stream.sampleRate*music.stream.channels);
return totalSeconds; return totalSeconds;
} }
@ -1612,11 +1549,8 @@ float GetMusicTimePlayed(Music music)
{ {
float secondsPlayed = 0.0f; float secondsPlayed = 0.0f;
if (music != NULL) unsigned int samplesPlayed = music.sampleCount - music.sampleLeft;
{ secondsPlayed = (float)samplesPlayed/(music.stream.sampleRate*music.stream.channels);
unsigned int samplesPlayed = music->sampleCount - music->sampleLeft;
secondsPlayed = (float)samplesPlayed/(music->stream.sampleRate*music->stream.channels);
}
return secondsPlayed; return secondsPlayed;
} }

View File

@ -80,25 +80,14 @@
// Wave type, defines audio wave data // Wave type, defines audio wave data
typedef struct Wave { typedef struct Wave {
unsigned int sampleCount; // Number of samples unsigned int sampleCount; // Total number of samples
unsigned int sampleRate; // Frequency (samples per second) unsigned int sampleRate; // Frequency (samples per second)
unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
unsigned int channels; // Number of channels (1-mono, 2-stereo) unsigned int channels; // Number of channels (1-mono, 2-stereo)
void *data; // Buffer data pointer void *data; // Buffer data pointer
} Wave; } Wave;
// Sound source type typedef struct rAudioBuffer rAudioBuffer;
typedef struct Sound {
void *audioBuffer; // Pointer to internal data used by the audio system
unsigned int source; // Audio source id
unsigned int buffer; // Audio buffer id
int format; // Audio format specifier
} Sound;
// Music type (file streaming from memory)
// NOTE: Anything longer than ~10 seconds should be streamed
typedef struct MusicData *Music;
// Audio stream type // Audio stream type
// NOTE: Useful to create custom audio streams not bound to a specific file // NOTE: Useful to create custom audio streams not bound to a specific file
@ -107,13 +96,28 @@ typedef struct AudioStream {
unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
unsigned int channels; // Number of channels (1-mono, 2-stereo) unsigned int channels; // Number of channels (1-mono, 2-stereo)
void *audioBuffer; // Pointer to internal data used by the audio system. rAudioBuffer *buffer; // Pointer to internal data used by the audio system
int format; // Audio format specifier
unsigned int source; // Audio source id
unsigned int buffers[2]; // Audio buffers (double buffering)
} AudioStream; } AudioStream;
// Sound source type
typedef struct Sound {
unsigned int sampleCount; // Total number of samples
AudioStream stream; // Audio stream
} Sound;
// Music stream type (audio file streaming from memory)
// NOTE: Anything longer than ~10 seconds should be streamed
typedef struct Music {
int ctxType; // Type of music context (audio filetype)
void *ctxData; // Audio context data, depends on type
unsigned int sampleCount; // Total number of samples
unsigned int sampleLeft; // Number of samples left to end
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
AudioStream stream; // Audio stream
} Music;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { // Prevents name mangling of functions extern "C" { // Prevents name mangling of functions
#endif #endif
@ -126,25 +130,31 @@ extern "C" { // Prevents name mangling of functions
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Declaration // Module Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Audio device management functions
void InitAudioDevice(void); // Initialize audio device and context void InitAudioDevice(void); // Initialize audio device and context
void CloseAudioDevice(void); // Close the audio device and context void CloseAudioDevice(void); // Close the audio device and context
bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully
void SetMasterVolume(float volume); // Set master volume (listener) void SetMasterVolume(float volume); // Set master volume (listener)
// Wave/Sound loading/unloading functions
Wave LoadWave(const char *fileName); // Load wave data from file Wave LoadWave(const char *fileName); // Load wave data from file
Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data
Sound LoadSound(const char *fileName); // Load sound from file Sound LoadSound(const char *fileName); // Load sound from file
Sound LoadSoundFromWave(Wave wave); // Load sound from wave data Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data
void UnloadWave(Wave wave); // Unload wave data void UnloadWave(Wave wave); // Unload wave data
void UnloadSound(Sound sound); // Unload sound void UnloadSound(Sound sound); // Unload sound
void ExportWave(Wave wave, const char *fileName); // Export wave data to file
void ExportWaveAsCode(Wave wave, const char *fileName); // Export wave sample data to code (.h)
// Wave/Sound management functions
void PlaySound(Sound sound); // Play a sound void PlaySound(Sound sound); // Play a sound
void PlaySoundMulti(Sound sound); // Play a sound using the multi channel buffer pool void StopSound(Sound sound); // Stop playing a sound
int GetSoundsPlaying(void); // Get number of sounds playing in the multichannel buffer pool
void PauseSound(Sound sound); // Pause a sound void PauseSound(Sound sound); // Pause a sound
void ResumeSound(Sound sound); // Resume a paused sound void ResumeSound(Sound sound); // Resume a paused sound
void StopSound(Sound sound); // Stop playing a sound void PlaySoundMulti(Sound sound); // Play a sound (using multichannel buffer pool)
void StopSoundMulti(void); // Stop any sound played with PlaySoundMulti() void StopSoundMulti(void); // Stop any sound playing (using multichannel buffer pool)
int GetSoundsPlaying(void); // Get number of sounds playing in the multichannel
bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing
void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level)
void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)
@ -152,6 +162,8 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // C
Wave WaveCopy(Wave wave); // Copy a wave to a new wave Wave WaveCopy(Wave wave); // Copy a wave to a new wave
void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range
float *GetWaveData(Wave wave); // Get samples data from wave as a floats array float *GetWaveData(Wave wave); // Get samples data from wave as a floats array
// Music management functions
Music LoadMusicStream(const char *fileName); // Load music stream from file Music LoadMusicStream(const char *fileName); // Load music stream from file
void UnloadMusicStream(Music music); // Unload music stream void UnloadMusicStream(Music music); // Unload music stream
void PlayMusicStream(Music music); // Start music playing void PlayMusicStream(Music music); // Start music playing
@ -167,9 +179,7 @@ float GetMusicTimeLength(Music music); // Get music tim
float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
// AudioStream management functions // AudioStream management functions
AudioStream InitAudioStream(unsigned int sampleRate, AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream raw audio pcm data)
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 UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data
void CloseAudioStream(AudioStream stream); // Close audio stream and free memory void CloseAudioStream(AudioStream stream); // Close audio stream and free memory
bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill

View File

@ -114,40 +114,40 @@
// NOTE: MSC C++ compiler does not support compound literals (C99 feature) // NOTE: MSC C++ compiler does not support compound literals (C99 feature)
// Plain structures in C++ (without constructors) can be initialized from { } initializers. // Plain structures in C++ (without constructors) can be initialized from { } initializers.
#if defined(__cplusplus) #if defined(__cplusplus)
#define CLITERAL #define CLITERAL(type) type
#else #else
#define CLITERAL (Color) #define CLITERAL(type) (type)
#endif #endif
// Some Basic Colors // Some Basic Colors
// NOTE: Custom raylib color palette for amazing visuals on WHITE background // NOTE: Custom raylib color palette for amazing visuals on WHITE background
#define LIGHTGRAY CLITERAL{ 200, 200, 200, 255 } // Light Gray #define LIGHTGRAY CLITERAL(Color){ 200, 200, 200, 255 } // Light Gray
#define GRAY CLITERAL{ 130, 130, 130, 255 } // Gray #define GRAY CLITERAL(Color){ 130, 130, 130, 255 } // Gray
#define DARKGRAY CLITERAL{ 80, 80, 80, 255 } // Dark Gray #define DARKGRAY CLITERAL(Color){ 80, 80, 80, 255 } // Dark Gray
#define YELLOW CLITERAL{ 253, 249, 0, 255 } // Yellow #define YELLOW CLITERAL(Color){ 253, 249, 0, 255 } // Yellow
#define GOLD CLITERAL{ 255, 203, 0, 255 } // Gold #define GOLD CLITERAL(Color){ 255, 203, 0, 255 } // Gold
#define ORANGE CLITERAL{ 255, 161, 0, 255 } // Orange #define ORANGE CLITERAL(Color){ 255, 161, 0, 255 } // Orange
#define PINK CLITERAL{ 255, 109, 194, 255 } // Pink #define PINK CLITERAL(Color){ 255, 109, 194, 255 } // Pink
#define RED CLITERAL{ 230, 41, 55, 255 } // Red #define RED CLITERAL(Color){ 230, 41, 55, 255 } // Red
#define MAROON CLITERAL{ 190, 33, 55, 255 } // Maroon #define MAROON CLITERAL(Color){ 190, 33, 55, 255 } // Maroon
#define GREEN CLITERAL{ 0, 228, 48, 255 } // Green #define GREEN CLITERAL(Color){ 0, 228, 48, 255 } // Green
#define LIME CLITERAL{ 0, 158, 47, 255 } // Lime #define LIME CLITERAL(Color){ 0, 158, 47, 255 } // Lime
#define DARKGREEN CLITERAL{ 0, 117, 44, 255 } // Dark Green #define DARKGREEN CLITERAL(Color){ 0, 117, 44, 255 } // Dark Green
#define SKYBLUE CLITERAL{ 102, 191, 255, 255 } // Sky Blue #define SKYBLUE CLITERAL(Color){ 102, 191, 255, 255 } // Sky Blue
#define BLUE CLITERAL{ 0, 121, 241, 255 } // Blue #define BLUE CLITERAL(Color){ 0, 121, 241, 255 } // Blue
#define DARKBLUE CLITERAL{ 0, 82, 172, 255 } // Dark Blue #define DARKBLUE CLITERAL(Color){ 0, 82, 172, 255 } // Dark Blue
#define PURPLE CLITERAL{ 200, 122, 255, 255 } // Purple #define PURPLE CLITERAL(Color){ 200, 122, 255, 255 } // Purple
#define VIOLET CLITERAL{ 135, 60, 190, 255 } // Violet #define VIOLET CLITERAL(Color){ 135, 60, 190, 255 } // Violet
#define DARKPURPLE CLITERAL{ 112, 31, 126, 255 } // Dark Purple #define DARKPURPLE CLITERAL(Color){ 112, 31, 126, 255 } // Dark Purple
#define BEIGE CLITERAL{ 211, 176, 131, 255 } // Beige #define BEIGE CLITERAL(Color){ 211, 176, 131, 255 } // Beige
#define BROWN CLITERAL{ 127, 106, 79, 255 } // Brown #define BROWN CLITERAL(Color){ 127, 106, 79, 255 } // Brown
#define DARKBROWN CLITERAL{ 76, 63, 47, 255 } // Dark Brown #define DARKBROWN CLITERAL(Color){ 76, 63, 47, 255 } // Dark Brown
#define WHITE CLITERAL{ 255, 255, 255, 255 } // White #define WHITE CLITERAL(Color){ 255, 255, 255, 255 } // White
#define BLACK CLITERAL{ 0, 0, 0, 255 } // Black #define BLACK CLITERAL(Color){ 0, 0, 0, 255 } // Black
#define BLANK CLITERAL{ 0, 0, 0, 0 } // Blank (Transparent) #define BLANK CLITERAL(Color){ 0, 0, 0, 0 } // Blank (Transparent)
#define MAGENTA CLITERAL{ 255, 0, 255, 255 } // Magenta #define MAGENTA CLITERAL(Color){ 255, 0, 255, 255 } // Magenta
#define RAYWHITE CLITERAL{ 245, 245, 245, 255 } // My own White (raylib logo) #define RAYWHITE CLITERAL(Color){ 245, 245, 245, 255 } // My own White (raylib logo)
// Temporal hack to avoid breaking old codebases using // Temporal hack to avoid breaking old codebases using
// deprecated raylib implementation of these functions // deprecated raylib implementation of these functions
@ -433,7 +433,7 @@ typedef struct Sound {
// Music stream type (audio file streaming from memory) // Music stream type (audio file streaming from memory)
// NOTE: Anything longer than ~10 seconds should be streamed // NOTE: Anything longer than ~10 seconds should be streamed
typedef struct MusicStream { typedef struct Music {
int ctxType; // Type of music context (audio filetype) int ctxType; // Type of music context (audio filetype)
void *ctxData; // Audio context data, depends on type void *ctxData; // Audio context data, depends on type
@ -442,7 +442,7 @@ typedef struct MusicStream {
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
AudioStream stream; // Audio stream AudioStream stream; // Audio stream
} MusicStream, *Music; } Music;
// Head-Mounted-Display device parameters // Head-Mounted-Display device parameters
typedef struct VrDeviceInfo { typedef struct VrDeviceInfo {
@ -1350,7 +1350,6 @@ RLAPI void SetMasterVolume(float volume); // Set mas
// Wave/Sound loading/unloading functions // Wave/Sound loading/unloading functions
RLAPI Wave LoadWave(const char *fileName); // Load wave data from file RLAPI Wave LoadWave(const char *fileName); // Load wave data from file
RLAPI Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data
RLAPI Sound LoadSound(const char *fileName); // Load sound from file RLAPI Sound LoadSound(const char *fileName); // Load sound from file
RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
RLAPI void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data RLAPI void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data
@ -1361,12 +1360,12 @@ RLAPI void ExportWaveAsCode(Wave wave, const char *fileName); // Export
// Wave/Sound management functions // Wave/Sound management functions
RLAPI void PlaySound(Sound sound); // Play a sound RLAPI void PlaySound(Sound sound); // Play a sound
RLAPI void PlaySoundMulti(Sound sound); // Play a sound using the multi channel buffer pool RLAPI void StopSound(Sound sound); // Stop playing a sound
RLAPI int GetSoundsPlaying(void); // Get number of sounds playing in the multichannel buffer pool
RLAPI void PauseSound(Sound sound); // Pause a sound RLAPI void PauseSound(Sound sound); // Pause a sound
RLAPI void ResumeSound(Sound sound); // Resume a paused sound RLAPI void ResumeSound(Sound sound); // Resume a paused sound
RLAPI void StopSound(Sound sound); // Stop playing a sound RLAPI void PlaySoundMulti(Sound sound); // Play a sound (using multichannel buffer pool)
RLAPI void StopSoundMulti(void); // Stop any sound played with PlaySoundMulti() RLAPI void StopSoundMulti(void); // Stop any sound playing (using multichannel buffer pool)
RLAPI int GetSoundsPlaying(void); // Get number of sounds playing in the multichannel
RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing
RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level)
RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)

View File

@ -735,7 +735,7 @@ typedef struct DrawCall {
int mode; // Drawing mode: LINES, TRIANGLES, QUADS int mode; // Drawing mode: LINES, TRIANGLES, QUADS
int vertexCount; // Number of vertex of the draw int vertexCount; // Number of vertex of the draw
int vertexAlignment; // Number of vertex required for index alignment (LINES, TRIANGLES) int vertexAlignment; // Number of vertex required for index alignment (LINES, TRIANGLES)
//unsigned int vaoId; // Vertex Array id to be used on the draw //unsigned int vaoId; // Vertex array id to be used on the draw
//unsigned int shaderId; // Shader id to be used on the draw //unsigned int shaderId; // Shader id to be used on the draw
unsigned int textureId; // Texture id to be used on the draw unsigned int textureId; // Texture id to be used on the draw
// TODO: Support additional texture units? // TODO: Support additional texture units?
@ -1140,8 +1140,8 @@ void rlEnd(void)
{ {
// WARNING: If we are between rlPushMatrix() and rlPopMatrix() and we need to force a rlglDraw(), // WARNING: If we are between rlPushMatrix() and rlPopMatrix() and we need to force a rlglDraw(),
// we need to call rlPopMatrix() before to recover *currentMatrix (modelview) for the next forced draw call! // we need to call rlPopMatrix() before to recover *currentMatrix (modelview) for the next forced draw call!
// Also noted that if we had multiple matrix pushed, it will require "stackCounter" pops before launching the draw // If we have multiple matrix pushed, it will require "stackCounter" pops before launching the draw
rlPopMatrix(); for (int i = stackCounter; i >= 0; i--) rlPopMatrix();
rlglDraw(); rlglDraw();
} }
} }
@ -1291,11 +1291,11 @@ void rlTextureParameters(unsigned int id, int param, int value)
{ {
if (value == RL_WRAP_MIRROR_CLAMP) if (value == RL_WRAP_MIRROR_CLAMP)
{ {
#if !defined(GRAPHICS_API_OPENGL_11) if (texMirrorClampSupported) glTexParameteri(GL_TEXTURE_2D, param, value);
if (!texMirrorClampSupported) TraceLog(LOG_WARNING, "Clamp mirror wrap mode not supported"); else TraceLog(LOG_WARNING, "Clamp mirror wrap mode not supported");
#endif
} }
else glTexParameteri(GL_TEXTURE_2D, param, value); else glTexParameteri(GL_TEXTURE_2D, param, value);
} break; } break;
case RL_TEXTURE_MAG_FILTER: case RL_TEXTURE_MAG_FILTER:
case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break; case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break;
@ -2623,8 +2623,16 @@ void rlDrawMesh(Mesh mesh, Material material, Matrix transform)
Matrix matView = modelview; // View matrix (camera) Matrix matView = modelview; // View matrix (camera)
Matrix matProjection = projection; // Projection matrix (perspective) Matrix matProjection = projection; // Projection matrix (perspective)
// Calculate model-view matrix combining matModel and matView // TODO: Matrix nightmare! Trying to combine stack matrices with view matrix and local model transform matrix..
Matrix matModelView = MatrixMultiply(transform, matView); // Transform to camera-space coordinates // There is some problem in the order matrices are multiplied... it requires some time to figure out...
Matrix matStackTransform = MatrixIdentity();
// TODO: Consider possible transform matrices in the stack
// Is this the right order? or should we start with the first stored matrix instead of the last one?
//for (int i = stackCounter; i > 0; i--) matStackTransform = MatrixMultiply(stack[i], matStackTransform);
Matrix matModel = MatrixMultiply(transform, matStackTransform); // Apply local model transformation
Matrix matModelView = MatrixMultiply(matModel, matView); // Transform to camera-space coordinates
//----------------------------------------------------- //-----------------------------------------------------
// Bind active texture maps (if available) // Bind active texture maps (if available)

View File

@ -77,9 +77,13 @@ typedef struct Stack {
size_t size; size_t size;
} Stack; } Stack;
#define MEMPOOL_BUCKET_SIZE 8
#define MEMPOOL_BUCKET_BITS 3
typedef struct MemPool { typedef struct MemPool {
AllocList freeList; AllocList freeList;
Stack stack; Stack stack;
MemNode *buckets[MEMPOOL_BUCKET_SIZE];
} MemPool; } MemPool;
// Object Pool // Object Pool
@ -164,10 +168,19 @@ static inline size_t __AlignSize(const size_t size, const size_t align)
return (size + (align - 1)) & -align; return (size + (align - 1)) & -align;
} }
static void __RemoveNode(MemNode **const node) static void __RemoveNode(MemPool *const mempool, MemNode **const node)
{ {
((*node)->prev != NULL)? ((*node)->prev->next = (*node)->next) : (*node = (*node)->next); if ((*node)->next != NULL) (*node)->next->prev = (*node)->prev;
((*node)->next != NULL)? ((*node)->next->prev = (*node)->prev) : (*node = (*node)->prev); else {
mempool->freeList.tail = (*node)->prev;
if (mempool->freeList.tail != NULL) mempool->freeList.tail->next = NULL;
}
if ((*node)->prev != NULL) (*node)->prev->next = (*node)->next;
else {
mempool->freeList.head = (*node)->next;
if (mempool->freeList.head != NULL) mempool->freeList.head->prev = NULL;
}
} }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -183,7 +196,7 @@ MemPool CreateMemPool(const size_t size)
{ {
// Align the mempool size to at least the size of an alloc node. // Align the mempool size to at least the size of an alloc node.
mempool.stack.size = size; mempool.stack.size = size;
mempool.stack.mem = malloc(1 + mempool.stack.size*sizeof *mempool.stack.mem); mempool.stack.mem = malloc(mempool.stack.size*sizeof *mempool.stack.mem);
if (mempool.stack.mem==NULL) if (mempool.stack.mem==NULL)
{ {
@ -229,8 +242,16 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
{ {
MemNode *new_mem = NULL; MemNode *new_mem = NULL;
const size_t ALLOC_SIZE = __AlignSize(size + sizeof *new_mem, sizeof(intptr_t)); const size_t ALLOC_SIZE = __AlignSize(size + sizeof *new_mem, sizeof(intptr_t));
const size_t BUCKET_INDEX = (ALLOC_SIZE >> MEMPOOL_BUCKET_BITS) - 1;
if (mempool->freeList.head != NULL) if (BUCKET_INDEX < MEMPOOL_BUCKET_SIZE && mempool->buckets[BUCKET_INDEX] != NULL && mempool->buckets[BUCKET_INDEX]->size >= ALLOC_SIZE)
{
new_mem = mempool->buckets[BUCKET_INDEX];
mempool->buckets[BUCKET_INDEX] = mempool->buckets[BUCKET_INDEX]->next;
if( mempool->buckets[BUCKET_INDEX] != NULL )
mempool->buckets[BUCKET_INDEX]->prev = NULL;
}
else if (mempool->freeList.head != NULL)
{ {
const size_t MEM_SPLIT_THRESHOLD = 16; const size_t MEM_SPLIT_THRESHOLD = 16;
@ -242,9 +263,8 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
{ {
// Close in size - reduce fragmentation by not splitting. // Close in size - reduce fragmentation by not splitting.
new_mem = *inode; new_mem = *inode;
__RemoveNode(inode); __RemoveNode(mempool, inode);
mempool->freeList.len--; mempool->freeList.len--;
new_mem->next = new_mem->prev = NULL;
break; break;
} }
else else
@ -253,7 +273,6 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
new_mem = (MemNode *)((uint8_t *)*inode + ((*inode)->size - ALLOC_SIZE)); new_mem = (MemNode *)((uint8_t *)*inode + ((*inode)->size - ALLOC_SIZE));
(*inode)->size -= ALLOC_SIZE; (*inode)->size -= ALLOC_SIZE;
new_mem->size = ALLOC_SIZE; new_mem->size = ALLOC_SIZE;
new_mem->next = new_mem->prev = NULL;
break; break;
} }
} }
@ -272,19 +291,20 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
// Use the available mempool space as the new node. // Use the available mempool space as the new node.
new_mem = (MemNode *)mempool->stack.base; new_mem = (MemNode *)mempool->stack.base;
new_mem->size = ALLOC_SIZE; new_mem->size = ALLOC_SIZE;
new_mem->next = new_mem->prev = NULL;
} }
} }
// Visual of the allocation block. // Visual of the allocation block.
// -------------- // --------------
// | mem size | lowest addr of block // | mem size | lowest addr of block
// | next node | // | next node | 12 byte (32-bit) header
// | prev node | 24 byte (64-bit) header
// -------------- // --------------
// | alloc'd | // | alloc'd |
// | memory | // | memory |
// | space | highest addr of block // | space | highest addr of block
// -------------- // --------------
new_mem->next = new_mem->prev = NULL;
uint8_t *const final_mem = (uint8_t *)new_mem + sizeof *new_mem; uint8_t *const final_mem = (uint8_t *)new_mem + sizeof *new_mem;
memset(final_mem, 0, new_mem->size - sizeof *new_mem); memset(final_mem, 0, new_mem->size - sizeof *new_mem);
return final_mem; return final_mem;
@ -296,17 +316,17 @@ void *MemPoolRealloc(MemPool *const restrict mempool, void *ptr, const size_t si
if ((mempool == NULL) || (size > mempool->stack.size)) return NULL; if ((mempool == NULL) || (size > mempool->stack.size)) return NULL;
// NULL ptr should make this work like regular Allocation. // NULL ptr should make this work like regular Allocation.
else if (ptr == NULL) return MemPoolAlloc(mempool, size); else if (ptr == NULL) return MemPoolAlloc(mempool, size);
else if ((uintptr_t)ptr <= (uintptr_t)mempool->stack.mem) return NULL; else if ((uintptr_t)ptr - sizeof(MemNode) < (uintptr_t)mempool->stack.mem) return NULL;
else else
{ {
MemNode *node = (MemNode *)((uint8_t *)ptr - sizeof *node); MemNode *const node = (MemNode *)((uint8_t *)ptr - sizeof *node);
const size_t NODE_SIZE = sizeof *node; const size_t NODE_SIZE = sizeof *node;
uint8_t *resized_block = MemPoolAlloc(mempool, size); uint8_t *const resized_block = MemPoolAlloc(mempool, size);
if (resized_block == NULL) return NULL; if (resized_block == NULL) return NULL;
else else
{ {
MemNode *resized = (MemNode *)(resized_block - sizeof *resized); MemNode *const resized = (MemNode *)(resized_block - sizeof *resized);
memmove(resized_block, ptr, (node->size > resized->size)? (resized->size - NODE_SIZE) : (node->size - NODE_SIZE)); memmove(resized_block, ptr, (node->size > resized->size)? (resized->size - NODE_SIZE) : (node->size - NODE_SIZE));
MemPoolFree(mempool, ptr); MemPoolFree(mempool, ptr);
return resized_block; return resized_block;
@ -316,11 +336,12 @@ void *MemPoolRealloc(MemPool *const restrict mempool, void *ptr, const size_t si
void MemPoolFree(MemPool *const restrict mempool, void *ptr) void MemPoolFree(MemPool *const restrict mempool, void *ptr)
{ {
if ((mempool == NULL) || (ptr == NULL) || ((uintptr_t)ptr <= (uintptr_t)mempool->stack.mem)) return; if ((mempool == NULL) || (ptr == NULL) || ((uintptr_t)ptr - sizeof(MemNode) < (uintptr_t)mempool->stack.mem)) return;
else else
{ {
// Behind the actual pointer data is the allocation info. // Behind the actual pointer data is the allocation info.
MemNode *mem_node = (MemNode *)((uint8_t *)ptr - sizeof *mem_node); MemNode *const mem_node = (MemNode *)((uint8_t *)ptr - sizeof *mem_node);
const size_t BUCKET_INDEX = (mem_node->size >> MEMPOOL_BUCKET_BITS) - 1;
// Make sure the pointer data is valid. // Make sure the pointer data is valid.
if (((uintptr_t)mem_node < (uintptr_t)mempool->stack.base) || if (((uintptr_t)mem_node < (uintptr_t)mempool->stack.base) ||
@ -332,52 +353,44 @@ void MemPoolFree(MemPool *const restrict mempool, void *ptr)
{ {
mempool->stack.base += mem_node->size; mempool->stack.base += mem_node->size;
} }
// attempted stack merge failed, try to place it into the memnode buckets
else if (BUCKET_INDEX < MEMPOOL_BUCKET_SIZE)
{
if (mempool->buckets[index] == NULL) mempool->buckets[index] = node;
else
{
for (MemNode *n = mempool->buckets[index]; n != NULL; n = n->next) if( n==node ) return;
mempool->buckets[index]->prev = node;
node->next = mempool->buckets[index];
mempool->buckets[index] = node;
}
}
// Otherwise, we add it to the free list. // Otherwise, we add it to the free list.
// We also check if the freelist already has the pointer so we can prevent double frees. // We also check if the freelist already has the pointer so we can prevent double frees.
else if ((mempool->freeList.len == 0UL) || ((uintptr_t)mempool->freeList.head >= (uintptr_t)mempool->stack.mem && (uintptr_t)mempool->freeList.head - (uintptr_t)mempool->stack.mem < mempool->stack.size)) else /*if ((mempool->freeList.len == 0UL) || ((uintptr_t)mempool->freeList.head >= (uintptr_t)mempool->stack.mem && (uintptr_t)mempool->freeList.head - (uintptr_t)mempool->stack.mem < mempool->stack.size))*/
{ {
for (MemNode *n = mempool->freeList.head; n != NULL; n = n->next) if (n == mem_node) return; for (MemNode *n = mempool->freeList.head; n != NULL; n = n->next) if (n == mem_node) return;
// This code inserts at head. // This code insertion sorts where largest size is last.
/*
( mempool->freeList.head==NULL)? (mempool->freeList.tail = mem_node) : (mempool->freeList.head->prev = mem_node);
mem_node->next = mempool->freeList.head;
mempool->freeList.head = mem_node;
mempool->freeList.len++;
*/
// This code insertion sorts where largest size is first.
if (mempool->freeList.head == NULL) if (mempool->freeList.head == NULL)
{ {
mempool->freeList.head = mempool->freeList.tail = mem_node; mempool->freeList.head = mempool->freeList.tail = mem_node;
mempool->freeList.len++; mempool->freeList.len++;
} }
else if (mempool->freeList.head->size <= mem_node->size) else if (mempool->freeList.head->size >= mem_node->size)
{ {
mem_node->next = mempool->freeList.head; mem_node->next = mempool->freeList.head;
mem_node->next->prev = mem_node; mem_node->next->prev = mem_node;
mempool->freeList.head = mem_node; mempool->freeList.head = mem_node;
mempool->freeList.len++; mempool->freeList.len++;
} }
else if (mempool->freeList.tail->size > mem_node->size) else //if (mempool->freeList.tail->size <= mem_node->size)
{ {
mem_node->prev = mempool->freeList.tail; mem_node->prev = mempool->freeList.tail;
mempool->freeList.tail->next = mem_node; mempool->freeList.tail->next = mem_node;
mempool->freeList.tail = mem_node; mempool->freeList.tail = mem_node;
mempool->freeList.len++; mempool->freeList.len++;
} }
else
{
MemNode *n = mempool->freeList.head;
while ((n->next != NULL) && (n->next->size > mem_node->size)) n = n->next;
mem_node->next = n->next;
if (n->next != NULL) mem_node->next->prev = mem_node;
n->next = mem_node;
mem_node->prev = n;
mempool->freeList.len++;
}
if (mempool->freeList.autoDefrag && (mempool->freeList.maxNodes != 0UL) && (mempool->freeList.len > mempool->freeList.maxNodes)) MemPoolDefrag(mempool); if (mempool->freeList.autoDefrag && (mempool->freeList.maxNodes != 0UL) && (mempool->freeList.len > mempool->freeList.maxNodes)) MemPoolDefrag(mempool);
} }
@ -400,6 +413,8 @@ size_t GetMemPoolFreeMemory(const MemPool mempool)
for (MemNode *n=mempool.freeList.head; n != NULL; n = n->next) total_remaining += n->size; for (MemNode *n=mempool.freeList.head; n != NULL; n = n->next) total_remaining += n->size;
for (size_t i=0; i<MEMPOOL_BUCKET_SIZE; i++) for (MemNode *n = mempool.buckets[i]; n != NULL; n = n->next) total_remaining += n->size;
return total_remaining; return total_remaining;
} }
@ -411,12 +426,29 @@ bool MemPoolDefrag(MemPool *const mempool)
// If the memory pool has been entirely released, fully defrag it. // If the memory pool has been entirely released, fully defrag it.
if (mempool->stack.size == GetMemPoolFreeMemory(*mempool)) if (mempool->stack.size == GetMemPoolFreeMemory(*mempool))
{ {
memset(&mempool->freeList, 0, sizeof mempool->freeList); mempool->freeList.head = mempool->freeList.tail = NULL;
mempool->freeList.len = 0;
for (size_t i = 0; i < MEMPOOL_BUCKET_SIZE; i++) mempool->buckets[i] = NULL;
mempool->stack.base = mempool->stack.mem + mempool->stack.size; mempool->stack.base = mempool->stack.mem + mempool->stack.size;
return true; return true;
} }
else else
{ {
for (size_t i=0; i<MEMPOOL_BUCKET_SIZE; i++)
{
while (mempool->buckets[i] != NULL)
{
if ((uintptr_t)mempool->buckets[i] == (uintptr_t)mempool->stack.base)
{
mempool->stack.base += mempool->buckets[i]->size;
mempool->buckets[i]->size = 0;
mempool->buckets[i] = mempool->buckets[i]->next;
if (mempool->buckets[i] != NULL) mempool->buckets[i]->prev = NULL;
}
else break;
}
}
const size_t PRE_DEFRAG_LEN = mempool->freeList.len; const size_t PRE_DEFRAG_LEN = mempool->freeList.len;
MemNode **node = &mempool->freeList.head; MemNode **node = &mempool->freeList.head;
@ -427,7 +459,7 @@ bool MemPoolDefrag(MemPool *const mempool)
// If node is right at the stack, merge it back into the stack. // If node is right at the stack, merge it back into the stack.
mempool->stack.base += (*node)->size; mempool->stack.base += (*node)->size;
(*node)->size = 0UL; (*node)->size = 0UL;
__RemoveNode(node); __RemoveNode(mempool, node);
mempool->freeList.len--; mempool->freeList.len--;
node = &mempool->freeList.head; node = &mempool->freeList.head;
} }
@ -475,6 +507,7 @@ bool MemPoolDefrag(MemPool *const mempool)
(*node)->size = 0UL; (*node)->size = 0UL;
(*node)->next->prev = (*node)->prev; (*node)->next->prev = (*node)->prev;
(*node)->prev->next = (*node)->next; (*node)->prev->next = (*node)->next;
*node = (*node)->next;
mempool->freeList.len--; mempool->freeList.len--;
node = &mempool->freeList.head; node = &mempool->freeList.head;
@ -487,6 +520,7 @@ bool MemPoolDefrag(MemPool *const mempool)
(*node)->size = 0UL; (*node)->size = 0UL;
(*node)->next->prev = (*node)->prev; (*node)->next->prev = (*node)->prev;
(*node)->prev->next = (*node)->next; (*node)->prev->next = (*node)->next;
*node = (*node)->prev;
mempool->freeList.len--; mempool->freeList.len--;
node = &mempool->freeList.head; node = &mempool->freeList.head;
@ -513,7 +547,7 @@ void ToggleMemPoolAutoDefrag(MemPool *const mempool)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
union ObjInfo { union ObjInfo {
uint8_t *const byte; uint8_t *const byte;
size_t *const size; size_t *const index;
}; };
ObjPool CreateObjPool(const size_t objsize, const size_t len) ObjPool CreateObjPool(const size_t objsize, const size_t len)
@ -537,7 +571,7 @@ ObjPool CreateObjPool(const size_t objsize, const size_t len)
for (size_t i=0; i<objpool.freeBlocks; i++) for (size_t i=0; i<objpool.freeBlocks; i++)
{ {
union ObjInfo block = { .byte = &objpool.stack.mem[i*objpool.objSize] }; union ObjInfo block = { .byte = &objpool.stack.mem[i*objpool.objSize] };
*block.size = i + 1; *block.index = i + 1;
} }
objpool.stack.base = objpool.stack.mem; objpool.stack.base = objpool.stack.mem;
@ -561,7 +595,7 @@ ObjPool CreateObjPoolFromBuffer(void *const buf, const size_t objsize, const siz
for (size_t i=0; i<objpool.freeBlocks; i++) for (size_t i=0; i<objpool.freeBlocks; i++)
{ {
union ObjInfo block = { .byte = &objpool.stack.mem[i*objpool.objSize] }; union ObjInfo block = { .byte = &objpool.stack.mem[i*objpool.objSize] };
*block.size = i + 1; *block.index = i + 1;
} }
objpool.stack.base = objpool.stack.mem; objpool.stack.base = objpool.stack.mem;
@ -594,7 +628,7 @@ void *ObjPoolAlloc(ObjPool *const objpool)
// after allocating, we set head to the address of the index that *Head holds. // after allocating, we set head to the address of the index that *Head holds.
// Head = &pool[*Head * pool.objsize]; // Head = &pool[*Head * pool.objsize];
objpool->stack.base = (objpool->freeBlocks != 0UL)? objpool->stack.mem + (*ret.size*objpool->objSize) : NULL; objpool->stack.base = (objpool->freeBlocks != 0UL)? objpool->stack.mem + (*ret.index*objpool->objSize) : NULL;
memset(ret.byte, 0, objpool->objSize); memset(ret.byte, 0, objpool->objSize);
return ret.byte; return ret.byte;
} }
@ -611,7 +645,7 @@ void ObjPoolFree(ObjPool *const restrict objpool, void *ptr)
// When we free our pointer, we recycle the pointer space to store the previous index and then we push it as our new head. // When we free our pointer, we recycle the pointer space to store the previous index and then we push it as our new head.
// *p = index of Head in relation to the buffer; // *p = index of Head in relation to the buffer;
// Head = p; // Head = p;
*p.size = (objpool->stack.base != NULL)? (objpool->stack.base - objpool->stack.mem)/objpool->objSize : objpool->stack.size; *p.index = (objpool->stack.base != NULL)? (objpool->stack.base - objpool->stack.mem)/objpool->objSize : objpool->stack.size;
objpool->stack.base = p.byte; objpool->stack.base = p.byte;
objpool->freeBlocks++; objpool->freeBlocks++;
} }

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif

View File

@ -230,7 +230,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
# Define a custom shell .html and output extension # Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)\src\shell.html CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html EXT = .html
endif endif