Merge branch 'master' into i-cant-think-of-a-name
This commit is contained in:
commit
50786b655b
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 \
|
||||||
|
|
|
||||||
71
examples/core/core_scissor_test.c
Normal file
71
examples/core/core_scissor_test.c
Normal 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;
|
||||||
|
}
|
||||||
BIN
examples/core/core_scissor_test.png
Normal file
BIN
examples/core/core_scissor_test.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -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
210
examples/textures/textures_mouse_painting.c
Normal file
210
examples/textures/textures_mouse_painting.c
Normal 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;
|
||||||
|
}
|
||||||
BIN
examples/textures/textures_mouse_painting.png
Normal file
BIN
examples/textures/textures_mouse_painting.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -96,7 +95,7 @@
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Types and Structures Definition
|
// Types and Structures Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
typedef enum { WINTER, SPRING, SUMMER, FALL, TRANSITION} SeasonState;
|
typedef enum { WINTER, SPRING, SUMMER, FALL, TRANSITION } SeasonState;
|
||||||
typedef enum { JUMPING, KICK, FINALFORM, GRABED, ONWIND } KoalaState;
|
typedef enum { JUMPING, KICK, FINALFORM, GRABED, ONWIND } KoalaState;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -670,7 +668,7 @@ void UpdateGameplayScreen(void)
|
||||||
|
|
||||||
transitionFramesCounter += speedMod*TIME_FACTOR;
|
transitionFramesCounter += speedMod*TIME_FACTOR;
|
||||||
|
|
||||||
if(transitionFramesCounter <= SEASONTRANSITION)
|
if (transitionFramesCounter <= SEASONTRANSITION)
|
||||||
{
|
{
|
||||||
color00 = ColorTransition(initcolor00, finalcolor00, transitionFramesCounter);
|
color00 = ColorTransition(initcolor00, finalcolor00, transitionFramesCounter);
|
||||||
color01 = ColorTransition(initcolor01, finalcolor01, transitionFramesCounter);
|
color01 = ColorTransition(initcolor01, finalcolor01, transitionFramesCounter);
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -1438,25 +1428,25 @@ void UpdateGameplayScreen(void)
|
||||||
|
|
||||||
PlaySound(fxEatLeaves);
|
PlaySound(fxEatLeaves);
|
||||||
|
|
||||||
if(leafType[j] == 0)
|
if (leafType[j] == 0)
|
||||||
{
|
{
|
||||||
currentLeaves++;
|
currentLeaves++;
|
||||||
popupLeaves[j].score = 1;
|
popupLeaves[j].score = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(leafType[j] == 1)
|
else if (leafType[j] == 1)
|
||||||
{
|
{
|
||||||
currentLeaves += 2;
|
currentLeaves += 2;
|
||||||
popupLeaves[j].score = 2;
|
popupLeaves[j].score = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(leafType[j] == 2)
|
else if (leafType[j] == 2)
|
||||||
{
|
{
|
||||||
currentLeaves += 3;
|
currentLeaves += 3;
|
||||||
popupLeaves[j].score = 3;
|
popupLeaves[j].score = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(leafType[j] == 3)
|
else if (leafType[j] == 3)
|
||||||
{
|
{
|
||||||
currentLeaves += 4;
|
currentLeaves += 4;
|
||||||
popupLeaves[j].score = 4;
|
popupLeaves[j].score = 4;
|
||||||
|
|
@ -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,9 +2379,7 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2558,7 +2540,7 @@ void UpdateGameplayScreen(void)
|
||||||
velocity -= 1*TIME_FACTOR;
|
velocity -= 1*TIME_FACTOR;
|
||||||
player.y -= velocity;
|
player.y -= velocity;
|
||||||
|
|
||||||
if(player.y >= GetScreenHeight())
|
if (player.y >= GetScreenHeight())
|
||||||
{
|
{
|
||||||
deathsCounter++;
|
deathsCounter++;
|
||||||
finishScreen = 1;
|
finishScreen = 1;
|
||||||
|
|
@ -2781,7 +2763,7 @@ void DrawGameplayScreen(void)
|
||||||
case KICK:DrawTexturePro(atlas01, gameplay_koala_dash, (Rectangle){player.x - player.width, player.y - gameplay_koala_jump.height/4, gameplay_koala_dash.width, gameplay_koala_dash.height}, (Vector2){0, 0}, 0, WHITE); break;
|
case KICK:DrawTexturePro(atlas01, gameplay_koala_dash, (Rectangle){player.x - player.width, player.y - gameplay_koala_jump.height/4, gameplay_koala_dash.width, gameplay_koala_dash.height}, (Vector2){0, 0}, 0, WHITE); break;
|
||||||
case FINALFORM:
|
case FINALFORM:
|
||||||
{
|
{
|
||||||
if(transforming)DrawTexturePro(atlas01, koalaAnimationTransform, (Rectangle){player.x - player.width, player.y - gameplay_koala_transform.height/4, gameplay_koala_transform.width/2, gameplay_koala_transform.height}, (Vector2){0, 0}, 0, finalColor);
|
if (transforming)DrawTexturePro(atlas01, koalaAnimationTransform, (Rectangle){player.x - player.width, player.y - gameplay_koala_transform.height/4, gameplay_koala_transform.width/2, gameplay_koala_transform.height}, (Vector2){0, 0}, 0, finalColor);
|
||||||
else DrawTexturePro(atlas01, koalaAnimationFly, (Rectangle){player.x - gameplay_koala_fly.width/3, player.y - gameplay_koala_fly.height/4, gameplay_koala_fly.width/2, gameplay_koala_fly.height}, (Vector2){0, 0}, 0, finalColor);//DrawTextureRec((koalaFly), (Rectangle){0, 0, 128, 128}, (Vector2){player.x - 50, player.y - 40}, WHITE);
|
else DrawTexturePro(atlas01, koalaAnimationFly, (Rectangle){player.x - gameplay_koala_fly.width/3, player.y - gameplay_koala_fly.height/4, gameplay_koala_fly.width/2, gameplay_koala_fly.height}, (Vector2){0, 0}, 0, finalColor);//DrawTextureRec((koalaFly), (Rectangle){0, 0, 128, 128}, (Vector2){player.x - 50, player.y - 40}, WHITE);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
@ -3781,7 +3763,7 @@ static void Reset(void)
|
||||||
bamboo[i].y = 0;
|
bamboo[i].y = 0;
|
||||||
bamboo[i].width = 50;
|
bamboo[i].width = 50;
|
||||||
bamboo[i].height = GetScreenHeight();
|
bamboo[i].height = GetScreenHeight();
|
||||||
if(i > 5) bambooActive[i] = false;
|
if (i > 5) bambooActive[i] = false;
|
||||||
else bambooActive[i] = true;
|
else bambooActive[i] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
10
projects/VSCode/.vscode/tasks.json
vendored
10
projects/VSCode/.vscode/tasks.json
vendored
|
|
@ -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"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
458
src/raudio.c
458
src/raudio.c
|
|
@ -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 (false) { }
|
||||||
#if defined(SUPPORT_FILEFORMAT_WAV)
|
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||||
if (IsFileExtension(fileName, ".wav")) wave = LoadWAV(fileName);
|
else if (IsFileExtension(fileName, ".wav")) wave = LoadWAV(fileName);
|
||||||
#else
|
|
||||||
if (false) {}
|
|
||||||
#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 (false) { }
|
||||||
#if defined(SUPPORT_FILEFORMAT_WAV)
|
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||||
if (IsFileExtension(fileName, ".wav")) success = SaveWAV(wave, fileName);
|
else if (IsFileExtension(fileName, ".wav")) success = SaveWAV(wave, fileName);
|
||||||
#else
|
|
||||||
if (false) {}
|
|
||||||
#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 (false) { }
|
||||||
#if defined(SUPPORT_FILEFORMAT_OGG)
|
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||||
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music->ctxData);
|
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
|
||||||
#else
|
|
||||||
if (false) {}
|
|
||||||
#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 (false) { }
|
||||||
#if defined(SUPPORT_FILEFORMAT_OGG)
|
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||||
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music->ctxData);
|
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
|
||||||
#else
|
|
||||||
if (false) {}
|
|
||||||
#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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
62
src/raudio.h
62
src/raudio.h
|
|
@ -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
|
||||||
|
|
|
||||||
69
src/raylib.h
69
src/raylib.h
|
|
@ -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)
|
||||||
|
|
|
||||||
24
src/rlgl.h
24
src/rlgl.h
|
|
@ -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)
|
||||||
|
|
|
||||||
128
src/rmem.h
128
src/rmem.h
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user