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

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

2
.github/FUNDING.yml vendored
View File

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

View File

@ -243,7 +243,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
# logic to a self contained function: UpdateDrawFrame(), check core_basic_window_web.c for reference.
# 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
endif
@ -365,6 +365,7 @@ EXAMPLES = \
core/core_window_letterbox \
core/core_drop_files \
core/core_random_values \
core/core_scissor_test \
core/core_storage_values \
core/core_vr_simulator \
core/core_loading_thread \
@ -394,6 +395,7 @@ EXAMPLES = \
text/text_rectangle_bounds \
text/text_unicode \
textures/textures_logo_raylib \
textures/textures_mouse_painting \
textures/textures_rectangle \
textures/textures_srcrec_dstrec \
textures/textures_image_drawing \

View File

@ -0,0 +1,71 @@
/*******************************************************************************************
*
* raylib [core] example - Scissor test
*
* This example has been created using raylib 2.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
* Example contributed by Chris Dill (@MysteriousSpace) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2019 Chris Dill (@MysteriousSpace)
*
********************************************************************************************/
#include "raylib.h"
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - scissor test");
Rectangle scissorArea = { 0, 0, 300, 300 };
bool scissorMode = true;
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KEY_S)) scissorMode = !scissorMode;
// Centre the scissor area around the mouse position
scissorArea.x = GetMouseX() - scissorArea.width/2;
scissorArea.y = GetMouseY() - scissorArea.height/2;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
if (scissorMode) BeginScissorMode(scissorArea.x, scissorArea.y, scissorArea.width, scissorArea.height);
// Draw full screen rectangle and some text
// NOTE: Only part defined by scissor area will be rendered
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), RED);
DrawText("Move the mouse around to reveal this text!", 190, 200, 20, LIGHTGRAY);
if (scissorMode) EndScissorMode();
DrawRectangleLinesEx(scissorArea, 1, BLACK);
DrawText("Press S to toggle scissor test", 10, 10, 20, BLACK);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -29,7 +29,7 @@ int main(void)
int gameScreenWidth = 640;
int 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);
SetTextureFilter(target.texture, FILTER_BILINEAR); // Texture scale filter to use
@ -59,7 +59,7 @@ int main(void)
BeginDrawing();
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);
ClearBackground(RAYWHITE); // Clear render texture background color

File diff suppressed because it is too large Load Diff

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif
# 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
endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif
# 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
endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif
# 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
endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif
# 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
endif

View File

@ -200,7 +200,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
ifeq ($(PLATFORM_OS),WINDOWS)
# resource file contains windows executable icon and properties
# -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
ifeq ($(PLATFORM_OS),LINUX)
ifeq ($(RAYLIB_LIBTYPE),STATIC)
@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif
# 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
endif

View File

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

View File

@ -38,7 +38,6 @@
//#define DEBUG
// DONE: Review MAX_* limits, don't waste memory!!!
#define MAX_ENEMIES 16
#define MAX_BAMBOO 16
#define MAX_LEAVES 14
@ -96,7 +95,7 @@
//----------------------------------------------------------------------------------
// 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 struct {
@ -343,7 +342,6 @@ static Rectangle leftButton = {0, 0, 0, 0};
static Rectangle rightButton = {0, 0, 0, 0};
static Rectangle powerButton = {0, 0, 0, 0};
static Rectangle fire[MAX_FIRE];
//static Rectangle flames[MAX_FLAMES];
static Rectangle ice[MAX_ICE];
static Rectangle resin[MAX_RESIN];
static Rectangle wind[MAX_WIND];
@ -351,7 +349,7 @@ static Rectangle bamboo[MAX_BAMBOO];
static Rectangle snake[MAX_ENEMIES];
static Rectangle dingo[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 backBar;
static Rectangle fireAnimation;
@ -387,7 +385,7 @@ static Vector2 textSize;
static Vector2 clockPosition;
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 backSnowParticle;
static ParticleSystem dandelionParticle;
@ -670,7 +668,7 @@ void UpdateGameplayScreen(void)
transitionFramesCounter += speedMod*TIME_FACTOR;
if(transitionFramesCounter <= SEASONTRANSITION)
if (transitionFramesCounter <= SEASONTRANSITION)
{
color00 = ColorTransition(initcolor00, finalcolor00, transitionFramesCounter);
color01 = ColorTransition(initcolor01, finalcolor01, transitionFramesCounter);
@ -1043,12 +1041,8 @@ void UpdateGameplayScreen(void)
#endif
}
#if defined(DEBUG)
if (currentLeaves < LEAVESTOTRANSFORM && (IsKeyPressed(KEY_ENTER)))
{
currentLeaves += LEAVESTOTRANSFORM;
}
if ((currentLeaves < LEAVESTOTRANSFORM) && (IsKeyPressed(KEY_ENTER))) currentLeaves += LEAVESTOTRANSFORM;
#endif
if (coolDown)
{
power += 20;
@ -1427,10 +1421,6 @@ void UpdateGameplayScreen(void)
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].scale = 1.0f;
popupLeaves[j].alpha = 1.0f;
@ -1438,25 +1428,25 @@ void UpdateGameplayScreen(void)
PlaySound(fxEatLeaves);
if(leafType[j] == 0)
if (leafType[j] == 0)
{
currentLeaves++;
popupLeaves[j].score = 1;
}
else if(leafType[j] == 1)
else if (leafType[j] == 1)
{
currentLeaves += 2;
popupLeaves[j].score = 2;
}
else if(leafType[j] == 2)
else if (leafType[j] == 2)
{
currentLeaves += 3;
popupLeaves[j].score = 3;
}
else if(leafType[j] == 3)
else if (leafType[j] == 3)
{
currentLeaves += 4;
popupLeaves[j].score = 4;
@ -2232,7 +2222,6 @@ void UpdateGameplayScreen(void)
player.x -= speed;
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++)
{
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].size = (float)GetRandomValue(5, 10)/30;
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].active = true;
@ -2317,7 +2305,6 @@ void UpdateGameplayScreen(void)
enemyHit[i].speed = (Vector2){ owl[i].x, owl[i].y };
enemyHit[i].size = (float)GetRandomValue(5, 10)/30;
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].active = true;
@ -2392,9 +2379,7 @@ void UpdateGameplayScreen(void)
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)
{
@ -2407,8 +2392,7 @@ void UpdateGameplayScreen(void)
finalColor = RED;
finalColor2 = WHITE;
}
if (!transBackAnim)
else
{
finalColor = WHITE;
finalColor2 = RED;
@ -2420,9 +2404,7 @@ void UpdateGameplayScreen(void)
thisFrameKoala = 0;
curFrameKoala = 0;
speedFX.active = true;
//speedMod = 2;
transCount = 0;
//printf ("THIS ISN'T EVEN MY FINAL FORM");
bambooTimer += 15*TIME_FACTOR;
}
}
@ -2558,7 +2540,7 @@ void UpdateGameplayScreen(void)
velocity -= 1*TIME_FACTOR;
player.y -= velocity;
if(player.y >= GetScreenHeight())
if (player.y >= GetScreenHeight())
{
deathsCounter++;
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 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);
} break;
@ -3781,7 +3763,7 @@ static void Reset(void)
bamboo[i].y = 0;
bamboo[i].width = 50;
bamboo[i].height = GetScreenHeight();
if(i > 5) bambooActive[i] = false;
if (i > 5) bambooActive[i] = false;
else bambooActive[i] = true;
}

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif
# 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
endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif
# 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
endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif
# 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
endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif
# 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
endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif
# 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
endif

View File

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

View File

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

View File

@ -29,8 +29,10 @@ RAYLIB_VERSION ?= 2.5.0
RAYLIB_API_VERSION ?= 251
RAYLIB_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
PLATFORM ?= PLATFORM_DESKTOP
@ -68,6 +70,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
# ifeq ($(UNAME),Msys) -> Windows
ifeq ($(OS),Windows_NT)
PLATFORM_OS=WINDOWS
export PATH := $(COMPILER_PATH):$(PATH)
else
UNAMEOS=$(shell uname)
ifeq ($(UNAMEOS),Linux)
@ -236,7 +239,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif
# 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
endif

View File

@ -251,10 +251,6 @@ void SetCameraMode(Camera camera, int mode)
cameraAngle.x = asinf( (float)fabs(dx)/distance.x); // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
cameraAngle.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;
// Lock cursor for first person and third person cameras

View File

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

View File

@ -236,16 +236,16 @@ static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 fr
// AudioBuffer management functions declaration
// 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);
void CloseAudioBuffer(AudioBuffer *audioBuffer);
bool IsAudioBufferPlaying(AudioBuffer *audioBuffer);
void PlayAudioBuffer(AudioBuffer *audioBuffer);
void StopAudioBuffer(AudioBuffer *audioBuffer);
void PauseAudioBuffer(AudioBuffer *audioBuffer);
void ResumeAudioBuffer(AudioBuffer *audioBuffer);
void SetAudioBufferVolume(AudioBuffer *audioBuffer, float volume);
void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch);
void TrackAudioBuffer(AudioBuffer *audioBuffer);
void UntrackAudioBuffer(AudioBuffer *audioBuffer);
void CloseAudioBuffer(AudioBuffer *buffer);
bool IsAudioBufferPlaying(AudioBuffer *buffer);
void PlayAudioBuffer(AudioBuffer *buffer);
void StopAudioBuffer(AudioBuffer *buffer);
void PauseAudioBuffer(AudioBuffer *buffer);
void ResumeAudioBuffer(AudioBuffer *buffer);
void SetAudioBufferVolume(AudioBuffer *buffer, float volume);
void SetAudioBufferPitch(AudioBuffer *buffer, float pitch);
void TrackAudioBuffer(AudioBuffer *buffer);
void UntrackAudioBuffer(AudioBuffer *buffer);
//----------------------------------------------------------------------------------
// Multi channel playback globals
@ -644,151 +644,127 @@ AudioBuffer *InitAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
}
// 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");
return;
UntrackAudioBuffer(buffer);
RL_FREE(buffer->buffer);
RL_FREE(buffer);
}
UntrackAudioBuffer(audioBuffer);
RL_FREE(audioBuffer->buffer);
RL_FREE(audioBuffer);
else TraceLog(LOG_ERROR, "CloseAudioBuffer() : No audio buffer");
}
// Check if an audio buffer is playing
bool IsAudioBufferPlaying(AudioBuffer *audioBuffer)
bool IsAudioBufferPlaying(AudioBuffer *buffer)
{
if (audioBuffer == NULL)
{
TraceLog(LOG_ERROR, "IsAudioBufferPlaying() : No audio buffer");
return false;
}
bool result = 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
// NOTE: Buffer is restarted to the start.
// 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");
return;
buffer->playing = true;
buffer->paused = false;
buffer->frameCursorPos = 0;
}
audioBuffer->playing = true;
audioBuffer->paused = false;
audioBuffer->frameCursorPos = 0;
else TraceLog(LOG_ERROR, "PlayAudioBuffer() : No 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");
return;
if (IsAudioBufferPlaying(buffer))
{
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.
if (!IsAudioBufferPlaying(audioBuffer)) return;
audioBuffer->playing = false;
audioBuffer->paused = false;
audioBuffer->frameCursorPos = 0;
audioBuffer->isSubBufferProcessed[0] = true;
audioBuffer->isSubBufferProcessed[1] = true;
}
else TraceLog(LOG_ERROR, "StopAudioBuffer() : No audio buffer");
}
// Pause an audio buffer
void PauseAudioBuffer(AudioBuffer *audioBuffer)
void PauseAudioBuffer(AudioBuffer *buffer)
{
if (audioBuffer == NULL)
{
TraceLog(LOG_ERROR, "PauseAudioBuffer() : No audio buffer");
return;
}
audioBuffer->paused = true;
if (buffer != NULL) buffer->paused = true;
else TraceLog(LOG_ERROR, "PauseAudioBuffer() : No audio buffer");
}
// Resume an audio buffer
void ResumeAudioBuffer(AudioBuffer *audioBuffer)
void ResumeAudioBuffer(AudioBuffer *buffer)
{
if (audioBuffer == NULL)
{
TraceLog(LOG_ERROR, "ResumeAudioBuffer() : No audio buffer");
return;
}
audioBuffer->paused = false;
if (buffer != NULL) buffer->paused = false;
else TraceLog(LOG_ERROR, "ResumeAudioBuffer() : No audio buffer");
}
// Set volume for an audio buffer
void SetAudioBufferVolume(AudioBuffer *audioBuffer, float volume)
void SetAudioBufferVolume(AudioBuffer *buffer, float volume)
{
if (audioBuffer == NULL)
{
TraceLog(LOG_WARNING, "SetAudioBufferVolume() : No audio buffer");
return;
}
audioBuffer->volume = volume;
if (buffer != NULL) buffer->volume = volume;
else TraceLog(LOG_WARNING, "SetAudioBufferVolume() : No 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");
return;
}
float pitchMul = pitch/audioBuffer->pitch;
float pitchMul = pitch/buffer->pitch;
// 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.
ma_uint32 newOutputSampleRate = (ma_uint32)((float)audioBuffer->dsp.src.config.sampleRateOut / pitchMul);
audioBuffer->pitch *= (float)audioBuffer->dsp.src.config.sampleRateOut / newOutputSampleRate;
ma_uint32 newOutputSampleRate = (ma_uint32)((float)buffer->dsp.src.config.sampleRateOut/pitchMul);
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
void TrackAudioBuffer(AudioBuffer *audioBuffer)
void TrackAudioBuffer(AudioBuffer *buffer)
{
ma_mutex_lock(&audioLock);
{
if (firstAudioBuffer == NULL) firstAudioBuffer = audioBuffer;
if (firstAudioBuffer == NULL) firstAudioBuffer = buffer;
else
{
lastAudioBuffer->next = audioBuffer;
audioBuffer->prev = lastAudioBuffer;
lastAudioBuffer->next = buffer;
buffer->prev = lastAudioBuffer;
}
lastAudioBuffer = audioBuffer;
lastAudioBuffer = buffer;
}
ma_mutex_unlock(&audioLock);
}
// Untrack audio buffer from linked list
void UntrackAudioBuffer(AudioBuffer *audioBuffer)
void UntrackAudioBuffer(AudioBuffer *buffer)
{
ma_mutex_lock(&audioLock);
{
if (audioBuffer->prev == NULL) firstAudioBuffer = audioBuffer->next;
else audioBuffer->prev->next = audioBuffer->next;
if (buffer->prev == NULL) firstAudioBuffer = buffer->next;
else buffer->prev->next = buffer->next;
if (audioBuffer->next == NULL) lastAudioBuffer = audioBuffer->prev;
else audioBuffer->next->prev = audioBuffer->prev;
if (buffer->next == NULL) lastAudioBuffer = buffer->prev;
else buffer->next->prev = buffer->prev;
audioBuffer->prev = NULL;
audioBuffer->next = NULL;
buffer->prev = NULL;
buffer->next = NULL;
}
ma_mutex_unlock(&audioLock);
}
@ -802,10 +778,9 @@ Wave LoadWave(const char *fileName)
{
Wave wave = { 0 };
if (false) { }
#if defined(SUPPORT_FILEFORMAT_WAV)
if (IsFileExtension(fileName, ".wav")) wave = LoadWAV(fileName);
#else
if (false) {}
else if (IsFileExtension(fileName, ".wav")) wave = LoadWAV(fileName);
#endif
#if defined(SUPPORT_FILEFORMAT_OGG)
else if (IsFileExtension(fileName, ".ogg")) wave = LoadOGG(fileName);
@ -821,25 +796,6 @@ Wave LoadWave(const char *fileName)
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
// NOTE: The entire file is loaded to memory to be played (no-streaming)
Sound LoadSound(const char *fileName)
@ -903,7 +859,7 @@ void UnloadWave(Wave wave)
// Unload sound
void UnloadSound(Sound sound)
{
CloseAudioBuffer((AudioBuffer *)sound.stream.buffer);
CloseAudioBuffer(sound.stream.buffer);
TraceLog(LOG_INFO, "Unloaded sound data from RAM");
}
@ -911,7 +867,7 @@ void UnloadSound(Sound sound)
// Update sound buffer with new data
void UpdateSound(Sound sound, const void *data, int samplesCount)
{
AudioBuffer *audioBuffer = (AudioBuffer *)sound.stream.buffer;
AudioBuffer *audioBuffer = sound.stream.buffer;
if (audioBuffer == NULL)
{
@ -930,10 +886,9 @@ void ExportWave(Wave wave, const char *fileName)
{
bool success = false;
if (false) { }
#if defined(SUPPORT_FILEFORMAT_WAV)
if (IsFileExtension(fileName, ".wav")) success = SaveWAV(wave, fileName);
#else
if (false) {}
else if (IsFileExtension(fileName, ".wav")) success = SaveWAV(wave, fileName);
#endif
else if (IsFileExtension(fileName, ".raw"))
{
@ -994,7 +949,7 @@ void ExportWaveAsCode(Wave wave, const char *fileName)
// Play a sound
void PlaySound(Sound sound)
{
PlayAudioBuffer((AudioBuffer *)sound.stream.buffer);
PlayAudioBuffer(sound.stream.buffer);
}
// Play a sound in the multichannel buffer pool
@ -1046,17 +1001,16 @@ void PlaySoundMulti(Sound sound)
audioBufferPoolChannels[index] = audioBufferPoolCounter;
audioBufferPoolCounter++;
audioBufferPool[index]->volume = ((AudioBuffer*)sound.stream.buffer)->volume;
audioBufferPool[index]->pitch = ((AudioBuffer*)sound.stream.buffer)->pitch;
audioBufferPool[index]->looping = ((AudioBuffer*)sound.stream.buffer)->looping;
audioBufferPool[index]->usage = ((AudioBuffer*)sound.stream.buffer)->usage;
audioBufferPool[index]->volume = sound.stream.buffer->volume;
audioBufferPool[index]->pitch = sound.stream.buffer->pitch;
audioBufferPool[index]->looping = sound.stream.buffer->looping;
audioBufferPool[index]->usage = sound.stream.buffer->usage;
audioBufferPool[index]->isSubBufferProcessed[0] = false;
audioBufferPool[index]->isSubBufferProcessed[1] = false;
audioBufferPool[index]->bufferSizeInFrames = ((AudioBuffer*)sound.stream.buffer)->bufferSizeInFrames;
audioBufferPool[index]->buffer = ((AudioBuffer*)sound.stream.buffer)->buffer;
audioBufferPool[index]->bufferSizeInFrames = sound.stream.buffer->bufferSizeInFrames;
audioBufferPool[index]->buffer = sound.stream.buffer->buffer;
PlayAudioBuffer(audioBufferPool[index]);
}
// Stop any sound played with PlaySoundMulti()
@ -1081,37 +1035,37 @@ int GetSoundsPlaying(void)
// Pause a sound
void PauseSound(Sound sound)
{
PauseAudioBuffer((AudioBuffer *)sound.stream.buffer);
PauseAudioBuffer(sound.stream.buffer);
}
// Resume a paused sound
void ResumeSound(Sound sound)
{
ResumeAudioBuffer((AudioBuffer *)sound.stream.buffer);
ResumeAudioBuffer(sound.stream.buffer);
}
// Stop reproducing a sound
void StopSound(Sound sound)
{
StopAudioBuffer((AudioBuffer *)sound.stream.buffer);
StopAudioBuffer(sound.stream.buffer);
}
// Check if a sound is playing
bool IsSoundPlaying(Sound sound)
{
return IsAudioBufferPlaying((AudioBuffer *)sound.stream.buffer);
return IsAudioBufferPlaying(sound.stream.buffer);
}
// Set volume for a sound
void SetSoundVolume(Sound sound, float volume)
{
SetAudioBufferVolume((AudioBuffer *)sound.stream.buffer, volume);
SetAudioBufferVolume(sound.stream.buffer, volume);
}
// Set pitch for a sound
void SetSoundPitch(Sound sound, float pitch)
{
SetAudioBufferPitch((AudioBuffer *)sound.stream.buffer, pitch);
SetAudioBufferPitch(sound.stream.buffer, pitch);
}
// Convert wave data to desired format
@ -1212,53 +1166,52 @@ float *GetWaveData(Wave wave)
// Load music stream from file
Music LoadMusicStream(const char *fileName)
{
Music music = (MusicStream *)RL_MALLOC(sizeof(MusicStream));
bool musicLoaded = true;
Music music = { 0 };
bool musicLoaded = false;
if (false) { }
#if defined(SUPPORT_FILEFORMAT_OGG)
if (IsFileExtension(fileName, ".ogg"))
else if (IsFileExtension(fileName, ".ogg"))
{
// 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;
else
if (music.ctxData != NULL)
{
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
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->sampleLeft = music->sampleCount;
music->ctxType = MUSIC_AUDIO_OGG;
music->loopCount = 0; // Infinite loop by default
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.sampleLeft = music.sampleCount;
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 channels: %i", fileName, info.channels);
TraceLog(LOG_DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required);
}
}
#else
if (false) {}
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
else if (IsFileExtension(fileName, ".flac"))
{
music->ctxData = drflac_open_file(fileName);
music.ctxData = drflac_open_file(fileName);
if (music->ctxData == NULL) musicLoaded = false;
else
if (music.ctxData != NULL)
{
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->sampleCount = (unsigned int)ctxFlac->totalSampleCount;
music->sampleLeft = music->sampleCount;
music->ctxType = MUSIC_AUDIO_FLAC;
music->loopCount = 0; // Infinite loop by default
music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels);
music.sampleCount = (unsigned int)ctxFlac->totalSampleCount;
music.sampleLeft = music.sampleCount;
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 bits per sample: %i", fileName, ctxFlac->bitsPerSample);
TraceLog(LOG_DEBUG, "[%s] FLAC channels: %i", fileName, ctxFlac->channels);
@ -1269,24 +1222,24 @@ Music LoadMusicStream(const char *fileName)
else if (IsFileExtension(fileName, ".mp3"))
{
drmp3 *ctxMp3 = RL_MALLOC(sizeof(drmp3));
music->ctxData = ctxMp3;
music.ctxData = ctxMp3;
int result = drmp3_init_file(ctxMp3, fileName, NULL);
if (!result) musicLoaded = false;
else
if (result > 0)
{
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 bits per sample: %i", fileName, 32);
TraceLog(LOG_INFO, "[%s] MP3 channels: %i", fileName, ctxMp3->channels);
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);
TraceLog(LOG_INFO, "[%s] MP3 total samples: %i", fileName, music.sampleCount);
}
}
#endif
@ -1297,73 +1250,70 @@ Music LoadMusicStream(const char *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
// NOTE: Only stereo is supported for XM
music->stream = InitAudioStream(48000, 16, 2);
music->sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm);
music->sampleLeft = music->sampleCount;
music->ctxType = MUSIC_MODULE_XM;
music->loopCount = 0; // Infinite loop by default
music.stream = InitAudioStream(48000, 16, 2);
music.sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm);
music.sampleLeft = music.sampleCount;
music.loopCount = 0; // Infinite loop by default
musicLoaded = true;
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);
music.ctxData = ctxXm;
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
#if defined(SUPPORT_FILEFORMAT_MOD)
else if (IsFileExtension(fileName, ".mod"))
{
jar_mod_context_t *ctxMod = RL_MALLOC(sizeof(jar_mod_context_t));
music->ctxData = ctxMod;
music.ctxData = 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->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
music.ctxType = MUSIC_MODULE_MOD;
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);
// NOTE: Only stereo is supported for MOD
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
else musicLoaded = false;
if (!musicLoaded)
{
if (false) { }
#if defined(SUPPORT_FILEFORMAT_OGG)
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music->ctxData);
#else
if (false) {}
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
#endif
#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
#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
#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
#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
RL_FREE(music);
music = NULL;
TraceLog(LOG_WARNING, "[%s] Music file could not be opened", fileName);
}
@ -1373,37 +1323,30 @@ Music LoadMusicStream(const char *fileName)
// Unload music stream
void UnloadMusicStream(Music music)
{
if (music == NULL) return;
CloseAudioStream(music->stream);
CloseAudioStream(music.stream);
if (false) { }
#if defined(SUPPORT_FILEFORMAT_OGG)
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music->ctxData);
#else
if (false) {}
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
#endif
#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
#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
#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
#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
RL_FREE(music);
}
// Start music playing (open stream)
void PlayMusicStream(Music music)
{
if (music != NULL)
{
AudioBuffer *audioBuffer = (AudioBuffer *)music->stream.buffer;
AudioBuffer *audioBuffer = music.stream.buffer;
if (audioBuffer == NULL)
{
@ -1417,81 +1360,76 @@ void PlayMusicStream(Music music)
// if (IsMusicPlaying(music)) PlayMusicStream(music);
ma_uint32 frameCursorPos = audioBuffer->frameCursorPos;
PlayAudioStream(music->stream); // <-- This resets the cursor position.
PlayAudioStream(music.stream); // <-- This resets the cursor position.
audioBuffer->frameCursorPos = frameCursorPos;
}
}
// Pause music playing
void PauseMusicStream(Music music)
{
if (music != NULL) PauseAudioStream(music->stream);
PauseAudioStream(music.stream);
}
// Resume music playing
void ResumeMusicStream(Music music)
{
if (music != NULL) ResumeAudioStream(music->stream);
ResumeAudioStream(music.stream);
}
// Stop music playing (close stream)
void StopMusicStream(Music music)
{
if (music == NULL) return;
StopAudioStream(music->stream);
StopAudioStream(music.stream);
// Restart music context
switch (music->ctxType)
switch (music.ctxType)
{
#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
#if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_AUDIO_FLAC: /* TODO: Restart FLAC context */ break;
#endif
#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
#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
#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
default: break;
}
music->sampleLeft = music->sampleCount;
music.sampleLeft = music.sampleCount;
}
// Update (re-fill) music buffers if data already processed
void UpdateMusicStream(Music music)
{
if (music == NULL) return;
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
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
while (IsAudioBufferProcessed(music->stream))
while (IsAudioBufferProcessed(music.stream))
{
if ((music->sampleLeft/music->stream.channels) >= subBufferSizeInFrames) samplesCount = subBufferSizeInFrames*music->stream.channels;
else samplesCount = music->sampleLeft;
if ((music.sampleLeft/music.stream.channels) >= subBufferSizeInFrames) samplesCount = subBufferSizeInFrames*music.stream.channels;
else samplesCount = music.sampleLeft;
switch (music->ctxType)
switch (music.ctxType)
{
#if defined(SUPPORT_FILEFORMAT_OGG)
case MUSIC_AUDIO_OGG:
{
// 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;
#endif
@ -1499,7 +1437,7 @@ void UpdateMusicStream(Music music)
case MUSIC_AUDIO_FLAC:
{
// 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;
#endif
@ -1507,7 +1445,7 @@ void UpdateMusicStream(Music music)
case MUSIC_AUDIO_MP3:
{
// 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;
#endif
@ -1515,29 +1453,29 @@ void UpdateMusicStream(Music music)
case MUSIC_MODULE_XM:
{
// 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;
#endif
#if defined(SUPPORT_FILEFORMAT_MOD)
case MUSIC_MODULE_MOD:
{
// 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;
#endif
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;
else music->sampleLeft -= samplesCount;
if (samplesCount > 1) music.sampleLeft -= samplesCount/2;
else music.sampleLeft -= samplesCount;
}
else music->sampleLeft -= samplesCount;
else music.sampleLeft -= samplesCount;
if (music->sampleLeft <= 0)
if (music.sampleLeft <= 0)
{
streamEnding = true;
break;
@ -1553,14 +1491,14 @@ void UpdateMusicStream(Music music)
StopMusicStream(music); // Stop music (and reset)
// 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
}
else
{
if (music->loopCount == 0) PlayMusicStream(music);
if (music.loopCount == 0) PlayMusicStream(music);
}
}
else
@ -1574,27 +1512,26 @@ void UpdateMusicStream(Music music)
// Check if any music is playing
bool IsMusicPlaying(Music music)
{
if (music == NULL) return false;
else return IsAudioStreamPlaying(music->stream);
return IsAudioStreamPlaying(music.stream);
}
// Set volume for music
void SetMusicVolume(Music music, float volume)
{
if (music != NULL) SetAudioStreamVolume(music->stream, volume);
SetAudioStreamVolume(music.stream, volume);
}
// Set pitch for music
void SetMusicPitch(Music music, float pitch)
{
if (music != NULL) SetAudioStreamPitch(music->stream, pitch);
SetAudioStreamPitch(music.stream, pitch);
}
// Set music loop count (loop repeats)
// NOTE: If set to -1, means infinite loop
void SetMusicLoopCount(Music music, int count)
{
if (music != NULL) music->loopCount = count;
music.loopCount = count;
}
// Get music time length (in seconds)
@ -1602,7 +1539,7 @@ float GetMusicTimeLength(Music music)
{
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;
}
@ -1612,11 +1549,8 @@ float GetMusicTimePlayed(Music music)
{
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;
}

View File

@ -80,25 +80,14 @@
// Wave type, defines audio wave data
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 sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
unsigned int channels; // Number of channels (1-mono, 2-stereo)
void *data; // Buffer data pointer
} Wave;
// Sound source type
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;
typedef struct rAudioBuffer rAudioBuffer;
// Audio stream type
// 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 channels; // Number of channels (1-mono, 2-stereo)
void *audioBuffer; // 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)
rAudioBuffer *buffer; // Pointer to internal data used by the audio system
} 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
extern "C" { // Prevents name mangling of functions
#endif
@ -126,25 +130,31 @@ extern "C" { // Prevents name mangling of functions
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
// Audio device management functions
void InitAudioDevice(void); // Initialize audio device and context
void CloseAudioDevice(void); // Close the audio device and context
bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully
void SetMasterVolume(float volume); // Set master volume (listener)
// Wave/Sound loading/unloading functions
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 LoadSoundFromWave(Wave wave); // Load sound from wave data
void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data
void UnloadWave(Wave wave); // Unload wave data
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 PlaySoundMulti(Sound sound); // Play a sound using the multi channel buffer pool
int GetSoundsPlaying(void); // Get number of sounds playing in the multichannel buffer pool
void StopSound(Sound sound); // Stop playing a sound
void PauseSound(Sound sound); // Pause a sound
void ResumeSound(Sound sound); // Resume a paused sound
void StopSound(Sound sound); // Stop playing a sound
void StopSoundMulti(void); // Stop any sound played with PlaySoundMulti()
void PlaySoundMulti(Sound sound); // Play a sound (using multichannel buffer pool)
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
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)
@ -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
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
// Music management functions
Music LoadMusicStream(const char *fileName); // Load music stream from file
void UnloadMusicStream(Music music); // Unload music stream
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)
// AudioStream management functions
AudioStream InitAudioStream(unsigned int sampleRate,
unsigned int sampleSize,
unsigned int channels); // Init audio stream (to stream raw audio pcm data)
AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream raw audio pcm data)
void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data
void CloseAudioStream(AudioStream stream); // Close audio stream and free memory
bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill

View File

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

View File

@ -735,7 +735,7 @@ typedef struct DrawCall {
int mode; // Drawing mode: LINES, TRIANGLES, QUADS
int vertexCount; // Number of vertex of the draw
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 textureId; // Texture id to be used on the draw
// 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(),
// 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
rlPopMatrix();
// If we have multiple matrix pushed, it will require "stackCounter" pops before launching the draw
for (int i = stackCounter; i >= 0; i--) rlPopMatrix();
rlglDraw();
}
}
@ -1291,11 +1291,11 @@ void rlTextureParameters(unsigned int id, int param, int value)
{
if (value == RL_WRAP_MIRROR_CLAMP)
{
#if !defined(GRAPHICS_API_OPENGL_11)
if (!texMirrorClampSupported) TraceLog(LOG_WARNING, "Clamp mirror wrap mode not supported");
#endif
if (texMirrorClampSupported) glTexParameteri(GL_TEXTURE_2D, param, value);
else TraceLog(LOG_WARNING, "Clamp mirror wrap mode not supported");
}
else glTexParameteri(GL_TEXTURE_2D, param, value);
} break;
case RL_TEXTURE_MAG_FILTER:
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 matProjection = projection; // Projection matrix (perspective)
// Calculate model-view matrix combining matModel and matView
Matrix matModelView = MatrixMultiply(transform, matView); // Transform to camera-space coordinates
// TODO: Matrix nightmare! Trying to combine stack matrices with view matrix and local model transform matrix..
// 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)

View File

@ -77,9 +77,13 @@ typedef struct Stack {
size_t size;
} Stack;
#define MEMPOOL_BUCKET_SIZE 8
#define MEMPOOL_BUCKET_BITS 3
typedef struct MemPool {
AllocList freeList;
Stack stack;
MemNode *buckets[MEMPOOL_BUCKET_SIZE];
} MemPool;
// Object Pool
@ -164,10 +168,19 @@ static inline size_t __AlignSize(const size_t size, const size_t 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);
((*node)->next != NULL)? ((*node)->next->prev = (*node)->prev) : (*node = (*node)->prev);
if ((*node)->next != NULL) (*node)->next->prev = (*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.
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)
{
@ -229,8 +242,16 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
{
MemNode *new_mem = NULL;
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;
@ -242,9 +263,8 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
{
// Close in size - reduce fragmentation by not splitting.
new_mem = *inode;
__RemoveNode(inode);
__RemoveNode(mempool, inode);
mempool->freeList.len--;
new_mem->next = new_mem->prev = NULL;
break;
}
else
@ -253,7 +273,6 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
new_mem = (MemNode *)((uint8_t *)*inode + ((*inode)->size - ALLOC_SIZE));
(*inode)->size -= ALLOC_SIZE;
new_mem->size = ALLOC_SIZE;
new_mem->next = new_mem->prev = NULL;
break;
}
}
@ -272,19 +291,20 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
// Use the available mempool space as the new node.
new_mem = (MemNode *)mempool->stack.base;
new_mem->size = ALLOC_SIZE;
new_mem->next = new_mem->prev = NULL;
}
}
// Visual of the allocation 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 |
// | memory |
// | space | highest addr of block
// --------------
new_mem->next = new_mem->prev = NULL;
uint8_t *const final_mem = (uint8_t *)new_mem + sizeof *new_mem;
memset(final_mem, 0, new_mem->size - sizeof *new_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;
// NULL ptr should make this work like regular Allocation.
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
{
MemNode *node = (MemNode *)((uint8_t *)ptr - sizeof *node);
MemNode *const node = (MemNode *)((uint8_t *)ptr - 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;
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));
MemPoolFree(mempool, ptr);
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)
{
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
{
// 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.
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;
}
// 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.
// 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;
// This code inserts at head.
/*
( 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.
// This code insertion sorts where largest size is last.
if (mempool->freeList.head == NULL)
{
mempool->freeList.head = mempool->freeList.tail = mem_node;
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->prev = mem_node;
mempool->freeList.head = mem_node;
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;
mempool->freeList.tail->next = mem_node;
mempool->freeList.tail = mem_node;
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);
}
@ -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 (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;
}
@ -411,12 +426,29 @@ bool MemPoolDefrag(MemPool *const mempool)
// If the memory pool has been entirely released, fully defrag it.
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;
return true;
}
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;
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.
mempool->stack.base += (*node)->size;
(*node)->size = 0UL;
__RemoveNode(node);
__RemoveNode(mempool, node);
mempool->freeList.len--;
node = &mempool->freeList.head;
}
@ -475,6 +507,7 @@ bool MemPoolDefrag(MemPool *const mempool)
(*node)->size = 0UL;
(*node)->next->prev = (*node)->prev;
(*node)->prev->next = (*node)->next;
*node = (*node)->next;
mempool->freeList.len--;
node = &mempool->freeList.head;
@ -487,6 +520,7 @@ bool MemPoolDefrag(MemPool *const mempool)
(*node)->size = 0UL;
(*node)->next->prev = (*node)->prev;
(*node)->prev->next = (*node)->next;
*node = (*node)->prev;
mempool->freeList.len--;
node = &mempool->freeList.head;
@ -513,7 +547,7 @@ void ToggleMemPoolAutoDefrag(MemPool *const mempool)
//----------------------------------------------------------------------------------
union ObjInfo {
uint8_t *const byte;
size_t *const size;
size_t *const index;
};
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++)
{
union ObjInfo block = { .byte = &objpool.stack.mem[i*objpool.objSize] };
*block.size = i + 1;
*block.index = i + 1;
}
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++)
{
union ObjInfo block = { .byte = &objpool.stack.mem[i*objpool.objSize] };
*block.size = i + 1;
*block.index = i + 1;
}
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.
// 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);
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.
// *p = index of Head in relation to the buffer;
// 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->freeBlocks++;
}

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif
# 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
endif

View File

@ -236,7 +236,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif
# 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
endif

View File

@ -230,7 +230,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif
# 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
endif