Merge remote-tracking branch 'upstream/master'
4
.github/FUNDING.yml
vendored
|
|
@ -1,8 +1,8 @@
|
||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
github: raysan5
|
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
|
||||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
custom: # Replace with a single custom sponsorship URL
|
custom: # Replace with a single custom sponsorship URL
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to
|
||||||
- [cray](https://github.com/tapgg/cray) : raylib **Crystal** binding
|
- [cray](https://github.com/tapgg/cray) : raylib **Crystal** binding
|
||||||
- [Graphics::Raylib](https://metacpan.org/pod/Graphics::Raylib) : raylib **Perl** wrapper
|
- [Graphics::Raylib](https://metacpan.org/pod/Graphics::Raylib) : raylib **Perl** wrapper
|
||||||
- [raylib-pascal](https://github.com/drezgames/raylib-pascal) - raylib **Pascal** binding
|
- [raylib-pascal](https://github.com/drezgames/raylib-pascal) - raylib **Pascal** binding
|
||||||
|
- [raylib-pas](https://github.com/tazdij/raylib-pas) - raylib **Pascal** binding (including rlgl & raymath)
|
||||||
- [Raylib-cs](https://github.com/ChrisDill/Raylib-cs) : raylib **C#** binding
|
- [Raylib-cs](https://github.com/ChrisDill/Raylib-cs) : raylib **C#** binding
|
||||||
- [RaylibSharp](https://github.com/TheLumaio/RaylibSharp) : raylib **C#** binding
|
- [RaylibSharp](https://github.com/TheLumaio/RaylibSharp) : raylib **C#** binding
|
||||||
- [raylib-ruby-ffi](https://github.com/D3nX/raylib-ruby-ffi) : raylib **Ruby** binding
|
- [raylib-ruby-ffi](https://github.com/D3nX/raylib-ruby-ffi) : raylib **Ruby** binding
|
||||||
|
|
|
||||||
|
|
@ -385,9 +385,9 @@ EXAMPLES = \
|
||||||
shapes/shapes_draw_circle_sector \
|
shapes/shapes_draw_circle_sector \
|
||||||
shapes/shapes_draw_rectangle_rounded \
|
shapes/shapes_draw_rectangle_rounded \
|
||||||
text/text_raylib_fonts \
|
text/text_raylib_fonts \
|
||||||
text/text_sprite_fonts \
|
text/text_font_spritefont \
|
||||||
text/text_ttf_loading \
|
text/text_font_loading \
|
||||||
text/text_bmfont_ttf \
|
text/text_font_filters \
|
||||||
text/text_font_sdf \
|
text/text_font_sdf \
|
||||||
text/text_format_text \
|
text/text_format_text \
|
||||||
text/text_input_box \
|
text/text_input_box \
|
||||||
|
|
@ -420,8 +420,7 @@ EXAMPLES = \
|
||||||
models/models_material_pbr \
|
models/models_material_pbr \
|
||||||
models/models_mesh_generation \
|
models/models_mesh_generation \
|
||||||
models/models_mesh_picking \
|
models/models_mesh_picking \
|
||||||
models/models_obj_loading \
|
models/models_loading \
|
||||||
models/models_obj_viewer \
|
|
||||||
models/models_orthographic_projection \
|
models/models_orthographic_projection \
|
||||||
models/models_rlgl_solar_system \
|
models/models_rlgl_solar_system \
|
||||||
models/models_skybox \
|
models/models_skybox \
|
||||||
|
|
@ -438,6 +437,8 @@ EXAMPLES = \
|
||||||
shaders/shaders_julia_set \
|
shaders/shaders_julia_set \
|
||||||
shaders/shaders_eratosthenes \
|
shaders/shaders_eratosthenes \
|
||||||
shaders/shaders_basic_lighting \
|
shaders/shaders_basic_lighting \
|
||||||
|
shaders/shaders_fog \
|
||||||
|
shaders/shaders_simple_mask \
|
||||||
audio/audio_module_playing \
|
audio/audio_module_playing \
|
||||||
audio/audio_music_stream \
|
audio/audio_music_stream \
|
||||||
audio/audio_raw_stream \
|
audio/audio_raw_stream \
|
||||||
|
|
@ -471,7 +472,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
|
||||||
del *.o *.exe /s
|
del *.o *.exe /s
|
||||||
endif
|
endif
|
||||||
ifeq ($(PLATFORM_OS),LINUX)
|
ifeq ($(PLATFORM_OS),LINUX)
|
||||||
find -type f -executable | xargs file -i | grep -E 'x-object|x-archive|x-sharedlib|x-executable' | rev | cut -d ':' -f 2- | rev | xargs rm -fv
|
find -type f -executable | xargs file -i | grep -E 'x-object|x-archive|x-sharedlib|x-executable|x-pie-executable' | rev | cut -d ':' -f 2- | rev | xargs rm -fv
|
||||||
endif
|
endif
|
||||||
ifeq ($(PLATFORM_OS),OSX)
|
ifeq ($(PLATFORM_OS),OSX)
|
||||||
find . -type f -perm +ugo+x -delete
|
find . -type f -perm +ugo+x -delete
|
||||||
|
|
|
||||||
|
|
@ -46,13 +46,13 @@ int main(void)
|
||||||
circles[i].radius = GetRandomValue(10, 40);
|
circles[i].radius = GetRandomValue(10, 40);
|
||||||
circles[i].position.x = GetRandomValue(circles[i].radius, screenWidth - circles[i].radius);
|
circles[i].position.x = GetRandomValue(circles[i].radius, screenWidth - circles[i].radius);
|
||||||
circles[i].position.y = GetRandomValue(circles[i].radius, screenHeight - circles[i].radius);
|
circles[i].position.y = GetRandomValue(circles[i].radius, screenHeight - circles[i].radius);
|
||||||
circles[i].speed = (float)GetRandomValue(1, 100)/20000.0f;
|
circles[i].speed = (float)GetRandomValue(1, 100)/2000.0f;
|
||||||
circles[i].color = colors[GetRandomValue(0, 13)];
|
circles[i].color = colors[GetRandomValue(0, 13)];
|
||||||
}
|
}
|
||||||
|
|
||||||
Music xm = LoadMusicStream("resources/chiptun1.mod");
|
Music music = LoadMusicStream("resources/mini1111.xm");
|
||||||
|
|
||||||
PlayMusicStream(xm);
|
PlayMusicStream(music);
|
||||||
|
|
||||||
float timePlayed = 0.0f;
|
float timePlayed = 0.0f;
|
||||||
bool pause = false;
|
bool pause = false;
|
||||||
|
|
@ -65,13 +65,13 @@ int main(void)
|
||||||
{
|
{
|
||||||
// Update
|
// Update
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
UpdateMusicStream(xm); // Update music buffer with new stream data
|
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||||
|
|
||||||
// Restart music playing (stop and play)
|
// Restart music playing (stop and play)
|
||||||
if (IsKeyPressed(KEY_SPACE))
|
if (IsKeyPressed(KEY_SPACE))
|
||||||
{
|
{
|
||||||
StopMusicStream(xm);
|
StopMusicStream(music);
|
||||||
PlayMusicStream(xm);
|
PlayMusicStream(music);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pause/Resume music playing
|
// Pause/Resume music playing
|
||||||
|
|
@ -79,12 +79,12 @@ int main(void)
|
||||||
{
|
{
|
||||||
pause = !pause;
|
pause = !pause;
|
||||||
|
|
||||||
if (pause) PauseMusicStream(xm);
|
if (pause) PauseMusicStream(music);
|
||||||
else ResumeMusicStream(xm);
|
else ResumeMusicStream(music);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get timePlayed scaled to bar dimensions
|
// Get timePlayed scaled to bar dimensions
|
||||||
timePlayed = GetMusicTimePlayed(xm)/GetMusicTimeLength(xm)*(screenWidth - 40);
|
timePlayed = GetMusicTimePlayed(music)/GetMusicTimeLength(music)*(screenWidth - 40);
|
||||||
|
|
||||||
// Color circles animation
|
// Color circles animation
|
||||||
for (int i = MAX_CIRCLES - 1; (i >= 0) && !pause; i--)
|
for (int i = MAX_CIRCLES - 1; (i >= 0) && !pause; i--)
|
||||||
|
|
@ -101,7 +101,7 @@ int main(void)
|
||||||
circles[i].position.x = GetRandomValue(circles[i].radius, screenWidth - circles[i].radius);
|
circles[i].position.x = GetRandomValue(circles[i].radius, screenWidth - circles[i].radius);
|
||||||
circles[i].position.y = GetRandomValue(circles[i].radius, screenHeight - circles[i].radius);
|
circles[i].position.y = GetRandomValue(circles[i].radius, screenHeight - circles[i].radius);
|
||||||
circles[i].color = colors[GetRandomValue(0, 13)];
|
circles[i].color = colors[GetRandomValue(0, 13)];
|
||||||
circles[i].speed = (float)GetRandomValue(1, 100)/20000.0f;
|
circles[i].speed = (float)GetRandomValue(1, 100)/2000.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -128,7 +128,7 @@ int main(void)
|
||||||
|
|
||||||
// De-Initialization
|
// De-Initialization
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
UnloadMusicStream(xm); // Unload music stream buffers from RAM
|
UnloadMusicStream(music); // Unload music stream buffers from RAM
|
||||||
|
|
||||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ int main(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refill audio stream if required
|
// Refill audio stream if required
|
||||||
if (IsAudioBufferProcessed(stream))
|
if (IsAudioStreamProcessed(stream))
|
||||||
{
|
{
|
||||||
// Synthesize a buffer that is exactly the requested size
|
// Synthesize a buffer that is exactly the requested size
|
||||||
int writeCursor = 0;
|
int writeCursor = 0;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ int main(void)
|
||||||
|
|
||||||
Camera2D camera = { 0 };
|
Camera2D camera = { 0 };
|
||||||
camera.target = (Vector2){ player.x + 20, player.y + 20 };
|
camera.target = (Vector2){ player.x + 20, player.y + 20 };
|
||||||
camera.offset = (Vector2){ 0, 0 };
|
camera.offset = (Vector2){ screenWidth/2, screenHeight/2 };
|
||||||
camera.rotation = 0.0f;
|
camera.rotation = 0.0f;
|
||||||
camera.zoom = 1.0f;
|
camera.zoom = 1.0f;
|
||||||
|
|
||||||
|
|
@ -54,16 +54,10 @@ int main(void)
|
||||||
{
|
{
|
||||||
// Update
|
// Update
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
if (IsKeyDown(KEY_RIGHT))
|
|
||||||
{
|
// Player movement
|
||||||
player.x += 2; // Player movement
|
if (IsKeyDown(KEY_RIGHT)) player.x += 2;
|
||||||
camera.offset.x -= 2; // Camera displacement with player movement
|
else if (IsKeyDown(KEY_LEFT)) player.x -= 2;
|
||||||
}
|
|
||||||
else if (IsKeyDown(KEY_LEFT))
|
|
||||||
{
|
|
||||||
player.x -= 2; // Player movement
|
|
||||||
camera.offset.x += 2; // Camera displacement with player movement
|
|
||||||
}
|
|
||||||
|
|
||||||
// Camera target follows player
|
// Camera target follows player
|
||||||
camera.target = (Vector2){ player.x + 20, player.y + 20 };
|
camera.target = (Vector2){ player.x + 20, player.y + 20 };
|
||||||
|
|
@ -135,4 +129,4 @@ int main(void)
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
284
examples/core/core_2d_camera_ext.c
Normal file
|
|
@ -0,0 +1,284 @@
|
||||||
|
/*******************************************************************************************
|
||||||
|
*
|
||||||
|
* raylib [core] example - 2d camera extended
|
||||||
|
*
|
||||||
|
* This example has been created using raylib 1.5 (www.raylib.com)
|
||||||
|
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 Ramon Santamaria (@raysan5)
|
||||||
|
*
|
||||||
|
********************************************************************************************/
|
||||||
|
|
||||||
|
#include "raylib.h"
|
||||||
|
#include "raymath.h"
|
||||||
|
|
||||||
|
#define G 400
|
||||||
|
#define PLAYER_JUMP_SPD 350.f
|
||||||
|
#define PLAYER_HOR_SPD 200.f
|
||||||
|
|
||||||
|
typedef struct Player {
|
||||||
|
Vector2 pos;
|
||||||
|
float vel;
|
||||||
|
int canJump;
|
||||||
|
} Player;
|
||||||
|
|
||||||
|
typedef struct EnvItem {
|
||||||
|
Rectangle rect;
|
||||||
|
int blocking;
|
||||||
|
Color color;
|
||||||
|
} EnvItem;
|
||||||
|
|
||||||
|
void updateCameraCenter(
|
||||||
|
float delta,
|
||||||
|
Camera2D *camera,
|
||||||
|
Player *player,
|
||||||
|
EnvItem *envItems,
|
||||||
|
int envItemsLength,
|
||||||
|
int width, int height
|
||||||
|
) {
|
||||||
|
camera->offset = (Vector2){ width/2, height/2 };
|
||||||
|
camera->target = player->pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateCameraCenterInsideMap(
|
||||||
|
float delta,
|
||||||
|
Camera2D *camera,
|
||||||
|
Player *player,
|
||||||
|
EnvItem *envItems,
|
||||||
|
int envItemsLength,
|
||||||
|
int width, int height
|
||||||
|
) {
|
||||||
|
camera->target = player->pos;
|
||||||
|
camera->offset = (Vector2){ width/2, height/2 };
|
||||||
|
float minX = 1000, minY = 1000, maxX = -1000, maxY = -1000;
|
||||||
|
for (int i = 0; i < envItemsLength; i++) {
|
||||||
|
EnvItem *ei = envItems + i;
|
||||||
|
minX = fminf(ei->rect.x, minX);
|
||||||
|
maxX = fmaxf(ei->rect.x + ei->rect.width, maxX);
|
||||||
|
minY = fminf(ei->rect.y, minY);
|
||||||
|
maxY = fmaxf(ei->rect.y + ei->rect.height, maxY);
|
||||||
|
}
|
||||||
|
Vector2 max = GetWorldToScreen2D((Vector2){ maxX, maxY }, *camera);
|
||||||
|
Vector2 min = GetWorldToScreen2D((Vector2){ minX, minY }, *camera);
|
||||||
|
if (max.x < width) {
|
||||||
|
camera->offset.x = width - (max.x - width/2);
|
||||||
|
}
|
||||||
|
if (max.y < height) {
|
||||||
|
camera->offset.y = height - (max.y - height/2);
|
||||||
|
}
|
||||||
|
if (min.x > 0) {
|
||||||
|
camera->offset.x = width/2 - min.x;
|
||||||
|
}
|
||||||
|
if (min.y > 0) {
|
||||||
|
camera->offset.y = height/2- min.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateCameraCenterSmoothFollow(
|
||||||
|
float delta,
|
||||||
|
Camera2D *camera,
|
||||||
|
Player *player,
|
||||||
|
EnvItem *envItems,
|
||||||
|
int envItemsLength,
|
||||||
|
int width, int height
|
||||||
|
) {
|
||||||
|
static float minSpeed = 30;
|
||||||
|
static float minEffectLength = 10;
|
||||||
|
static float fractionSpeed = 0.8f;
|
||||||
|
camera->offset = (Vector2){ width/2, height/2 };
|
||||||
|
Vector2 diff = Vector2Subtract(player->pos, camera->target);
|
||||||
|
float length = Vector2Length(diff);
|
||||||
|
if (length > minEffectLength) {
|
||||||
|
float speed = fmaxf(fractionSpeed * length, minSpeed);
|
||||||
|
camera->target = Vector2Add(camera->target, Vector2Scale(diff, speed*delta/length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateCameraEvenOutOnLanding(
|
||||||
|
float delta,
|
||||||
|
Camera2D *camera,
|
||||||
|
Player *player,
|
||||||
|
EnvItem *envItems,
|
||||||
|
int envItemsLength,
|
||||||
|
int width, int height
|
||||||
|
) {
|
||||||
|
static float evenOutSpeed = 700;
|
||||||
|
static int eveningOut = false;
|
||||||
|
static float evenOutTarget;
|
||||||
|
camera->offset = (Vector2){ width/2, height/2 };
|
||||||
|
camera->target.x = player->pos.x;
|
||||||
|
if (eveningOut) {
|
||||||
|
if (evenOutTarget > camera->target.y) {
|
||||||
|
camera->target.y += evenOutSpeed * delta;
|
||||||
|
if (camera->target.y > evenOutTarget) {
|
||||||
|
camera->target.y = evenOutTarget;
|
||||||
|
eveningOut = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
camera->target.y -= evenOutSpeed * delta;
|
||||||
|
if (camera->target.y < evenOutTarget) {
|
||||||
|
camera->target.y = evenOutTarget;
|
||||||
|
eveningOut = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (player->canJump &&
|
||||||
|
player->vel == 0 &&
|
||||||
|
player->pos.y != camera->target.y
|
||||||
|
) {
|
||||||
|
eveningOut = 1;
|
||||||
|
evenOutTarget = player->pos.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateCameraPlayerBoundsPush(
|
||||||
|
float delta,
|
||||||
|
Camera2D *camera,
|
||||||
|
Player *player,
|
||||||
|
EnvItem *envItems,
|
||||||
|
int envItemsLength,
|
||||||
|
int width, int height
|
||||||
|
) {
|
||||||
|
static Vector2 bbox = { 0.2f, 0.2f };
|
||||||
|
|
||||||
|
Vector2 bboxWorldMin = GetScreenToWorld2D((Vector2){ (1 - bbox.x) * 0.5 * width, (1 - bbox.y) * 0.5 * height }, *camera);
|
||||||
|
Vector2 bboxWorldMax = GetScreenToWorld2D((Vector2){ (1 + bbox.x) * 0.5 * width, (1 + bbox.y) * 0.5 * height }, *camera);
|
||||||
|
camera->offset = (Vector2){ (1 - bbox.x) * 0.5 * width, (1 - bbox.y) * 0.5 * height };
|
||||||
|
|
||||||
|
if (player->pos.x < bboxWorldMin.x) {
|
||||||
|
camera->target.x = player->pos.x;
|
||||||
|
}
|
||||||
|
if (player->pos.y < bboxWorldMin.y) {
|
||||||
|
camera->target.y = player->pos.y;
|
||||||
|
}
|
||||||
|
if (player->pos.x > bboxWorldMax.x) {
|
||||||
|
camera->target.x = bboxWorldMin.x + (player->pos.x - bboxWorldMax.x);
|
||||||
|
}
|
||||||
|
if (player->pos.y > bboxWorldMax.y) {
|
||||||
|
camera->target.y = bboxWorldMin.y + (player->pos.y - bboxWorldMax.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void updatePlayer(float delta, Player *player, EnvItem *envItems, int envItemsLength) {
|
||||||
|
if (IsKeyDown(KEY_LEFT)) player->pos.x -= PLAYER_HOR_SPD*delta;
|
||||||
|
if (IsKeyDown(KEY_RIGHT)) player->pos.x += PLAYER_HOR_SPD*delta;
|
||||||
|
if (IsKeyDown(KEY_SPACE) && player->canJump) {
|
||||||
|
player->vel = -PLAYER_JUMP_SPD;
|
||||||
|
player->canJump = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hitObstacle = 0;
|
||||||
|
for (int i = 0; i < envItemsLength; i++) {
|
||||||
|
EnvItem *ei = envItems + i;
|
||||||
|
Vector2 *p = &(player->pos);
|
||||||
|
if (ei->blocking &&
|
||||||
|
ei->rect.x <= p->x &&
|
||||||
|
ei->rect.x + ei->rect.width >= p->x &&
|
||||||
|
ei->rect.y >= p->y &&
|
||||||
|
ei->rect.y < p->y + player->vel * delta)
|
||||||
|
{
|
||||||
|
hitObstacle = 1;
|
||||||
|
player->vel = 0.0f;
|
||||||
|
p->y = ei->rect.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hitObstacle) {
|
||||||
|
player->pos.y += player->vel * delta;
|
||||||
|
player->vel += G * delta;
|
||||||
|
player->canJump = 0;
|
||||||
|
} else {
|
||||||
|
player->canJump = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderWorld(Player *player, EnvItem *envItems, int envItemsLength) {
|
||||||
|
for (int i = 0; i < envItemsLength; i++) {
|
||||||
|
DrawRectangleRec(envItems[i].rect, envItems[i].color);
|
||||||
|
}
|
||||||
|
Rectangle playerRect = { player->pos.x - 20, player->pos.y - 40, 40, 40 };
|
||||||
|
DrawRectangleRec(playerRect, RED);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const int screenWidth = 800;
|
||||||
|
const int screenHeight = 450;
|
||||||
|
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera");
|
||||||
|
SetTargetFPS(60);
|
||||||
|
|
||||||
|
Player player;
|
||||||
|
player.pos = (Vector2){ 400, 280 };
|
||||||
|
player.vel = 0;
|
||||||
|
player.canJump = 0;
|
||||||
|
EnvItem envItems[] = {
|
||||||
|
{{ 0, 0, 1000, 400 }, 0, LIGHTGRAY },
|
||||||
|
{{ 0, 400, 1000, 200 }, 1, GRAY },
|
||||||
|
{{ 300, 200, 400, 10 }, 1, GRAY },
|
||||||
|
{{ 250, 300, 100, 10 }, 1, GRAY },
|
||||||
|
{{ 650, 300, 100, 10 }, 1, GRAY }
|
||||||
|
};
|
||||||
|
int envItemsLength = sizeof(envItems) / sizeof (envItems[0]);
|
||||||
|
|
||||||
|
Camera2D camera = { 0 };
|
||||||
|
camera.target = player.pos;
|
||||||
|
camera.offset = (Vector2){ screenWidth/2, screenHeight/2 };
|
||||||
|
camera.rotation = 0.0f;
|
||||||
|
camera.zoom = 1.0f;
|
||||||
|
|
||||||
|
int cameraOption = 0;
|
||||||
|
void (*cameraUpdaters[])(float, Camera2D*, Player*, EnvItem*, int, int, int) = {
|
||||||
|
updateCameraCenter,
|
||||||
|
updateCameraCenterInsideMap,
|
||||||
|
updateCameraCenterSmoothFollow,
|
||||||
|
updateCameraEvenOutOnLanding,
|
||||||
|
updateCameraPlayerBoundsPush
|
||||||
|
};
|
||||||
|
int cameraUpdatersLength = sizeof(cameraUpdaters) / sizeof(cameraUpdaters[0]);
|
||||||
|
char* cameraDescriptions[] = {
|
||||||
|
"Follow player center",
|
||||||
|
"Follow player center, but clamp to map edges",
|
||||||
|
"Follow player center; smoothed",
|
||||||
|
"Follow player center horizontally; updateplayer center vertically after landing",
|
||||||
|
"Player push camera on getting too close to screen edge"
|
||||||
|
};
|
||||||
|
|
||||||
|
while (!WindowShouldClose()) {
|
||||||
|
float delta = GetFrameTime();
|
||||||
|
updatePlayer(delta, &player, envItems, envItemsLength);
|
||||||
|
|
||||||
|
camera.zoom += ((float)GetMouseWheelMove()*0.05f);
|
||||||
|
if (camera.zoom > 3.0f) camera.zoom = 3.0f;
|
||||||
|
else if (camera.zoom < 0.25f) camera.zoom = 0.25f;
|
||||||
|
if (IsKeyPressed(KEY_R))
|
||||||
|
{
|
||||||
|
camera.zoom = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsKeyPressed(KEY_C)) {
|
||||||
|
cameraOption = (cameraOption + 1) % cameraUpdatersLength;
|
||||||
|
}
|
||||||
|
cameraUpdaters[cameraOption](delta, &camera, &player, envItems, envItemsLength, screenWidth, screenHeight);
|
||||||
|
|
||||||
|
BeginDrawing();
|
||||||
|
ClearBackground(RAYWHITE);
|
||||||
|
|
||||||
|
BeginMode2D(camera);
|
||||||
|
renderWorld(&player, envItems, envItemsLength);
|
||||||
|
EndMode2D();
|
||||||
|
|
||||||
|
DrawText("Controls:", 20, 20, 10, BLACK);
|
||||||
|
DrawText("- Right/Left to move", 40, 40, 10, DARKGRAY);
|
||||||
|
DrawText("- Space to jump", 40, 60, 10, DARKGRAY);
|
||||||
|
DrawText("- Mouse Wheel to Zoom in-out, R to reset zoom", 40, 80, 10, DARKGRAY);
|
||||||
|
DrawText("- C to change camera mode", 40, 100, 10, DARKGRAY);
|
||||||
|
DrawText("Current camera mode:", 20, 120, 10, BLACK);
|
||||||
|
DrawText(cameraDescriptions[cameraOption], 40, 140, 10, DARKGRAY);
|
||||||
|
EndDrawing();
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseWindow(); // Close window and OpenGL context
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -23,40 +23,40 @@
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
// Initialization
|
// Initialization
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
|
|
||||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
|
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
|
||||||
|
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
//--------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Main game loop
|
|
||||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
|
||||||
{
|
|
||||||
// Update
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
// TODO: Update your variables here
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Draw
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
BeginDrawing();
|
|
||||||
|
|
||||||
ClearBackground(RAYWHITE);
|
|
||||||
|
|
||||||
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
|
|
||||||
|
|
||||||
EndDrawing();
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
}
|
|
||||||
|
|
||||||
// De-Initialization
|
|
||||||
//--------------------------------------------------------------------------------------
|
|
||||||
CloseWindow(); // Close window and OpenGL context
|
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
return 0;
|
// Main game loop
|
||||||
|
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||||
|
{
|
||||||
|
// Update
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// TODO: Update your variables here
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
BeginDrawing();
|
||||||
|
|
||||||
|
ClearBackground(RAYWHITE);
|
||||||
|
|
||||||
|
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
|
||||||
|
|
||||||
|
EndDrawing();
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
}
|
||||||
|
|
||||||
|
// De-Initialization
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
CloseWindow(); // Close window and OpenGL context
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -11,14 +11,14 @@ uniform sampler2D texture0;
|
||||||
uniform vec4 colDiffuse;
|
uniform vec4 colDiffuse;
|
||||||
|
|
||||||
// NOTE: Add here your custom variables
|
// NOTE: Add here your custom variables
|
||||||
uniform vec2 leftLensCenter = vec2(0.288, 0.5);
|
uniform vec2 leftLensCenter;
|
||||||
uniform vec2 rightLensCenter = vec2(0.712, 0.5);
|
uniform vec2 rightLensCenter;
|
||||||
uniform vec2 leftScreenCenter = vec2(0.25, 0.5);
|
uniform vec2 leftScreenCenter;
|
||||||
uniform vec2 rightScreenCenter = vec2(0.75, 0.5);
|
uniform vec2 rightScreenCenter;
|
||||||
uniform vec2 scale = vec2(0.25, 0.45);
|
uniform vec2 scale;
|
||||||
uniform vec2 scaleIn = vec2(4, 2.2222);
|
uniform vec2 scaleIn;
|
||||||
uniform vec4 hmdWarpParam = vec4(1, 0.22, 0.24, 0);
|
uniform vec4 hmdWarpParam;
|
||||||
uniform vec4 chromaAbParam = vec4(0.996, -0.004, 1.014, 0.0);
|
uniform vec4 chromaAbParam;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,15 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019 Culacant (@culacant) and Ramon Santamaria (@raysan5)
|
* Copyright (c) 2019 Culacant (@culacant) and Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
|
********************************************************************************************
|
||||||
|
*
|
||||||
|
* To export a model from blender, make sure it is not posed, the vertices need to be in the
|
||||||
|
* same position as they would be in edit mode.
|
||||||
|
* and that the scale of your models is set to 0. Scaling can be done from the export menu.
|
||||||
|
*
|
||||||
********************************************************************************************/
|
********************************************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
|
|
@ -91,8 +98,11 @@ int main(void)
|
||||||
|
|
||||||
// De-Initialization
|
// De-Initialization
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
UnloadTexture(texture); // Unload texture
|
||||||
|
|
||||||
// Unload model animations data
|
// Unload model animations data
|
||||||
for (int i = 0; i < animsCount; i++) UnloadModelAnimation(anims[i]);
|
for (int i = 0; i < animsCount; i++) UnloadModelAnimation(anims[i]);
|
||||||
|
RL_FREE(anims);
|
||||||
|
|
||||||
UnloadModel(model); // Unload model
|
UnloadModel(model); // Unload model
|
||||||
|
|
||||||
|
|
|
||||||
142
examples/models/models_loading.c
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*******************************************************************************************
|
||||||
|
*
|
||||||
|
* raylib [models] example - Models loading
|
||||||
|
*
|
||||||
|
* raylib supports multiple models file formats:
|
||||||
|
*
|
||||||
|
* - OBJ > Text file, must include vertex position-texcoords-normals information,
|
||||||
|
* if files references some .mtl materials file, it will be loaded (or try to)
|
||||||
|
* - GLTF > Modern text/binary file format, includes lot of information and it could
|
||||||
|
* also reference external files, raylib will try loading mesh and materials data
|
||||||
|
* - IQM > Binary file format including mesh vertex data but also animation data,
|
||||||
|
* raylib can load .iqm animations.
|
||||||
|
*
|
||||||
|
* This example has been created using raylib 2.6 (www.raylib.com)
|
||||||
|
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
|
||||||
|
*
|
||||||
|
********************************************************************************************/
|
||||||
|
|
||||||
|
#include "raylib.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
// Initialization
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
const int screenWidth = 800;
|
||||||
|
const int screenHeight = 450;
|
||||||
|
|
||||||
|
InitWindow(screenWidth, screenHeight, "raylib [models] example - models loading");
|
||||||
|
|
||||||
|
// Define the camera to look into our 3d world
|
||||||
|
Camera camera = { 0 };
|
||||||
|
camera.position = (Vector3){ 50.0f, 50.0f, 50.0f }; // Camera position
|
||||||
|
camera.target = (Vector3){ 0.0f, 10.0f, 0.0f }; // Camera looking at point
|
||||||
|
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target)
|
||||||
|
camera.fovy = 45.0f; // Camera field-of-view Y
|
||||||
|
camera.type = CAMERA_PERSPECTIVE; // Camera mode type
|
||||||
|
|
||||||
|
Model model = LoadModel("resources/models/castle.obj"); // Load model
|
||||||
|
Texture2D texture = LoadTexture("resources/models/castle_diffuse.png"); // Load model texture
|
||||||
|
model.materials[0].maps[MAP_DIFFUSE].texture = texture; // Set map diffuse texture
|
||||||
|
|
||||||
|
Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
|
||||||
|
|
||||||
|
BoundingBox bounds = MeshBoundingBox(model.meshes[0]); // Set model bounds
|
||||||
|
|
||||||
|
// NOTE: bounds are calculated from the original size of the model,
|
||||||
|
// if model is scaled on drawing, bounds must be also scaled
|
||||||
|
|
||||||
|
SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode
|
||||||
|
|
||||||
|
bool selected = false; // Selected object flag
|
||||||
|
|
||||||
|
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Main game loop
|
||||||
|
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||||
|
{
|
||||||
|
// Update
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
UpdateCamera(&camera);
|
||||||
|
|
||||||
|
// Load new models/textures on drag&drop
|
||||||
|
if (IsFileDropped())
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
char **droppedFiles = GetDroppedFiles(&count);
|
||||||
|
|
||||||
|
if (count == 1) // Only support one file dropped
|
||||||
|
{
|
||||||
|
if (IsFileExtension(droppedFiles[0], ".obj") ||
|
||||||
|
IsFileExtension(droppedFiles[0], ".gltf") ||
|
||||||
|
IsFileExtension(droppedFiles[0], ".iqm")) // Model file formats supported
|
||||||
|
{
|
||||||
|
UnloadModel(model); // Unload previous model
|
||||||
|
model = LoadModel(droppedFiles[0]); // Load new model
|
||||||
|
model.materials[0].maps[MAP_DIFFUSE].texture = texture; // Set current map diffuse texture
|
||||||
|
|
||||||
|
bounds = MeshBoundingBox(model.meshes[0]);
|
||||||
|
|
||||||
|
// TODO: Move camera position from target enough distance to visualize model properly
|
||||||
|
}
|
||||||
|
else if (IsFileExtension(droppedFiles[0], ".png")) // Texture file formats supported
|
||||||
|
{
|
||||||
|
// Unload current model texture and load new one
|
||||||
|
UnloadTexture(texture);
|
||||||
|
texture = LoadTexture(droppedFiles[0]);
|
||||||
|
model.materials[0].maps[MAP_DIFFUSE].texture = texture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearDroppedFiles(); // Clear internal buffers
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select model on mouse click
|
||||||
|
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
|
||||||
|
{
|
||||||
|
// Check collision between ray and box
|
||||||
|
if (CheckCollisionRayBox(GetMouseRay(GetMousePosition(), camera), bounds)) selected = !selected;
|
||||||
|
else selected = false;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
BeginDrawing();
|
||||||
|
|
||||||
|
ClearBackground(RAYWHITE);
|
||||||
|
|
||||||
|
BeginMode3D(camera);
|
||||||
|
|
||||||
|
DrawModel(model, position, 1.0f, WHITE); // Draw 3d model with texture
|
||||||
|
|
||||||
|
DrawGrid(20, 10.0f); // Draw a grid
|
||||||
|
|
||||||
|
if (selected) DrawBoundingBox(bounds, GREEN); // Draw selection box
|
||||||
|
|
||||||
|
EndMode3D();
|
||||||
|
|
||||||
|
DrawText("Drag & drop model to load mesh/texture.", 10, GetScreenHeight() - 20, 10, DARKGRAY);
|
||||||
|
if (selected) DrawText("MODEL SELECTED", GetScreenWidth() - 110, 10, 10, GREEN);
|
||||||
|
|
||||||
|
DrawText("(c) Castle 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, GRAY);
|
||||||
|
|
||||||
|
DrawFPS(10, 10);
|
||||||
|
|
||||||
|
EndDrawing();
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
}
|
||||||
|
|
||||||
|
// De-Initialization
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
UnloadTexture(texture); // Unload texture
|
||||||
|
UnloadModel(model); // Unload model
|
||||||
|
|
||||||
|
CloseWindow(); // Close window and OpenGL context
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
examples/models/models_loading.png
Normal file
|
After Width: | Height: | Size: 217 KiB |
|
|
@ -50,16 +50,15 @@ int main(void)
|
||||||
// NOTE: New VBO for tangents is generated at default location and also binded to mesh VAO
|
// NOTE: New VBO for tangents is generated at default location and also binded to mesh VAO
|
||||||
MeshTangents(&model.meshes[0]);
|
MeshTangents(&model.meshes[0]);
|
||||||
|
|
||||||
|
UnloadMaterial(model.materials[0]); // get rid of default material
|
||||||
model.materials[0] = LoadMaterialPBR((Color){ 255, 255, 255, 255 }, 1.0f, 1.0f);
|
model.materials[0] = LoadMaterialPBR((Color){ 255, 255, 255, 255 }, 1.0f, 1.0f);
|
||||||
|
|
||||||
// Define lights attributes
|
// Create lights
|
||||||
// NOTE: Shader is passed to every light on creation to define shader bindings internally
|
// NOTE: Lights are added to an internal lights pool automatically
|
||||||
Light lights[MAX_LIGHTS] = {
|
CreateLight(LIGHT_POINT, (Vector3){ LIGHT_DISTANCE, LIGHT_HEIGHT, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 255, 0, 0, 255 }, model.materials[0].shader);
|
||||||
CreateLight(LIGHT_POINT, (Vector3){ LIGHT_DISTANCE, LIGHT_HEIGHT, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 255, 0, 0, 255 }, model.materials[0].shader),
|
CreateLight(LIGHT_POINT, (Vector3){ 0.0f, LIGHT_HEIGHT, LIGHT_DISTANCE }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 0, 255, 0, 255 }, model.materials[0].shader);
|
||||||
CreateLight(LIGHT_POINT, (Vector3){ 0.0f, LIGHT_HEIGHT, LIGHT_DISTANCE }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 0, 255, 0, 255 }, model.materials[0].shader),
|
CreateLight(LIGHT_POINT, (Vector3){ -LIGHT_DISTANCE, LIGHT_HEIGHT, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 0, 0, 255, 255 }, model.materials[0].shader);
|
||||||
CreateLight(LIGHT_POINT, (Vector3){ -LIGHT_DISTANCE, LIGHT_HEIGHT, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 0, 0, 255, 255 }, model.materials[0].shader),
|
CreateLight(LIGHT_DIRECTIONAL, (Vector3){ 0.0f, LIGHT_HEIGHT*2.0f, -LIGHT_DISTANCE }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 255, 0, 255, 255 }, model.materials[0].shader);
|
||||||
CreateLight(LIGHT_DIRECTIONAL, (Vector3){ 0.0f, LIGHT_HEIGHT*2.0f, -LIGHT_DISTANCE }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 255, 0, 255, 255 }, model.materials[0].shader)
|
|
||||||
};
|
|
||||||
|
|
||||||
SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode
|
SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode
|
||||||
|
|
||||||
|
|
@ -100,7 +99,20 @@ int main(void)
|
||||||
|
|
||||||
// De-Initialization
|
// De-Initialization
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
UnloadModel(model); // Unload skybox model
|
|
||||||
|
// Shaders and textures must be unloaded by user,
|
||||||
|
// they could be in use by other models
|
||||||
|
UnloadTexture(model.materials[0].maps[MAP_ALBEDO].texture);
|
||||||
|
UnloadTexture(model.materials[0].maps[MAP_NORMAL].texture);
|
||||||
|
UnloadTexture(model.materials[0].maps[MAP_METALNESS].texture);
|
||||||
|
UnloadTexture(model.materials[0].maps[MAP_ROUGHNESS].texture);
|
||||||
|
UnloadTexture(model.materials[0].maps[MAP_OCCLUSION].texture);
|
||||||
|
UnloadTexture(model.materials[0].maps[MAP_IRRADIANCE].texture);
|
||||||
|
UnloadTexture(model.materials[0].maps[MAP_PREFILTER].texture);
|
||||||
|
UnloadTexture(model.materials[0].maps[MAP_BRDF].texture);
|
||||||
|
UnloadShader(model.materials[0].shader);
|
||||||
|
|
||||||
|
UnloadModel(model); // Unload model
|
||||||
|
|
||||||
CloseWindow(); // Close window and OpenGL context
|
CloseWindow(); // Close window and OpenGL context
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
@ -112,8 +124,8 @@ int main(void)
|
||||||
// NOTE: PBR shader is loaded inside this function
|
// NOTE: PBR shader is loaded inside this function
|
||||||
static Material LoadMaterialPBR(Color albedo, float metalness, float roughness)
|
static Material LoadMaterialPBR(Color albedo, float metalness, float roughness)
|
||||||
{
|
{
|
||||||
Material mat = { 0 }; // NOTE: All maps textures are set to { 0 }
|
Material mat = LoadMaterialDefault(); // Initialize material to default
|
||||||
|
|
||||||
#if defined(PLATFORM_DESKTOP)
|
#if defined(PLATFORM_DESKTOP)
|
||||||
mat.shader = LoadShader("resources/shaders/glsl330/pbr.vs", "resources/shaders/glsl330/pbr.fs");
|
mat.shader = LoadShader("resources/shaders/glsl330/pbr.vs", "resources/shaders/glsl330/pbr.fs");
|
||||||
#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB
|
#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB
|
||||||
|
|
@ -135,7 +147,7 @@ static Material LoadMaterialPBR(Color albedo, float metalness, float roughness)
|
||||||
|
|
||||||
// Set view matrix location
|
// Set view matrix location
|
||||||
mat.shader.locs[LOC_MATRIX_MODEL] = GetShaderLocation(mat.shader, "matModel");
|
mat.shader.locs[LOC_MATRIX_MODEL] = GetShaderLocation(mat.shader, "matModel");
|
||||||
mat.shader.locs[LOC_MATRIX_VIEW] = GetShaderLocation(mat.shader, "view");
|
//mat.shader.locs[LOC_MATRIX_VIEW] = GetShaderLocation(mat.shader, "view");
|
||||||
mat.shader.locs[LOC_VECTOR_VIEW] = GetShaderLocation(mat.shader, "viewPos");
|
mat.shader.locs[LOC_VECTOR_VIEW] = GetShaderLocation(mat.shader, "viewPos");
|
||||||
|
|
||||||
// Set PBR standard maps
|
// Set PBR standard maps
|
||||||
|
|
|
||||||
|
|
@ -115,11 +115,12 @@ int main(void)
|
||||||
|
|
||||||
// De-Initialization
|
// De-Initialization
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
UnloadTexture(texture); // Unload texture
|
||||||
|
|
||||||
// Unload models data (GPU VRAM)
|
// Unload models data (GPU VRAM)
|
||||||
for (int i = 0; i < NUM_MODELS; i++) UnloadModel(models[i]);
|
for (int i = 0; i < NUM_MODELS; i++) UnloadModel(models[i]);
|
||||||
|
|
||||||
CloseWindow(); // Close window and OpenGL context
|
CloseWindow(); // Close window and OpenGL context
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ int main(void)
|
||||||
|
|
||||||
// Check ray collision against model
|
// Check ray collision against model
|
||||||
// NOTE: It considers model.transform matrix!
|
// NOTE: It considers model.transform matrix!
|
||||||
meshHitInfo = GetCollisionRayModel(ray, &tower);
|
meshHitInfo = GetCollisionRayModel(ray, tower);
|
||||||
|
|
||||||
if ((meshHitInfo.hit) && (meshHitInfo.distance < nearestHit.distance))
|
if ((meshHitInfo.hit) && (meshHitInfo.distance < nearestHit.distance))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
/*******************************************************************************************
|
|
||||||
*
|
|
||||||
* raylib [models] example - Load and draw a 3d model (OBJ)
|
|
||||||
*
|
|
||||||
* This example has been created using raylib 1.3 (www.raylib.com)
|
|
||||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2014 Ramon Santamaria (@raysan5)
|
|
||||||
*
|
|
||||||
********************************************************************************************/
|
|
||||||
|
|
||||||
#include "raylib.h"
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
// Initialization
|
|
||||||
//--------------------------------------------------------------------------------------
|
|
||||||
const int screenWidth = 800;
|
|
||||||
const int screenHeight = 450;
|
|
||||||
|
|
||||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - obj model loading");
|
|
||||||
|
|
||||||
// Define the camera to look into our 3d world
|
|
||||||
Camera camera = { 0 };
|
|
||||||
camera.position = (Vector3){ 8.0f, 8.0f, 8.0f }; // Camera position
|
|
||||||
camera.target = (Vector3){ 0.0f, 2.5f, 0.0f }; // Camera looking at point
|
|
||||||
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target)
|
|
||||||
camera.fovy = 45.0f; // Camera field-of-view Y
|
|
||||||
camera.type = CAMERA_PERSPECTIVE; // Camera mode type
|
|
||||||
|
|
||||||
Model model = LoadModel("resources/models/castle.obj"); // Load OBJ model
|
|
||||||
Texture2D texture = LoadTexture("resources/models/castle_diffuse.png"); // Load model texture
|
|
||||||
model.materials[0].maps[MAP_DIFFUSE].texture = texture; // Set map diffuse texture
|
|
||||||
Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
|
|
||||||
|
|
||||||
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
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
//...
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Draw
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
BeginDrawing();
|
|
||||||
|
|
||||||
ClearBackground(RAYWHITE);
|
|
||||||
|
|
||||||
BeginMode3D(camera);
|
|
||||||
|
|
||||||
DrawModel(model, position, 0.2f, WHITE); // Draw 3d model with texture
|
|
||||||
|
|
||||||
DrawGrid(10, 1.0f); // Draw a grid
|
|
||||||
|
|
||||||
DrawGizmo(position); // Draw gizmo
|
|
||||||
|
|
||||||
EndMode3D();
|
|
||||||
|
|
||||||
DrawText("(c) Castle 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, GRAY);
|
|
||||||
|
|
||||||
DrawFPS(10, 10);
|
|
||||||
|
|
||||||
EndDrawing();
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
}
|
|
||||||
|
|
||||||
// De-Initialization
|
|
||||||
//--------------------------------------------------------------------------------------
|
|
||||||
UnloadTexture(texture); // Unload texture
|
|
||||||
UnloadModel(model); // Unload model
|
|
||||||
|
|
||||||
CloseWindow(); // Close window and OpenGL context
|
|
||||||
//--------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 260 KiB |
|
|
@ -1,127 +0,0 @@
|
||||||
/*******************************************************************************************
|
|
||||||
*
|
|
||||||
* raylib [models] example - OBJ models viewer
|
|
||||||
*
|
|
||||||
* This example has been created using raylib 2.0 (www.raylib.com)
|
|
||||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
|
|
||||||
*
|
|
||||||
********************************************************************************************/
|
|
||||||
|
|
||||||
#include "raylib.h"
|
|
||||||
|
|
||||||
#include <string.h> // Required for: strcpy()
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
// Initialization
|
|
||||||
//--------------------------------------------------------------------------------------
|
|
||||||
const int screenWidth = 800;
|
|
||||||
const int screenHeight = 450;
|
|
||||||
|
|
||||||
InitWindow(screenWidth, screenHeight, "raylib example - obj viewer");
|
|
||||||
|
|
||||||
// Define the camera to look into our 3d world
|
|
||||||
Camera camera = { { 30.0f, 30.0f, 30.0f }, { 0.0f, 10.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 };
|
|
||||||
|
|
||||||
Model model = LoadModel("resources/models/turret.obj"); // Load default model obj
|
|
||||||
Texture2D texture = LoadTexture("resources/models/turret_diffuse.png"); // Load default model texture
|
|
||||||
model.materials[0].maps[MAP_DIFFUSE].texture = texture; // Bind texture to model
|
|
||||||
|
|
||||||
Vector3 position = { 0.0, 0.0, 0.0 }; // Set model position
|
|
||||||
BoundingBox bounds = MeshBoundingBox(model.meshes[0]); // Set model bounds
|
|
||||||
bool selected = false; // Selected object flag
|
|
||||||
|
|
||||||
SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode
|
|
||||||
|
|
||||||
char objFilename[64] = "turret.obj";
|
|
||||||
|
|
||||||
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 (IsFileDropped())
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
char **droppedFiles = GetDroppedFiles(&count);
|
|
||||||
|
|
||||||
if (count == 1)
|
|
||||||
{
|
|
||||||
if (IsFileExtension(droppedFiles[0], ".obj"))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < model.meshCount; i++) UnloadMesh(&model.meshes[i]);
|
|
||||||
model.meshes = LoadMeshes(droppedFiles[0], &model.meshCount);
|
|
||||||
bounds = MeshBoundingBox(model.meshes[0]);
|
|
||||||
}
|
|
||||||
else if (IsFileExtension(droppedFiles[0], ".png"))
|
|
||||||
{
|
|
||||||
UnloadTexture(texture);
|
|
||||||
texture = LoadTexture(droppedFiles[0]);
|
|
||||||
model.materials[0].maps[MAP_DIFFUSE].texture = texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
strcpy(objFilename, GetFileName(droppedFiles[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
ClearDroppedFiles(); // Clear internal buffers
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateCamera(&camera);
|
|
||||||
|
|
||||||
// Select model on mouse click
|
|
||||||
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
|
|
||||||
{
|
|
||||||
// Check collision between ray and box
|
|
||||||
if (CheckCollisionRayBox(GetMouseRay(GetMousePosition(), camera), bounds)) selected = !selected;
|
|
||||||
else selected = false;
|
|
||||||
}
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Draw
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
BeginDrawing();
|
|
||||||
|
|
||||||
ClearBackground(RAYWHITE);
|
|
||||||
|
|
||||||
BeginMode3D(camera);
|
|
||||||
|
|
||||||
DrawModel(model, position, 1.0f, WHITE); // Draw 3d model with texture
|
|
||||||
|
|
||||||
DrawGrid(20.0, 10.0); // Draw a grid
|
|
||||||
|
|
||||||
if (selected) DrawBoundingBox(bounds, GREEN);
|
|
||||||
|
|
||||||
EndMode3D();
|
|
||||||
|
|
||||||
DrawText("Free camera default controls:", 10, 20, 10, DARKGRAY);
|
|
||||||
DrawText("- Mouse Wheel to Zoom in-out", 20, 40, 10, GRAY);
|
|
||||||
DrawText("- Mouse Wheel Pressed to Pan", 20, 60, 10, GRAY);
|
|
||||||
DrawText("- Alt + Mouse Wheel Pressed to Rotate", 20, 80, 10, GRAY);
|
|
||||||
DrawText("- Alt + Ctrl + Mouse Wheel Pressed for Smooth Zoom", 20, 100, 10, GRAY);
|
|
||||||
|
|
||||||
DrawText("Drag & drop .obj/.png to load mesh/texture.", 10, GetScreenHeight() - 20, 10, DARKGRAY);
|
|
||||||
DrawText(FormatText("Current file: %s", objFilename), 250, GetScreenHeight() - 20, 10, GRAY);
|
|
||||||
if (selected) DrawText("MODEL SELECTED", GetScreenWidth() - 110, 10, 10, GREEN);
|
|
||||||
|
|
||||||
DrawText("(c) Turret 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, GRAY);
|
|
||||||
|
|
||||||
EndDrawing();
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
}
|
|
||||||
|
|
||||||
// De-Initialization
|
|
||||||
//--------------------------------------------------------------------------------------
|
|
||||||
UnloadModel(model); // Unload model
|
|
||||||
|
|
||||||
ClearDroppedFiles(); // Clear internal buffers
|
|
||||||
|
|
||||||
CloseWindow(); // Close window and OpenGL context
|
|
||||||
//--------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 95 KiB |
|
|
@ -89,7 +89,10 @@ int main(void)
|
||||||
|
|
||||||
// De-Initialization
|
// De-Initialization
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
UnloadModel(skybox); // Unload skybox model (and textures)
|
UnloadShader(skybox.materials[0].shader);
|
||||||
|
UnloadTexture(skybox.materials[0].maps[MAP_CUBEMAP].texture);
|
||||||
|
|
||||||
|
UnloadModel(skybox); // Unload skybox model
|
||||||
|
|
||||||
CloseWindow(); // Close window and OpenGL context
|
CloseWindow(); // Close window and OpenGL context
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,7 @@ int main(void)
|
||||||
while (pitchOffset < -180) pitchOffset += 360;
|
while (pitchOffset < -180) pitchOffset += 360;
|
||||||
pitchOffset *= 10;
|
pitchOffset *= 10;
|
||||||
|
|
||||||
|
/* matrix transform done with multiplication to combine rotations
|
||||||
Matrix transform = MatrixIdentity();
|
Matrix transform = MatrixIdentity();
|
||||||
|
|
||||||
transform = MatrixMultiply(transform, MatrixRotateZ(DEG2RAD*roll));
|
transform = MatrixMultiply(transform, MatrixRotateZ(DEG2RAD*roll));
|
||||||
|
|
@ -99,8 +100,11 @@ int main(void)
|
||||||
transform = MatrixMultiply(transform, MatrixRotateY(DEG2RAD*yaw));
|
transform = MatrixMultiply(transform, MatrixRotateY(DEG2RAD*yaw));
|
||||||
|
|
||||||
model.transform = transform;
|
model.transform = transform;
|
||||||
//----------------------------------------------------------------------------------
|
*/
|
||||||
|
// matrix created from multiple axes at once
|
||||||
|
model.transform = MatrixRotateXYZ((Vector3){DEG2RAD*pitch,DEG2RAD*yaw,DEG2RAD*roll});
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
// Draw
|
// Draw
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
|
|
@ -165,6 +169,7 @@ int main(void)
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Unload all loaded data
|
// Unload all loaded data
|
||||||
|
UnloadTexture(model.materials[0].maps[MAP_DIFFUSE].texture);
|
||||||
UnloadModel(model);
|
UnloadModel(model);
|
||||||
|
|
||||||
UnloadRenderTexture(framebuffer);
|
UnloadRenderTexture(framebuffer);
|
||||||
|
|
|
||||||
BIN
examples/models/resources/models/Duck/Duck.glb
Normal file
219
examples/models/resources/models/Duck/Duck.gltf
Normal file
|
|
@ -0,0 +1,219 @@
|
||||||
|
{
|
||||||
|
"asset": {
|
||||||
|
"generator": "COLLADA2GLTF",
|
||||||
|
"version": "2.0"
|
||||||
|
},
|
||||||
|
"scene": 0,
|
||||||
|
"scenes": [
|
||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"children": [
|
||||||
|
2,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"matrix": [
|
||||||
|
0.009999999776482582,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.009999999776482582,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.009999999776482582,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matrix": [
|
||||||
|
-0.7289686799049377,
|
||||||
|
0.0,
|
||||||
|
-0.6845470666885376,
|
||||||
|
0.0,
|
||||||
|
-0.4252049028873444,
|
||||||
|
0.7836934328079224,
|
||||||
|
0.4527972936630249,
|
||||||
|
0.0,
|
||||||
|
0.5364750623703003,
|
||||||
|
0.6211478114128113,
|
||||||
|
-0.571287989616394,
|
||||||
|
0.0,
|
||||||
|
400.1130065917969,
|
||||||
|
463.2640075683594,
|
||||||
|
-431.0780334472656,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"camera": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cameras": [
|
||||||
|
{
|
||||||
|
"perspective": {
|
||||||
|
"aspectRatio": 1.5,
|
||||||
|
"yfov": 0.6605925559997559,
|
||||||
|
"zfar": 10000.0,
|
||||||
|
"znear": 1.0
|
||||||
|
},
|
||||||
|
"type": "perspective"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meshes": [
|
||||||
|
{
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"NORMAL": 1,
|
||||||
|
"POSITION": 2,
|
||||||
|
"TEXCOORD_0": 3
|
||||||
|
},
|
||||||
|
"indices": 0,
|
||||||
|
"mode": 4,
|
||||||
|
"material": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "LOD3spShape"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accessors": [
|
||||||
|
{
|
||||||
|
"bufferView": 0,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5123,
|
||||||
|
"count": 12636,
|
||||||
|
"max": [
|
||||||
|
2398
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 2399,
|
||||||
|
"max": [
|
||||||
|
0.9995989799499512,
|
||||||
|
0.999580979347229,
|
||||||
|
0.9984359741210938
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.9990839958190918,
|
||||||
|
-1.0,
|
||||||
|
-0.9998319745063782
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"byteOffset": 28788,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 2399,
|
||||||
|
"max": [
|
||||||
|
96.17990112304688,
|
||||||
|
163.97000122070313,
|
||||||
|
53.92519760131836
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-69.29850006103516,
|
||||||
|
9.929369926452637,
|
||||||
|
-61.32819747924805
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 2399,
|
||||||
|
"max": [
|
||||||
|
0.9833459854125976,
|
||||||
|
0.9800369739532472
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0.026409000158309938,
|
||||||
|
0.01996302604675293
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"materials": [
|
||||||
|
{
|
||||||
|
"pbrMetallicRoughness": {
|
||||||
|
"baseColorTexture": {
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
"metallicFactor": 0.0
|
||||||
|
},
|
||||||
|
"emissiveFactor": [
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"name": "blinn3-fx"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"sampler": 0,
|
||||||
|
"source": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"images": [
|
||||||
|
{
|
||||||
|
"uri": "DuckCM.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"samplers": [
|
||||||
|
{
|
||||||
|
"magFilter": 9729,
|
||||||
|
"minFilter": 9986,
|
||||||
|
"wrapS": 10497,
|
||||||
|
"wrapT": 10497
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bufferViews": [
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 76768,
|
||||||
|
"byteLength": 25272,
|
||||||
|
"target": 34963
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"byteLength": 57576,
|
||||||
|
"byteStride": 12,
|
||||||
|
"target": 34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 57576,
|
||||||
|
"byteLength": 19192,
|
||||||
|
"byteStride": 8,
|
||||||
|
"target": 34962
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buffers": [
|
||||||
|
{
|
||||||
|
"byteLength": 102040,
|
||||||
|
"uri": "Duck0.bin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
examples/models/resources/models/Duck/Duck0.bin
Normal file
BIN
examples/models/resources/models/Duck/DuckCM.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
14
examples/models/resources/models/Duck/Duck_license.txt
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Duck
|
||||||
|
## Screenshot
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## License Information
|
||||||
|
|
||||||
|
Copyright 2006 Sony Computer Entertainment Inc.
|
||||||
|
|
||||||
|
Licensed under the SCEA Shared Source License, Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at:
|
||||||
|
|
||||||
|
http://research.scea.com/scea_shared_source_license.html
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
Before Width: | Height: | Size: 364 KiB After Width: | Height: | Size: 295 KiB |
|
|
@ -73,6 +73,8 @@ vec3 fresnelSchlick(float cosTheta, vec3 F0);
|
||||||
vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness);
|
vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness);
|
||||||
vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir);
|
vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir);
|
||||||
|
|
||||||
|
// WARNING: There is some weird behaviour with this function, always returns black!
|
||||||
|
// Yes, I even tried: return texture(property.sampler, texCoord).rgb;
|
||||||
vec3 ComputeMaterialProperty(MaterialProperty property)
|
vec3 ComputeMaterialProperty(MaterialProperty property)
|
||||||
{
|
{
|
||||||
vec3 result = vec3(0.0, 0.0, 0.0);
|
vec3 result = vec3(0.0, 0.0, 0.0);
|
||||||
|
|
@ -187,17 +189,17 @@ void main()
|
||||||
else texCoord = fragTexCoord; // Use default texture coordinates
|
else texCoord = fragTexCoord; // Use default texture coordinates
|
||||||
|
|
||||||
// Fetch material values from texture sampler or color attributes
|
// Fetch material values from texture sampler or color attributes
|
||||||
vec3 color = ComputeMaterialProperty(albedo);
|
vec3 color = texture(albedo.sampler, texCoord).rgb; //ComputeMaterialProperty(albedo);
|
||||||
vec3 metal = ComputeMaterialProperty(metalness);
|
vec3 metal = texture(metalness.sampler, texCoord).rgb; //ComputeMaterialProperty(metalness);
|
||||||
vec3 rough = ComputeMaterialProperty(roughness);
|
vec3 rough = texture(roughness.sampler, texCoord).rgb; //ComputeMaterialProperty(roughness);
|
||||||
vec3 emiss = ComputeMaterialProperty(emission);
|
vec3 emiss = texture(emission.sampler, texCoord).rgb; //ComputeMaterialProperty(emission);
|
||||||
vec3 ao = ComputeMaterialProperty(occlusion);
|
vec3 ao = texture(occlusion.sampler, texCoord).rgb; //ComputeMaterialProperty(occlusion);
|
||||||
|
|
||||||
// Check if normal mapping is enabled
|
// Check if normal mapping is enabled
|
||||||
if (normals.useSampler == 1)
|
if (normals.useSampler == 1)
|
||||||
{
|
{
|
||||||
// Fetch normal map color and transform lighting values to tangent space
|
// Fetch normal map color and transform lighting values to tangent space
|
||||||
normal = ComputeMaterialProperty(normals);
|
normal = texture(normals.sampler, texCoord).rgb; //ComputeMaterialProperty(normals);
|
||||||
normal = normalize(normal*2.0 - 1.0);
|
normal = normalize(normal*2.0 - 1.0);
|
||||||
normal = normalize(normal*TBN);
|
normal = normalize(normal*TBN);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@
|
||||||
#ifndef RLIGHTS_H
|
#ifndef RLIGHTS_H
|
||||||
#define RLIGHTS_H
|
#define RLIGHTS_H
|
||||||
|
|
||||||
|
#include "raylib.h"
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Defines and Macros
|
// Defines and Macros
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -65,16 +67,11 @@ typedef struct {
|
||||||
extern "C" { // Prevents name mangling of functions
|
extern "C" { // Prevents name mangling of functions
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
// Global Variables Definition
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
int lightsCount = 0; // Current amount of created lights
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module Functions Declaration
|
// Module Functions Declaration
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
Light CreateLight(int type, Vector3 pos, Vector3 targ, Color color, Shader shader); // Defines a light and get locations from PBR shader
|
void CreateLight(int type, Vector3 pos, Vector3 targ, Color color, Shader shader); // Defines a light and get locations from PBR shader
|
||||||
void UpdateLightValues(Shader shader, Light light); // Send to PBR shader light values
|
void UpdateLightValues(Shader shader, Light light); // Send to PBR shader light values
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +103,8 @@ void UpdateLightValues(Shader shader, Light light);
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Global Variables Definition
|
// Global Variables Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// ...
|
static Light lights[MAX_LIGHTS] = { 0 };
|
||||||
|
static int lightsCount = 0; // Current amount of created lights
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module specific Functions Declaration
|
// Module specific Functions Declaration
|
||||||
|
|
@ -118,7 +116,7 @@ void UpdateLightValues(Shader shader, Light light);
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Defines a light and get locations from PBR shader
|
// Defines a light and get locations from PBR shader
|
||||||
Light CreateLight(int type, Vector3 pos, Vector3 targ, Color color, Shader shader)
|
void CreateLight(int type, Vector3 pos, Vector3 targ, Color color, Shader shader)
|
||||||
{
|
{
|
||||||
Light light = { 0 };
|
Light light = { 0 };
|
||||||
|
|
||||||
|
|
@ -148,10 +146,10 @@ Light CreateLight(int type, Vector3 pos, Vector3 targ, Color color, Shader shade
|
||||||
light.colorLoc = GetShaderLocation(shader, colorName);
|
light.colorLoc = GetShaderLocation(shader, colorName);
|
||||||
|
|
||||||
UpdateLightValues(shader, light);
|
UpdateLightValues(shader, light);
|
||||||
|
|
||||||
|
lights[lightsCount] = light;
|
||||||
lightsCount++;
|
lightsCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return light;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send to PBR shader light values
|
// Send to PBR shader light values
|
||||||
|
|
|
||||||
|
|
@ -48,178 +48,178 @@ char recvBuffer[512];
|
||||||
// Attempt to connect to the network (Either TCP, or UDP)
|
// Attempt to connect to the network (Either TCP, or UDP)
|
||||||
void NetworkConnect()
|
void NetworkConnect()
|
||||||
{
|
{
|
||||||
// If the server is configured as UDP, ignore connection requests
|
// If the server is configured as UDP, ignore connection requests
|
||||||
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
|
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
|
||||||
ping = true;
|
ping = true;
|
||||||
connected = true;
|
connected = true;
|
||||||
} else {
|
} else {
|
||||||
// If the client is connected, run the server code to check for a connection
|
// If the client is connected, run the server code to check for a connection
|
||||||
if (client_connected) {
|
if (client_connected) {
|
||||||
int active = CheckSockets(socket_set, 0);
|
int active = CheckSockets(socket_set, 0);
|
||||||
if (active != 0) {
|
if (active != 0) {
|
||||||
TraceLog(LOG_DEBUG,
|
TraceLog(LOG_DEBUG,
|
||||||
"There are currently %d socket(s) with data to be processed.", active);
|
"There are currently %d socket(s) with data to be processed.", active);
|
||||||
}
|
}
|
||||||
if (active > 0) {
|
if (active > 0) {
|
||||||
if ((connection = SocketAccept(server_res->socket, &connection_cfg)) != NULL) {
|
if ((connection = SocketAccept(server_res->socket, &connection_cfg)) != NULL) {
|
||||||
AddSocket(socket_set, connection);
|
AddSocket(socket_set, connection);
|
||||||
ping = true;
|
ping = true;
|
||||||
connected = true;
|
connected = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check if we're connected every _delay_ seconds
|
// Check if we're connected every _delay_ seconds
|
||||||
elapsed += GetFrameTime();
|
elapsed += GetFrameTime();
|
||||||
if (elapsed > delay) {
|
if (elapsed > delay) {
|
||||||
if (IsSocketConnected(client_res->socket)) {
|
if (IsSocketConnected(client_res->socket)) {
|
||||||
client_connected = true;
|
client_connected = true;
|
||||||
}
|
}
|
||||||
elapsed = 0.0f;
|
elapsed = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once connected to the network, check the sockets for pending information
|
// Once connected to the network, check the sockets for pending information
|
||||||
// and when information is ready, send either a Ping or a Pong.
|
// and when information is ready, send either a Ping or a Pong.
|
||||||
void NetworkUpdate()
|
void NetworkUpdate()
|
||||||
{
|
{
|
||||||
// CheckSockets
|
// CheckSockets
|
||||||
//
|
//
|
||||||
// If any of the sockets in the socket_set are pending (received data, or requests)
|
// If any of the sockets in the socket_set are pending (received data, or requests)
|
||||||
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
|
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
|
||||||
int active = CheckSockets(socket_set, 0);
|
int active = CheckSockets(socket_set, 0);
|
||||||
if (active != 0) {
|
if (active != 0) {
|
||||||
TraceLog(LOG_DEBUG,
|
TraceLog(LOG_DEBUG,
|
||||||
"There are currently %d socket(s) with data to be processed.", active);
|
"There are currently %d socket(s) with data to be processed.", active);
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSocketReady
|
// IsSocketReady
|
||||||
//
|
//
|
||||||
// If the socket is ready, attempt to receive data from the socket
|
// If the socket is ready, attempt to receive data from the socket
|
||||||
int bytesRecv = 0;
|
int bytesRecv = 0;
|
||||||
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
|
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
|
||||||
if (IsSocketReady(client_res->socket)) {
|
if (IsSocketReady(client_res->socket)) {
|
||||||
bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen);
|
bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen);
|
||||||
}
|
}
|
||||||
if (IsSocketReady(server_res->socket)) {
|
if (IsSocketReady(server_res->socket)) {
|
||||||
bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen);
|
bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (IsSocketReady(connection)) {
|
if (IsSocketReady(connection)) {
|
||||||
bytesRecv = SocketReceive(connection, recvBuffer, msglen);
|
bytesRecv = SocketReceive(connection, recvBuffer, msglen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we received data, was that data a "Ping!" or a "Pong!"
|
// If we received data, was that data a "Ping!" or a "Pong!"
|
||||||
if (bytesRecv > 0) {
|
if (bytesRecv > 0) {
|
||||||
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
|
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
|
||||||
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
|
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
|
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
|
||||||
elapsed += GetFrameTime();
|
elapsed += GetFrameTime();
|
||||||
if (elapsed > delay) {
|
if (elapsed > delay) {
|
||||||
if (ping) {
|
if (ping) {
|
||||||
ping = false;
|
ping = false;
|
||||||
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
|
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
|
||||||
SocketSend(client_res->socket, pingmsg, msglen);
|
SocketSend(client_res->socket, pingmsg, msglen);
|
||||||
} else {
|
} else {
|
||||||
SocketSend(client_res->socket, pingmsg, msglen);
|
SocketSend(client_res->socket, pingmsg, msglen);
|
||||||
}
|
}
|
||||||
} else if (pong) {
|
} else if (pong) {
|
||||||
pong = false;
|
pong = false;
|
||||||
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
|
if (server_cfg.type == SOCKET_UDP && client_cfg.type == SOCKET_UDP) {
|
||||||
SocketSend(client_res->socket, pongmsg, msglen);
|
SocketSend(client_res->socket, pongmsg, msglen);
|
||||||
} else {
|
} else {
|
||||||
SocketSend(client_res->socket, pongmsg, msglen);
|
SocketSend(client_res->socket, pongmsg, msglen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elapsed = 0.0f;
|
elapsed = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
InitWindow(
|
InitWindow(
|
||||||
screenWidth, screenHeight, "raylib [network] example - ping pong");
|
screenWidth, screenHeight, "raylib [network] example - ping pong");
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
SetTraceLogLevel(LOG_DEBUG);
|
SetTraceLogLevel(LOG_DEBUG);
|
||||||
|
|
||||||
// Networking
|
// Networking
|
||||||
InitNetwork();
|
InitNetwork();
|
||||||
|
|
||||||
// Create the server
|
// Create the server
|
||||||
//
|
//
|
||||||
// Performs
|
// Performs
|
||||||
// getaddrinfo
|
// getaddrinfo
|
||||||
// socket
|
// socket
|
||||||
// setsockopt
|
// setsockopt
|
||||||
// bind
|
// bind
|
||||||
// listen
|
// listen
|
||||||
server_res = AllocSocketResult();
|
server_res = AllocSocketResult();
|
||||||
if (!SocketCreate(&server_cfg, server_res)) {
|
if (!SocketCreate(&server_cfg, server_res)) {
|
||||||
TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d",
|
TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d",
|
||||||
server_res->status, server_res->socket->status);
|
server_res->status, server_res->socket->status);
|
||||||
} else {
|
} else {
|
||||||
if (!SocketBind(&server_cfg, server_res)) {
|
if (!SocketBind(&server_cfg, server_res)) {
|
||||||
TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d",
|
TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d",
|
||||||
server_res->status, server_res->socket->status);
|
server_res->status, server_res->socket->status);
|
||||||
} else {
|
} else {
|
||||||
if (!(server_cfg.type == SOCKET_UDP)) {
|
if (!(server_cfg.type == SOCKET_UDP)) {
|
||||||
if (!SocketListen(&server_cfg, server_res)) {
|
if (!SocketListen(&server_cfg, server_res)) {
|
||||||
TraceLog(LOG_WARNING,
|
TraceLog(LOG_WARNING,
|
||||||
"Failed to start listen server: status %d, errno %d",
|
"Failed to start listen server: status %d, errno %d",
|
||||||
server_res->status, server_res->socket->status);
|
server_res->status, server_res->socket->status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the client
|
// Create the client
|
||||||
//
|
//
|
||||||
// Performs
|
// Performs
|
||||||
// getaddrinfo
|
// getaddrinfo
|
||||||
// socket
|
// socket
|
||||||
// setsockopt
|
// setsockopt
|
||||||
// connect (TCP only)
|
// connect (TCP only)
|
||||||
client_res = AllocSocketResult();
|
client_res = AllocSocketResult();
|
||||||
if (!SocketCreate(&client_cfg, client_res)) {
|
if (!SocketCreate(&client_cfg, client_res)) {
|
||||||
TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
|
TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
|
||||||
client_res->status, client_res->socket->status);
|
client_res->status, client_res->socket->status);
|
||||||
} else {
|
} else {
|
||||||
if (!(client_cfg.type == SOCKET_UDP)) {
|
if (!(client_cfg.type == SOCKET_UDP)) {
|
||||||
if (!SocketConnect(&client_cfg, client_res)) {
|
if (!SocketConnect(&client_cfg, client_res)) {
|
||||||
TraceLog(LOG_WARNING,
|
TraceLog(LOG_WARNING,
|
||||||
"Failed to connect to server: status %d, errno %d",
|
"Failed to connect to server: status %d, errno %d",
|
||||||
client_res->status, client_res->socket->status);
|
client_res->status, client_res->socket->status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create & Add sockets to the socket set
|
// Create & Add sockets to the socket set
|
||||||
socket_set = AllocSocketSet(3);
|
socket_set = AllocSocketSet(3);
|
||||||
msglen = strlen(pingmsg) + 1;
|
msglen = strlen(pingmsg) + 1;
|
||||||
memset(recvBuffer, '\0', sizeof(recvBuffer));
|
memset(recvBuffer, '\0', sizeof(recvBuffer));
|
||||||
AddSocket(socket_set, server_res->socket);
|
AddSocket(socket_set, server_res->socket);
|
||||||
AddSocket(socket_set, client_res->socket);
|
AddSocket(socket_set, client_res->socket);
|
||||||
|
|
||||||
// Main game loop
|
// Main game loop
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
if (connected) {
|
if (connected) {
|
||||||
NetworkUpdate();
|
NetworkUpdate();
|
||||||
} else {
|
} else {
|
||||||
NetworkConnect();
|
NetworkConnect();
|
||||||
}
|
}
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -28,30 +28,30 @@ uint16_t port = 0;
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
InitWindow(
|
InitWindow(
|
||||||
screenWidth, screenHeight, "raylib [network] example - ping pong");
|
screenWidth, screenHeight, "raylib [network] example - ping pong");
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
|
|
||||||
SetTraceLogLevel(LOG_DEBUG);
|
SetTraceLogLevel(LOG_DEBUG);
|
||||||
|
|
||||||
// Networking
|
// Networking
|
||||||
InitNetwork();
|
InitNetwork();
|
||||||
|
|
||||||
AddressInformation* addr = AllocAddressList(1);
|
AddressInformation* addr = AllocAddressList(1);
|
||||||
int count = ResolveHost(
|
int count = ResolveHost(
|
||||||
NULL,
|
NULL,
|
||||||
"5210",
|
"5210",
|
||||||
ADDRESS_TYPE_IPV4,
|
ADDRESS_TYPE_IPV4,
|
||||||
0 // Uncomment any of these flags
|
0 // Uncomment any of these flags
|
||||||
// ADDRESS_INFO_NUMERICHOST // or try them in conjunction to
|
// ADDRESS_INFO_NUMERICHOST // or try them in conjunction to
|
||||||
// ADDRESS_INFO_NUMERICSERV // specify custom behaviour from
|
// ADDRESS_INFO_NUMERICSERV // specify custom behaviour from
|
||||||
// ADDRESS_INFO_DNS_ONLY // the function getaddrinfo()
|
// ADDRESS_INFO_DNS_ONLY // the function getaddrinfo()
|
||||||
// ADDRESS_INFO_ALL //
|
// ADDRESS_INFO_ALL //
|
||||||
// ADDRESS_INFO_FQDN // e.g. ADDRESS_INFO_CANONNAME | ADDRESS_INFO_NUMERICSERV
|
// ADDRESS_INFO_FQDN // e.g. ADDRESS_INFO_CANONNAME | ADDRESS_INFO_NUMERICSERV
|
||||||
,
|
,
|
||||||
addr
|
addr
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -61,20 +61,20 @@ int main()
|
||||||
TraceLog(LOG_INFO, "Resolved to ip %s::%d\n", buffer, port);
|
TraceLog(LOG_INFO, "Resolved to ip %s::%d\n", buffer, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main game loop
|
// Main game loop
|
||||||
while (!WindowShouldClose())
|
while (!WindowShouldClose())
|
||||||
{
|
{
|
||||||
// Draw
|
// Draw
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
|
|
||||||
// Clear
|
// Clear
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
|
|
||||||
// End draw
|
// End draw
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -43,109 +43,109 @@ char recvBuffer[512];
|
||||||
// Attempt to connect to the network (Either TCP, or UDP)
|
// Attempt to connect to the network (Either TCP, or UDP)
|
||||||
void NetworkConnect()
|
void NetworkConnect()
|
||||||
{
|
{
|
||||||
// Check if we're connected every _delay_ seconds
|
// Check if we're connected every _delay_ seconds
|
||||||
elapsed += GetFrameTime();
|
elapsed += GetFrameTime();
|
||||||
if (elapsed > delay) {
|
if (elapsed > delay) {
|
||||||
if (IsSocketConnected(client_res->socket)) { connected = true; }
|
if (IsSocketConnected(client_res->socket)) { connected = true; }
|
||||||
elapsed = 0.0f;
|
elapsed = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once connected to the network, check the sockets for pending information
|
// Once connected to the network, check the sockets for pending information
|
||||||
// and when information is ready, send either a Ping or a Pong.
|
// and when information is ready, send either a Ping or a Pong.
|
||||||
void NetworkUpdate()
|
void NetworkUpdate()
|
||||||
{
|
{
|
||||||
// CheckSockets
|
// CheckSockets
|
||||||
//
|
//
|
||||||
// If any of the sockets in the socket_set are pending (received data, or requests)
|
// If any of the sockets in the socket_set are pending (received data, or requests)
|
||||||
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
|
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
|
||||||
int active = CheckSockets(socket_set, 0);
|
int active = CheckSockets(socket_set, 0);
|
||||||
if (active != 0) {
|
if (active != 0) {
|
||||||
TraceLog(LOG_DEBUG,
|
TraceLog(LOG_DEBUG,
|
||||||
"There are currently %d socket(s) with data to be processed.", active);
|
"There are currently %d socket(s) with data to be processed.", active);
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSocketReady
|
// IsSocketReady
|
||||||
//
|
//
|
||||||
// If the socket is ready, attempt to receive data from the socket
|
// If the socket is ready, attempt to receive data from the socket
|
||||||
int bytesRecv = 0;
|
int bytesRecv = 0;
|
||||||
if (IsSocketReady(client_res->socket)) {
|
if (IsSocketReady(client_res->socket)) {
|
||||||
bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen);
|
bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we received data, was that data a "Ping!" or a "Pong!"
|
// If we received data, was that data a "Ping!" or a "Pong!"
|
||||||
if (bytesRecv > 0) {
|
if (bytesRecv > 0) {
|
||||||
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
|
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
|
||||||
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
|
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
|
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
|
||||||
elapsed += GetFrameTime();
|
elapsed += GetFrameTime();
|
||||||
if (elapsed > delay) {
|
if (elapsed > delay) {
|
||||||
if (ping) {
|
if (ping) {
|
||||||
ping = false;
|
ping = false;
|
||||||
SocketSend(client_res->socket, pingmsg, msglen);
|
SocketSend(client_res->socket, pingmsg, msglen);
|
||||||
} else if (pong) {
|
} else if (pong) {
|
||||||
pong = false;
|
pong = false;
|
||||||
SocketSend(client_res->socket, pongmsg, msglen);
|
SocketSend(client_res->socket, pongmsg, msglen);
|
||||||
}
|
}
|
||||||
elapsed = 0.0f;
|
elapsed = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
InitWindow(
|
InitWindow(
|
||||||
screenWidth, screenHeight, "raylib [network] example - tcp client");
|
screenWidth, screenHeight, "raylib [network] example - tcp client");
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
SetTraceLogLevel(LOG_DEBUG);
|
SetTraceLogLevel(LOG_DEBUG);
|
||||||
|
|
||||||
// Networking
|
// Networking
|
||||||
InitNetwork();
|
InitNetwork();
|
||||||
|
|
||||||
// Create the client
|
// Create the client
|
||||||
//
|
//
|
||||||
// Performs
|
// Performs
|
||||||
// getaddrinfo
|
// getaddrinfo
|
||||||
// socket
|
// socket
|
||||||
// setsockopt
|
// setsockopt
|
||||||
// connect (TCP only)
|
// connect (TCP only)
|
||||||
client_res = AllocSocketResult();
|
client_res = AllocSocketResult();
|
||||||
if (!SocketCreate(&client_cfg, client_res)) {
|
if (!SocketCreate(&client_cfg, client_res)) {
|
||||||
TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
|
TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
|
||||||
client_res->status, client_res->socket->status);
|
client_res->status, client_res->socket->status);
|
||||||
} else {
|
} else {
|
||||||
if (!(client_cfg.type == SOCKET_UDP)) {
|
if (!(client_cfg.type == SOCKET_UDP)) {
|
||||||
if (!SocketConnect(&client_cfg, client_res)) {
|
if (!SocketConnect(&client_cfg, client_res)) {
|
||||||
TraceLog(LOG_WARNING,
|
TraceLog(LOG_WARNING,
|
||||||
"Failed to connect to server: status %d, errno %d",
|
"Failed to connect to server: status %d, errno %d",
|
||||||
client_res->status, client_res->socket->status);
|
client_res->status, client_res->socket->status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create & Add sockets to the socket set
|
// Create & Add sockets to the socket set
|
||||||
socket_set = AllocSocketSet(1);
|
socket_set = AllocSocketSet(1);
|
||||||
msglen = strlen(pingmsg) + 1;
|
msglen = strlen(pingmsg) + 1;
|
||||||
memset(recvBuffer, '\0', sizeof(recvBuffer));
|
memset(recvBuffer, '\0', sizeof(recvBuffer));
|
||||||
AddSocket(socket_set, client_res->socket);
|
AddSocket(socket_set, client_res->socket);
|
||||||
|
|
||||||
// Main game loop
|
// Main game loop
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
if (connected) {
|
if (connected) {
|
||||||
NetworkUpdate();
|
NetworkUpdate();
|
||||||
} else {
|
} else {
|
||||||
NetworkConnect();
|
NetworkConnect();
|
||||||
}
|
}
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -45,121 +45,121 @@ char recvBuffer[512];
|
||||||
// Attempt to connect to the network (Either TCP, or UDP)
|
// Attempt to connect to the network (Either TCP, or UDP)
|
||||||
void NetworkConnect()
|
void NetworkConnect()
|
||||||
{
|
{
|
||||||
int active = CheckSockets(socket_set, 0);
|
int active = CheckSockets(socket_set, 0);
|
||||||
if (active != 0) {
|
if (active != 0) {
|
||||||
TraceLog(LOG_DEBUG,
|
TraceLog(LOG_DEBUG,
|
||||||
"There are currently %d socket(s) with data to be processed.", active);
|
"There are currently %d socket(s) with data to be processed.", active);
|
||||||
}
|
}
|
||||||
if (active > 0) {
|
if (active > 0) {
|
||||||
if ((connection = SocketAccept(server_res->socket, &connection_cfg)) != NULL) {
|
if ((connection = SocketAccept(server_res->socket, &connection_cfg)) != NULL) {
|
||||||
AddSocket(socket_set, connection);
|
AddSocket(socket_set, connection);
|
||||||
ping = true;
|
ping = true;
|
||||||
connected = true;
|
connected = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once connected to the network, check the sockets for pending information
|
// Once connected to the network, check the sockets for pending information
|
||||||
// and when information is ready, send either a Ping or a Pong.
|
// and when information is ready, send either a Ping or a Pong.
|
||||||
void NetworkUpdate()
|
void NetworkUpdate()
|
||||||
{
|
{
|
||||||
// CheckSockets
|
// CheckSockets
|
||||||
//
|
//
|
||||||
// If any of the sockets in the socket_set are pending (received data, or requests)
|
// If any of the sockets in the socket_set are pending (received data, or requests)
|
||||||
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
|
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
|
||||||
int active = CheckSockets(socket_set, 0);
|
int active = CheckSockets(socket_set, 0);
|
||||||
if (active != 0) {
|
if (active != 0) {
|
||||||
TraceLog(LOG_DEBUG,
|
TraceLog(LOG_DEBUG,
|
||||||
"There are currently %d socket(s) with data to be processed.", active);
|
"There are currently %d socket(s) with data to be processed.", active);
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSocketReady
|
// IsSocketReady
|
||||||
//
|
//
|
||||||
// If the socket is ready, attempt to receive data from the socket
|
// If the socket is ready, attempt to receive data from the socket
|
||||||
int bytesRecv = 0;
|
int bytesRecv = 0;
|
||||||
if (IsSocketReady(connection)) {
|
if (IsSocketReady(connection)) {
|
||||||
bytesRecv = SocketReceive(connection, recvBuffer, msglen);
|
bytesRecv = SocketReceive(connection, recvBuffer, msglen);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we received data, was that data a "Ping!" or a "Pong!"
|
// If we received data, was that data a "Ping!" or a "Pong!"
|
||||||
if (bytesRecv > 0) {
|
if (bytesRecv > 0) {
|
||||||
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
|
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
|
||||||
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
|
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
|
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
|
||||||
elapsed += GetFrameTime();
|
elapsed += GetFrameTime();
|
||||||
if (elapsed > delay) {
|
if (elapsed > delay) {
|
||||||
if (ping) {
|
if (ping) {
|
||||||
ping = false;
|
ping = false;
|
||||||
SocketSend(connection, pingmsg, msglen);
|
SocketSend(connection, pingmsg, msglen);
|
||||||
} else if (pong) {
|
} else if (pong) {
|
||||||
pong = false;
|
pong = false;
|
||||||
SocketSend(connection, pongmsg, msglen);
|
SocketSend(connection, pongmsg, msglen);
|
||||||
}
|
}
|
||||||
elapsed = 0.0f;
|
elapsed = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
InitWindow(
|
InitWindow(
|
||||||
screenWidth, screenHeight, "raylib [network] example - tcp server");
|
screenWidth, screenHeight, "raylib [network] example - tcp server");
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
SetTraceLogLevel(LOG_DEBUG);
|
SetTraceLogLevel(LOG_DEBUG);
|
||||||
|
|
||||||
// Networking
|
// Networking
|
||||||
InitNetwork();
|
InitNetwork();
|
||||||
|
|
||||||
// Create the server
|
// Create the server
|
||||||
//
|
//
|
||||||
// Performs
|
// Performs
|
||||||
// getaddrinfo
|
// getaddrinfo
|
||||||
// socket
|
// socket
|
||||||
// setsockopt
|
// setsockopt
|
||||||
// bind
|
// bind
|
||||||
// listen
|
// listen
|
||||||
server_res = AllocSocketResult();
|
server_res = AllocSocketResult();
|
||||||
if (!SocketCreate(&server_cfg, server_res)) {
|
if (!SocketCreate(&server_cfg, server_res)) {
|
||||||
TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d",
|
TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d",
|
||||||
server_res->status, server_res->socket->status);
|
server_res->status, server_res->socket->status);
|
||||||
} else {
|
} else {
|
||||||
if (!SocketBind(&server_cfg, server_res)) {
|
if (!SocketBind(&server_cfg, server_res)) {
|
||||||
TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d",
|
TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d",
|
||||||
server_res->status, server_res->socket->status);
|
server_res->status, server_res->socket->status);
|
||||||
} else {
|
} else {
|
||||||
if (!(server_cfg.type == SOCKET_UDP)) {
|
if (!(server_cfg.type == SOCKET_UDP)) {
|
||||||
if (!SocketListen(&server_cfg, server_res)) {
|
if (!SocketListen(&server_cfg, server_res)) {
|
||||||
TraceLog(LOG_WARNING,
|
TraceLog(LOG_WARNING,
|
||||||
"Failed to start listen server: status %d, errno %d",
|
"Failed to start listen server: status %d, errno %d",
|
||||||
server_res->status, server_res->socket->status);
|
server_res->status, server_res->socket->status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create & Add sockets to the socket set
|
// Create & Add sockets to the socket set
|
||||||
socket_set = AllocSocketSet(2);
|
socket_set = AllocSocketSet(2);
|
||||||
msglen = strlen(pingmsg) + 1;
|
msglen = strlen(pingmsg) + 1;
|
||||||
memset(recvBuffer, '\0', sizeof(recvBuffer));
|
memset(recvBuffer, '\0', sizeof(recvBuffer));
|
||||||
AddSocket(socket_set, server_res->socket);
|
AddSocket(socket_set, server_res->socket);
|
||||||
|
|
||||||
// Main game loop
|
// Main game loop
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
if (connected) {
|
if (connected) {
|
||||||
NetworkUpdate();
|
NetworkUpdate();
|
||||||
} else {
|
} else {
|
||||||
NetworkConnect();
|
NetworkConnect();
|
||||||
}
|
}
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -27,80 +27,80 @@
|
||||||
|
|
||||||
void test_network_initialise()
|
void test_network_initialise()
|
||||||
{
|
{
|
||||||
assert(InitNetwork() == true);
|
assert(InitNetwork() == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_socket_result()
|
void test_socket_result()
|
||||||
{
|
{
|
||||||
SocketResult *result = AllocSocketResult();
|
SocketResult *result = AllocSocketResult();
|
||||||
assert(result != NULL);
|
assert(result != NULL);
|
||||||
FreeSocketResult(&result);
|
FreeSocketResult(&result);
|
||||||
assert(result == NULL);
|
assert(result == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_socket()
|
void test_socket()
|
||||||
{
|
{
|
||||||
Socket *socket = AllocSocket();
|
Socket *socket = AllocSocket();
|
||||||
assert(socket != NULL);
|
assert(socket != NULL);
|
||||||
FreeSocket(&socket);
|
FreeSocket(&socket);
|
||||||
assert(socket == NULL);
|
assert(socket == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_resolve_ip()
|
void test_resolve_ip()
|
||||||
{
|
{
|
||||||
const char *host = "8.8.8.8";
|
const char *host = "8.8.8.8";
|
||||||
const char *port = "8080";
|
const char *port = "8080";
|
||||||
char ip[ADDRESS_IPV6_ADDRSTRLEN];
|
char ip[ADDRESS_IPV6_ADDRSTRLEN];
|
||||||
char service[ADDRESS_MAXSERV];
|
char service[ADDRESS_MAXSERV];
|
||||||
|
|
||||||
memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
|
memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
|
||||||
ResolveIP(host, port, NAME_INFO_NUMERICHOST, ip, service);
|
ResolveIP(host, port, NAME_INFO_NUMERICHOST, ip, service);
|
||||||
TraceLog(LOG_INFO, "Resolved %s to %s", host, ip);
|
TraceLog(LOG_INFO, "Resolved %s to %s", host, ip);
|
||||||
assert(strcmp(ip, "8.8.8.8") == 0);
|
assert(strcmp(ip, "8.8.8.8") == 0);
|
||||||
|
|
||||||
memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
|
memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
|
||||||
ResolveIP(host, port, NAME_INFO_DEFAULT, ip, service);
|
ResolveIP(host, port, NAME_INFO_DEFAULT, ip, service);
|
||||||
TraceLog(LOG_INFO, "Resolved %s to %s", host, ip);
|
TraceLog(LOG_INFO, "Resolved %s to %s", host, ip);
|
||||||
assert(strcmp(ip, "google-public-dns-a.google.com") == 0);
|
assert(strcmp(ip, "google-public-dns-a.google.com") == 0);
|
||||||
|
|
||||||
memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
|
memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
|
||||||
ResolveIP(host, port, NAME_INFO_NOFQDN, ip, service);
|
ResolveIP(host, port, NAME_INFO_NOFQDN, ip, service);
|
||||||
TraceLog(LOG_INFO, "Resolved %s to %s", host, ip);
|
TraceLog(LOG_INFO, "Resolved %s to %s", host, ip);
|
||||||
assert(strcmp(ip, "google-public-dns-a") == 0);
|
assert(strcmp(ip, "google-public-dns-a") == 0);
|
||||||
|
|
||||||
memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
|
memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
|
||||||
ResolveIP(host, port, NAME_INFO_NUMERICHOST, ip, service);
|
ResolveIP(host, port, NAME_INFO_NUMERICHOST, ip, service);
|
||||||
TraceLog(LOG_INFO, "Resolved %s to %s", host, ip);
|
TraceLog(LOG_INFO, "Resolved %s to %s", host, ip);
|
||||||
assert(strcmp(ip, "8.8.8.8") == 0);
|
assert(strcmp(ip, "8.8.8.8") == 0);
|
||||||
|
|
||||||
memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
|
memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
|
||||||
ResolveIP(host, port, NAME_INFO_NAMEREQD, ip, service);
|
ResolveIP(host, port, NAME_INFO_NAMEREQD, ip, service);
|
||||||
TraceLog(LOG_INFO, "Resolved %s to %s", host, ip);
|
TraceLog(LOG_INFO, "Resolved %s to %s", host, ip);
|
||||||
assert(strcmp(ip, "google-public-dns-a.google.com") == 0);
|
assert(strcmp(ip, "google-public-dns-a.google.com") == 0);
|
||||||
|
|
||||||
memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
|
memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
|
||||||
ResolveIP(host, port, NAME_INFO_NUMERICSERV, ip, service);
|
ResolveIP(host, port, NAME_INFO_NUMERICSERV, ip, service);
|
||||||
TraceLog(LOG_INFO, "Resolved %s to %s", host, ip);
|
TraceLog(LOG_INFO, "Resolved %s to %s", host, ip);
|
||||||
assert(strcmp(ip, "google-public-dns-a.google.com") == 0);
|
assert(strcmp(ip, "google-public-dns-a.google.com") == 0);
|
||||||
|
|
||||||
memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
|
memset(ip, '\0', ADDRESS_IPV6_ADDRSTRLEN);
|
||||||
ResolveIP(host, port, NAME_INFO_DGRAM, ip, service);
|
ResolveIP(host, port, NAME_INFO_DGRAM, ip, service);
|
||||||
TraceLog(LOG_INFO, "Resolved %s to %s", host, ip);
|
TraceLog(LOG_INFO, "Resolved %s to %s", host, ip);
|
||||||
assert(strcmp(ip, "google-public-dns-a.google.com") == 0);
|
assert(strcmp(ip, "google-public-dns-a.google.com") == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_resolve_host()
|
void test_resolve_host()
|
||||||
{
|
{
|
||||||
const char * address = "localhost";
|
const char * address = "localhost";
|
||||||
const char * port = "80";
|
const char * port = "80";
|
||||||
AddressInformation *addr = AllocAddressList(3);
|
AddressInformation *addr = AllocAddressList(3);
|
||||||
int count = ResolveHost(address, port, ADDRESS_TYPE_ANY, 0, addr);
|
int count = ResolveHost(address, port, ADDRESS_TYPE_ANY, 0, addr);
|
||||||
|
|
||||||
assert(GetAddressFamily(addr[0]) == ADDRESS_TYPE_IPV6);
|
assert(GetAddressFamily(addr[0]) == ADDRESS_TYPE_IPV6);
|
||||||
assert(GetAddressFamily(addr[1]) == ADDRESS_TYPE_IPV4);
|
assert(GetAddressFamily(addr[1]) == ADDRESS_TYPE_IPV4);
|
||||||
assert(GetAddressSocketType(addr[0]) == 0);
|
assert(GetAddressSocketType(addr[0]) == 0);
|
||||||
assert(GetAddressProtocol(addr[0]) == 0);
|
assert(GetAddressProtocol(addr[0]) == 0);
|
||||||
// for (size_t i = 0; i < count; i++) { PrintAddressInfo(addr[i]); }
|
// for (size_t i = 0; i < count; i++) { PrintAddressInfo(addr[i]); }
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_address()
|
void test_address()
|
||||||
|
|
@ -113,36 +113,36 @@ void test_address_list()
|
||||||
|
|
||||||
void test_socket_create()
|
void test_socket_create()
|
||||||
{
|
{
|
||||||
SocketConfig server_cfg = {.host = "127.0.0.1", .port = "8080", .server = true, .nonblocking = true};
|
SocketConfig server_cfg = {.host = "127.0.0.1", .port = "8080", .server = true, .nonblocking = true};
|
||||||
Socket * socket = AllocSocket();
|
Socket * socket = AllocSocket();
|
||||||
SocketResult *server_res = AllocSocketResult();
|
SocketResult *server_res = AllocSocketResult();
|
||||||
SocketSet * socket_set = AllocSocketSet(1);
|
SocketSet * socket_set = AllocSocketSet(1);
|
||||||
assert(SocketCreate(&server_cfg, server_res));
|
assert(SocketCreate(&server_cfg, server_res));
|
||||||
assert(AddSocket(socket_set, server_res->socket));
|
assert(AddSocket(socket_set, server_res->socket));
|
||||||
assert(SocketListen(&server_cfg, server_res));
|
assert(SocketListen(&server_cfg, server_res));
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
InitWindow(
|
InitWindow(
|
||||||
screenWidth, screenHeight, "raylib [network] example - network test");
|
screenWidth, screenHeight, "raylib [network] example - network test");
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
|
|
||||||
// Run the tests
|
// Run the tests
|
||||||
test_network_initialise();
|
test_network_initialise();
|
||||||
test_resolve_host();
|
test_resolve_host();
|
||||||
// test_socket_create();
|
// test_socket_create();
|
||||||
|
|
||||||
// Main game loop
|
// Main game loop
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
|
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -43,86 +43,86 @@ char recvBuffer[512];
|
||||||
// and when information is ready, send either a Ping or a Pong.
|
// and when information is ready, send either a Ping or a Pong.
|
||||||
void NetworkUpdate()
|
void NetworkUpdate()
|
||||||
{
|
{
|
||||||
// CheckSockets
|
// CheckSockets
|
||||||
//
|
//
|
||||||
// If any of the sockets in the socket_set are pending (received data, or requests)
|
// If any of the sockets in the socket_set are pending (received data, or requests)
|
||||||
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
|
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
|
||||||
int active = CheckSockets(socket_set, 0);
|
int active = CheckSockets(socket_set, 0);
|
||||||
if (active != 0) {
|
if (active != 0) {
|
||||||
TraceLog(LOG_DEBUG,
|
TraceLog(LOG_DEBUG,
|
||||||
"There are currently %d socket(s) with data to be processed.", active);
|
"There are currently %d socket(s) with data to be processed.", active);
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSocketReady
|
// IsSocketReady
|
||||||
//
|
//
|
||||||
// If the socket is ready, attempt to receive data from the socket
|
// If the socket is ready, attempt to receive data from the socket
|
||||||
int bytesRecv = 0;
|
int bytesRecv = 0;
|
||||||
if (IsSocketReady(client_res->socket)) {
|
if (IsSocketReady(client_res->socket)) {
|
||||||
bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen);
|
bytesRecv = SocketReceive(client_res->socket, recvBuffer, msglen);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we received data, was that data a "Ping!" or a "Pong!"
|
// If we received data, was that data a "Ping!" or a "Pong!"
|
||||||
if (bytesRecv > 0) {
|
if (bytesRecv > 0) {
|
||||||
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
|
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
|
||||||
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
|
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
|
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
|
||||||
elapsed += GetFrameTime();
|
elapsed += GetFrameTime();
|
||||||
if (elapsed > delay) {
|
if (elapsed > delay) {
|
||||||
if (ping) {
|
if (ping) {
|
||||||
ping = false;
|
ping = false;
|
||||||
SocketSend(client_res->socket, pingmsg, msglen);
|
SocketSend(client_res->socket, pingmsg, msglen);
|
||||||
} else if (pong) {
|
} else if (pong) {
|
||||||
pong = false;
|
pong = false;
|
||||||
SocketSend(client_res->socket, pongmsg, msglen);
|
SocketSend(client_res->socket, pongmsg, msglen);
|
||||||
}
|
}
|
||||||
elapsed = 0.0f;
|
elapsed = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
InitWindow(
|
InitWindow(
|
||||||
screenWidth, screenHeight, "raylib [network] example - udp client");
|
screenWidth, screenHeight, "raylib [network] example - udp client");
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
SetTraceLogLevel(LOG_DEBUG);
|
SetTraceLogLevel(LOG_DEBUG);
|
||||||
|
|
||||||
// Networking
|
// Networking
|
||||||
InitNetwork();
|
InitNetwork();
|
||||||
|
|
||||||
// Create the client
|
// Create the client
|
||||||
//
|
//
|
||||||
// Performs
|
// Performs
|
||||||
// getaddrinfo
|
// getaddrinfo
|
||||||
// socket
|
// socket
|
||||||
// setsockopt
|
// setsockopt
|
||||||
// connect (TCP only)
|
// connect (TCP only)
|
||||||
client_res = AllocSocketResult();
|
client_res = AllocSocketResult();
|
||||||
if (!SocketCreate(&client_cfg, client_res)) {
|
if (!SocketCreate(&client_cfg, client_res)) {
|
||||||
TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
|
TraceLog(LOG_WARNING, "Failed to open client: status %d, errno %d",
|
||||||
client_res->status, client_res->socket->status);
|
client_res->status, client_res->socket->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create & Add sockets to the socket set
|
// Create & Add sockets to the socket set
|
||||||
socket_set = AllocSocketSet(1);
|
socket_set = AllocSocketSet(1);
|
||||||
msglen = strlen(pingmsg) + 1;
|
msglen = strlen(pingmsg) + 1;
|
||||||
ping = true;
|
ping = true;
|
||||||
memset(recvBuffer, '\0', sizeof(recvBuffer));
|
memset(recvBuffer, '\0', sizeof(recvBuffer));
|
||||||
AddSocket(socket_set, client_res->socket);
|
AddSocket(socket_set, client_res->socket);
|
||||||
|
|
||||||
// Main game loop
|
// Main game loop
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
NetworkUpdate();
|
NetworkUpdate();
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -43,92 +43,92 @@ char recvBuffer[512];
|
||||||
// and when information is ready, send either a Ping or a Pong.
|
// and when information is ready, send either a Ping or a Pong.
|
||||||
void NetworkUpdate()
|
void NetworkUpdate()
|
||||||
{
|
{
|
||||||
// CheckSockets
|
// CheckSockets
|
||||||
//
|
//
|
||||||
// If any of the sockets in the socket_set are pending (received data, or requests)
|
// If any of the sockets in the socket_set are pending (received data, or requests)
|
||||||
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
|
// then mark the socket as being ready. You can check this with IsSocketReady(client_res->socket)
|
||||||
int active = CheckSockets(socket_set, 0);
|
int active = CheckSockets(socket_set, 0);
|
||||||
if (active != 0) {
|
if (active != 0) {
|
||||||
TraceLog(LOG_DEBUG,
|
TraceLog(LOG_DEBUG,
|
||||||
"There are currently %d socket(s) with data to be processed.", active);
|
"There are currently %d socket(s) with data to be processed.", active);
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSocketReady
|
// IsSocketReady
|
||||||
//
|
//
|
||||||
// If the socket is ready, attempt to receive data from the socket
|
// If the socket is ready, attempt to receive data from the socket
|
||||||
// int bytesRecv = 0;
|
// int bytesRecv = 0;
|
||||||
// if (IsSocketReady(server_res->socket)) {
|
// if (IsSocketReady(server_res->socket)) {
|
||||||
// bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen);
|
// bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen);
|
||||||
// }
|
// }
|
||||||
int bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen);
|
int bytesRecv = SocketReceive(server_res->socket, recvBuffer, msglen);
|
||||||
|
|
||||||
// If we received data, was that data a "Ping!" or a "Pong!"
|
// If we received data, was that data a "Ping!" or a "Pong!"
|
||||||
if (bytesRecv > 0) {
|
if (bytesRecv > 0) {
|
||||||
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
|
if (strcmp(recvBuffer, pingmsg) == 0) { pong = true; }
|
||||||
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
|
if (strcmp(recvBuffer, pongmsg) == 0) { ping = true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
|
// After each delay has expired, send a response "Ping!" for a "Pong!" and vice versa
|
||||||
elapsed += GetFrameTime();
|
elapsed += GetFrameTime();
|
||||||
if (elapsed > delay) {
|
if (elapsed > delay) {
|
||||||
if (ping) {
|
if (ping) {
|
||||||
ping = false;
|
ping = false;
|
||||||
SocketSend(server_res->socket, pingmsg, msglen);
|
SocketSend(server_res->socket, pingmsg, msglen);
|
||||||
} else if (pong) {
|
} else if (pong) {
|
||||||
pong = false;
|
pong = false;
|
||||||
SocketSend(server_res->socket, pongmsg, msglen);
|
SocketSend(server_res->socket, pongmsg, msglen);
|
||||||
}
|
}
|
||||||
elapsed = 0.0f;
|
elapsed = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
InitWindow(
|
InitWindow(
|
||||||
screenWidth, screenHeight, "raylib [network] example - udp server");
|
screenWidth, screenHeight, "raylib [network] example - udp server");
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
SetTraceLogLevel(LOG_DEBUG);
|
SetTraceLogLevel(LOG_DEBUG);
|
||||||
|
|
||||||
// Networking
|
// Networking
|
||||||
InitNetwork();
|
InitNetwork();
|
||||||
|
|
||||||
// Create the server
|
// Create the server
|
||||||
//
|
//
|
||||||
// Performs
|
// Performs
|
||||||
// getaddrinfo
|
// getaddrinfo
|
||||||
// socket
|
// socket
|
||||||
// setsockopt
|
// setsockopt
|
||||||
// bind
|
// bind
|
||||||
// listen
|
// listen
|
||||||
server_res = AllocSocketResult();
|
server_res = AllocSocketResult();
|
||||||
if (!SocketCreate(&server_cfg, server_res)) {
|
if (!SocketCreate(&server_cfg, server_res)) {
|
||||||
TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d",
|
TraceLog(LOG_WARNING, "Failed to open server: status %d, errno %d",
|
||||||
server_res->status, server_res->socket->status);
|
server_res->status, server_res->socket->status);
|
||||||
} else {
|
} else {
|
||||||
if (!SocketBind(&server_cfg, server_res)) {
|
if (!SocketBind(&server_cfg, server_res)) {
|
||||||
TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d",
|
TraceLog(LOG_WARNING, "Failed to bind server: status %d, errno %d",
|
||||||
server_res->status, server_res->socket->status);
|
server_res->status, server_res->socket->status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create & Add sockets to the socket set
|
// Create & Add sockets to the socket set
|
||||||
socket_set = AllocSocketSet(1);
|
socket_set = AllocSocketSet(1);
|
||||||
msglen = strlen(pingmsg) + 1;
|
msglen = strlen(pingmsg) + 1;
|
||||||
memset(recvBuffer, '\0', sizeof(recvBuffer));
|
memset(recvBuffer, '\0', sizeof(recvBuffer));
|
||||||
AddSocket(socket_set, server_res->socket);
|
AddSocket(socket_set, server_res->socket);
|
||||||
|
|
||||||
// Main game loop
|
// Main game loop
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
NetworkUpdate();
|
NetworkUpdate();
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -58,29 +58,29 @@
|
||||||
// Check if a key has been pressed
|
// Check if a key has been pressed
|
||||||
static int kbhit(void)
|
static int kbhit(void)
|
||||||
{
|
{
|
||||||
struct termios oldt, newt;
|
struct termios oldt, newt;
|
||||||
int ch;
|
int ch;
|
||||||
int oldf;
|
int oldf;
|
||||||
|
|
||||||
tcgetattr(STDIN_FILENO, &oldt);
|
tcgetattr(STDIN_FILENO, &oldt);
|
||||||
newt = oldt;
|
newt = oldt;
|
||||||
newt.c_lflag &= ~(ICANON | ECHO);
|
newt.c_lflag &= ~(ICANON | ECHO);
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
||||||
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
|
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
|
||||||
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
|
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
|
||||||
|
|
||||||
ch = getchar();
|
ch = getchar();
|
||||||
|
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||||
fcntl(STDIN_FILENO, F_SETFL, oldf);
|
fcntl(STDIN_FILENO, F_SETFL, oldf);
|
||||||
|
|
||||||
if (ch != EOF)
|
if (ch != EOF)
|
||||||
{
|
{
|
||||||
ungetc(ch, stdin);
|
ungetc(ch, stdin);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get pressed character
|
// Get pressed character
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,10 @@ int main(void)
|
||||||
|
|
||||||
// De-Initialization
|
// De-Initialization
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
DestroyPhysicsBody(circleA);
|
||||||
|
DestroyPhysicsBody(circleB);
|
||||||
|
DestroyPhysicsBody(circleC);
|
||||||
|
DestroyPhysicsBody(floor);
|
||||||
ClosePhysics(); // Unitialize physics
|
ClosePhysics(); // Unitialize physics
|
||||||
|
|
||||||
CloseWindow(); // Close window and OpenGL context
|
CloseWindow(); // Close window and OpenGL context
|
||||||
|
|
|
||||||
BIN
examples/shaders/resources/mask.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
examples/shaders/resources/plasma.png
Normal file
|
After Width: | Height: | Size: 568 KiB |
|
|
@ -8,8 +8,6 @@ varying vec4 fragColor;
|
||||||
|
|
||||||
uniform vec3 viewEye;
|
uniform vec3 viewEye;
|
||||||
uniform vec3 viewCenter;
|
uniform vec3 viewCenter;
|
||||||
uniform vec3 viewUp;
|
|
||||||
uniform float deltaTime;
|
|
||||||
uniform float runTime;
|
uniform float runTime;
|
||||||
uniform vec2 resolution;
|
uniform vec2 resolution;
|
||||||
|
|
||||||
|
|
@ -428,4 +426,4 @@ void main()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gl_FragColor = vec4( tot, 1.0 );
|
gl_FragColor = vec4( tot, 1.0 );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
99
examples/shaders/resources/shaders/glsl330/fog.fs
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
// Input vertex attributes (from vertex shader)
|
||||||
|
in vec2 fragTexCoord;
|
||||||
|
in vec4 fragColor;
|
||||||
|
in vec3 fragPosition;
|
||||||
|
in vec3 fragNormal;
|
||||||
|
|
||||||
|
// Input uniform values
|
||||||
|
uniform sampler2D texture0;
|
||||||
|
uniform vec4 colDiffuse;
|
||||||
|
|
||||||
|
// Output fragment color
|
||||||
|
out vec4 finalColor;
|
||||||
|
|
||||||
|
// NOTE: Add here your custom variables
|
||||||
|
|
||||||
|
#define MAX_LIGHTS 4
|
||||||
|
#define LIGHT_DIRECTIONAL 0
|
||||||
|
#define LIGHT_POINT 1
|
||||||
|
|
||||||
|
struct MaterialProperty {
|
||||||
|
vec3 color;
|
||||||
|
int useSampler;
|
||||||
|
sampler2D sampler;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Light {
|
||||||
|
int enabled;
|
||||||
|
int type;
|
||||||
|
vec3 position;
|
||||||
|
vec3 target;
|
||||||
|
vec4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Input lighting values
|
||||||
|
uniform Light lights[MAX_LIGHTS];
|
||||||
|
uniform vec4 ambient;
|
||||||
|
uniform vec3 viewPos;
|
||||||
|
uniform float fogDensity;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Texel color fetching from texture sampler
|
||||||
|
vec4 texelColor = texture(texture0, fragTexCoord);
|
||||||
|
vec3 lightDot = vec3(0.0);
|
||||||
|
vec3 normal = normalize(fragNormal);
|
||||||
|
vec3 viewD = normalize(viewPos - fragPosition);
|
||||||
|
vec3 specular = vec3(0.0);
|
||||||
|
|
||||||
|
// NOTE: Implement here your fragment shader code
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_LIGHTS; i++)
|
||||||
|
{
|
||||||
|
if (lights[i].enabled == 1)
|
||||||
|
{
|
||||||
|
vec3 light = vec3(0.0);
|
||||||
|
if (lights[i].type == LIGHT_DIRECTIONAL) {
|
||||||
|
light = -normalize(lights[i].target - lights[i].position);
|
||||||
|
}
|
||||||
|
if (lights[i].type == LIGHT_POINT) {
|
||||||
|
light = normalize(lights[i].position - fragPosition);
|
||||||
|
}
|
||||||
|
float NdotL = max(dot(normal, light), 0.0);
|
||||||
|
lightDot += lights[i].color.rgb * NdotL;
|
||||||
|
|
||||||
|
float specCo = 0.0;
|
||||||
|
if(NdotL > 0.0)
|
||||||
|
specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16);//16 =shine
|
||||||
|
specular += specCo;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finalColor = (texelColor * ((colDiffuse+vec4(specular,1)) * vec4(lightDot, 1.0)));
|
||||||
|
finalColor += texelColor * (ambient/10.0);
|
||||||
|
|
||||||
|
// Gamma correction
|
||||||
|
finalColor = pow(finalColor, vec4(1.0/2.2));
|
||||||
|
|
||||||
|
// Fog calculation
|
||||||
|
float dist = length(viewPos - fragPosition);
|
||||||
|
|
||||||
|
// these could be parameters...
|
||||||
|
const vec4 fogColor = vec4(0.5, 0.5, 0.5, 1.0);
|
||||||
|
//const float fogDensity = 0.16;
|
||||||
|
|
||||||
|
// Exponential fog
|
||||||
|
float fogFactor = 1.0/exp((dist*fogDensity)*(dist*fogDensity));
|
||||||
|
|
||||||
|
// Linear fog (less nice)
|
||||||
|
//const float fogStart = 2.0;
|
||||||
|
//const float fogEnd = 10.0;
|
||||||
|
//float fogFactor = (fogEnd - dist)/(fogEnd - fogStart);
|
||||||
|
|
||||||
|
fogFactor = clamp(fogFactor, 0.0, 1.0);
|
||||||
|
|
||||||
|
finalColor = mix(fogColor, finalColor, fogFactor);
|
||||||
|
}
|
||||||
32
examples/shaders/resources/shaders/glsl330/fog.vs
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
// Input vertex attributes
|
||||||
|
in vec3 vertexPosition;
|
||||||
|
in vec2 vertexTexCoord;
|
||||||
|
in vec3 vertexNormal;
|
||||||
|
in vec4 vertexColor;
|
||||||
|
|
||||||
|
// Input uniform values
|
||||||
|
uniform mat4 mvp;
|
||||||
|
uniform mat4 matModel;
|
||||||
|
|
||||||
|
// Output vertex attributes (to fragment shader)
|
||||||
|
out vec2 fragTexCoord;
|
||||||
|
out vec4 fragColor;
|
||||||
|
out vec3 fragPosition;
|
||||||
|
out vec3 fragNormal;
|
||||||
|
|
||||||
|
// NOTE: Add here your custom variables
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Send vertex attributes to fragment shader
|
||||||
|
fragTexCoord = vertexTexCoord;
|
||||||
|
fragColor = vertexColor;
|
||||||
|
fragPosition = vec3(matModel*vec4(vertexPosition, 1.0f));
|
||||||
|
mat3 normalMatrix = transpose(inverse(mat3(matModel)));
|
||||||
|
fragNormal = normalize(normalMatrix*vertexNormal);
|
||||||
|
|
||||||
|
// Calculate final vertex position
|
||||||
|
gl_Position = mvp*vec4(vertexPosition, 1.0);
|
||||||
|
}
|
||||||
21
examples/shaders/resources/shaders/glsl330/mask.fs
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
// Input vertex attributes (from vertex shader)
|
||||||
|
in vec2 fragTexCoord;
|
||||||
|
|
||||||
|
// Input uniform values
|
||||||
|
uniform sampler2D texture0;
|
||||||
|
uniform sampler2D mask;
|
||||||
|
uniform int frame;
|
||||||
|
|
||||||
|
// Output fragment color
|
||||||
|
out vec4 finalColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 maskColour = texture(mask, fragTexCoord+vec2(sin(-frame/150.0)/10.0,cos(-frame/170.0)/10.0));
|
||||||
|
if (maskColour.r < 0.25) discard;
|
||||||
|
vec4 texelColor = texture(texture0, fragTexCoord+vec2(sin(frame/90.0)/8.0,cos(frame/60.0)/8.0));
|
||||||
|
|
||||||
|
finalColor = texelColor * maskColour;
|
||||||
|
}
|
||||||
21
examples/shaders/resources/shaders/glsl330/mask.vs
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
// Input vertex attributes
|
||||||
|
in vec3 vertexPosition;
|
||||||
|
in vec2 vertexTexCoord;
|
||||||
|
|
||||||
|
// Input uniform values
|
||||||
|
uniform mat4 mvp;
|
||||||
|
uniform mat4 matModel;
|
||||||
|
|
||||||
|
// Output vertex attributes (to fragment shader)
|
||||||
|
out vec2 fragTexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Send vertex attributes to fragment shader
|
||||||
|
fragTexCoord = vertexTexCoord;
|
||||||
|
|
||||||
|
// Calculate final vertex position
|
||||||
|
gl_Position = mvp*vec4(vertexPosition, 1.0);
|
||||||
|
}
|
||||||
|
|
@ -9,8 +9,6 @@ out vec4 finalColor;
|
||||||
|
|
||||||
uniform vec3 viewEye;
|
uniform vec3 viewEye;
|
||||||
uniform vec3 viewCenter;
|
uniform vec3 viewCenter;
|
||||||
uniform vec3 viewUp;
|
|
||||||
uniform float deltaTime;
|
|
||||||
uniform float runTime;
|
uniform float runTime;
|
||||||
uniform vec2 resolution;
|
uniform vec2 resolution;
|
||||||
|
|
||||||
|
|
@ -429,4 +427,4 @@ void main()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
finalColor = vec4( tot, 1.0 );
|
finalColor = vec4( tot, 1.0 );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
153
examples/shaders/shaders_fog.c
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
/*******************************************************************************************
|
||||||
|
*
|
||||||
|
* raylib [shaders] example - fog
|
||||||
|
*
|
||||||
|
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||||
|
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
|
||||||
|
*
|
||||||
|
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3).
|
||||||
|
*
|
||||||
|
* This example has been created using raylib 2.5 (www.raylib.com)
|
||||||
|
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||||
|
*
|
||||||
|
* Example contributed by Chris Camacho (@codifies) and reviewed by Ramon Santamaria (@raysan5)
|
||||||
|
*
|
||||||
|
* Chris Camacho (@codifies - http://bedroomcoders.co.uk/) notes:
|
||||||
|
*
|
||||||
|
* This is based on the PBR lighting example, but greatly simplified to aid learning...
|
||||||
|
* actually there is very little of the PBR example left!
|
||||||
|
* When I first looked at the bewildering complexity of the PBR example I feared
|
||||||
|
* I would never understand how I could do simple lighting with raylib however its
|
||||||
|
* a testement to the authors of raylib (including rlights.h) that the example
|
||||||
|
* came together fairly quickly.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Chris Camacho (@codifies) and Ramon Santamaria (@raysan5)
|
||||||
|
*
|
||||||
|
********************************************************************************************/
|
||||||
|
|
||||||
|
#include "raylib.h"
|
||||||
|
|
||||||
|
#include "raymath.h"
|
||||||
|
|
||||||
|
#define RLIGHTS_IMPLEMENTATION
|
||||||
|
#include "rlights.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
// Initialization
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
const int screenWidth = 800;
|
||||||
|
const int screenHeight = 450;
|
||||||
|
|
||||||
|
SetConfigFlags(FLAG_MSAA_4X_HINT); // Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||||
|
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - fog");
|
||||||
|
|
||||||
|
// Define the camera to look into our 3d world
|
||||||
|
Camera camera = {
|
||||||
|
(Vector3){ 2.0f, 2.0f, 6.0f }, // position
|
||||||
|
(Vector3){ 0.0f, 0.5f, 0.0f }, // target
|
||||||
|
(Vector3){ 0.0f, 1.0f, 0.0f }, // up
|
||||||
|
45.0f, CAMERA_PERSPECTIVE }; // fov, type
|
||||||
|
|
||||||
|
// Load models and texture
|
||||||
|
Model modelA = LoadModelFromMesh(GenMeshTorus(0.4f, 1.0f, 16, 32));
|
||||||
|
Model modelB = LoadModelFromMesh(GenMeshCube(1.0f, 1.0f, 1.0f));
|
||||||
|
Model modelC = LoadModelFromMesh(GenMeshSphere(0.5f, 32, 32));
|
||||||
|
Texture texture = LoadTexture("resources/texel_checker.png");
|
||||||
|
|
||||||
|
// Assign texture to default model material
|
||||||
|
modelA.materials[0].maps[MAP_DIFFUSE].texture = texture;
|
||||||
|
modelB.materials[0].maps[MAP_DIFFUSE].texture = texture;
|
||||||
|
modelC.materials[0].maps[MAP_DIFFUSE].texture = texture;
|
||||||
|
|
||||||
|
// Load shader and set up some uniforms
|
||||||
|
Shader shader = LoadShader("resources/shaders/glsl330/fog.vs", "resources/shaders/glsl330/fog.fs");
|
||||||
|
shader.locs[LOC_MATRIX_MODEL] = GetShaderLocation(shader, "matModel");
|
||||||
|
shader.locs[LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos");
|
||||||
|
|
||||||
|
// Ambient light level
|
||||||
|
int ambientLoc = GetShaderLocation(shader, "ambient");
|
||||||
|
SetShaderValue(shader, ambientLoc, (float[4]){ 0.2f, 0.2f, 0.2f, 1.0f }, UNIFORM_VEC4);
|
||||||
|
|
||||||
|
float fogDensity = 0.15f;
|
||||||
|
int fogDensityLoc = GetShaderLocation(shader, "fogDensity");
|
||||||
|
SetShaderValue(shader, fogDensityLoc, &fogDensity, UNIFORM_FLOAT);
|
||||||
|
|
||||||
|
// NOTE: All models share the same shader
|
||||||
|
modelA.materials[0].shader = shader;
|
||||||
|
modelB.materials[0].shader = shader;
|
||||||
|
modelC.materials[0].shader = shader;
|
||||||
|
|
||||||
|
// Using just 1 point lights
|
||||||
|
CreateLight(LIGHT_POINT, (Vector3){ 0, 2, 6 }, Vector3Zero(), WHITE, shader);
|
||||||
|
|
||||||
|
SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode
|
||||||
|
|
||||||
|
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Main game loop
|
||||||
|
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||||
|
{
|
||||||
|
// Update
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
UpdateCamera(&camera); // Update camera
|
||||||
|
|
||||||
|
if (IsKeyDown(KEY_UP))
|
||||||
|
{
|
||||||
|
fogDensity += 0.001;
|
||||||
|
if (fogDensity > 1.0) fogDensity = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsKeyDown(KEY_DOWN))
|
||||||
|
{
|
||||||
|
fogDensity -= 0.001;
|
||||||
|
if (fogDensity < 0.0) fogDensity = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetShaderValue(shader, fogDensityLoc, &fogDensity, UNIFORM_FLOAT);
|
||||||
|
|
||||||
|
// Rotate the torus
|
||||||
|
modelA.transform = MatrixMultiply(modelA.transform, MatrixRotateX(-0.025));
|
||||||
|
modelA.transform = MatrixMultiply(modelA.transform, MatrixRotateZ(0.012));
|
||||||
|
|
||||||
|
// Update the light shader with the camera view position
|
||||||
|
SetShaderValue(shader, shader.locs[LOC_VECTOR_VIEW], &camera.position.x, UNIFORM_VEC3);
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
BeginDrawing();
|
||||||
|
|
||||||
|
ClearBackground(GRAY);
|
||||||
|
|
||||||
|
BeginMode3D(camera);
|
||||||
|
|
||||||
|
// Draw the three models
|
||||||
|
DrawModel(modelA, Vector3Zero(), 1.0f, WHITE);
|
||||||
|
DrawModel(modelB, (Vector3){ -2.6, 0, 0 }, 1.0f, WHITE);
|
||||||
|
DrawModel(modelC, (Vector3){ 2.6, 0, 0 }, 1.0f, WHITE);
|
||||||
|
|
||||||
|
for (int i = -20; i < 20; i += 2) DrawModel(modelA,(Vector3){ i, 0, 2 }, 1.0f, WHITE);
|
||||||
|
|
||||||
|
EndMode3D();
|
||||||
|
|
||||||
|
DrawText(TextFormat("Use KEY_UP/KEY_DOWN to change fog density [%.2f]", fogDensity), 10, 10, 20, RAYWHITE);
|
||||||
|
|
||||||
|
EndDrawing();
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
}
|
||||||
|
|
||||||
|
// De-Initialization
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
UnloadModel(modelA); // Unload the model A
|
||||||
|
UnloadModel(modelB); // Unload the model B
|
||||||
|
UnloadModel(modelC); // Unload the model C
|
||||||
|
UnloadTexture(texture); // Unload the texture
|
||||||
|
UnloadShader(shader); // Unload shader
|
||||||
|
|
||||||
|
CloseWindow(); // Close window and OpenGL context
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
examples/shaders/shaders_fog.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
|
|
@ -28,9 +28,10 @@ int main(void)
|
||||||
{
|
{
|
||||||
// Initialization
|
// Initialization
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
const int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
const int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
|
|
||||||
|
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
||||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - raymarching shapes");
|
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - raymarching shapes");
|
||||||
|
|
||||||
Camera camera = { 0 };
|
Camera camera = { 0 };
|
||||||
|
|
@ -48,12 +49,10 @@ int main(void)
|
||||||
// Get shader locations for required uniforms
|
// Get shader locations for required uniforms
|
||||||
int viewEyeLoc = GetShaderLocation(shader, "viewEye");
|
int viewEyeLoc = GetShaderLocation(shader, "viewEye");
|
||||||
int viewCenterLoc = GetShaderLocation(shader, "viewCenter");
|
int viewCenterLoc = GetShaderLocation(shader, "viewCenter");
|
||||||
int viewUpLoc = GetShaderLocation(shader, "viewUp");
|
|
||||||
int deltaTimeLoc = GetShaderLocation(shader, "deltaTime");
|
|
||||||
int runTimeLoc = GetShaderLocation(shader, "runTime");
|
int runTimeLoc = GetShaderLocation(shader, "runTime");
|
||||||
int resolutionLoc = GetShaderLocation(shader, "resolution");
|
int resolutionLoc = GetShaderLocation(shader, "resolution");
|
||||||
|
|
||||||
float resolution[2] = { screenWidth, screenHeight };
|
float resolution[2] = { (float)screenWidth, (float)screenHeight };
|
||||||
SetShaderValue(shader, resolutionLoc, resolution, UNIFORM_VEC2);
|
SetShaderValue(shader, resolutionLoc, resolution, UNIFORM_VEC2);
|
||||||
|
|
||||||
float runTime = 0.0f;
|
float runTime = 0.0f;
|
||||||
|
|
@ -64,13 +63,22 @@ int main(void)
|
||||||
// Main game loop
|
// Main game loop
|
||||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||||
{
|
{
|
||||||
|
// Check if screen is resized
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
if(IsWindowResized())
|
||||||
|
{
|
||||||
|
screenWidth = GetScreenWidth();
|
||||||
|
screenHeight = GetScreenHeight();
|
||||||
|
float resolution[2] = { (float)screenWidth, (float)screenHeight };
|
||||||
|
SetShaderValue(shader, resolutionLoc, resolution, UNIFORM_VEC2);
|
||||||
|
}
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
UpdateCamera(&camera); // Update camera
|
UpdateCamera(&camera); // Update camera
|
||||||
|
|
||||||
float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z };
|
float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z };
|
||||||
float cameraTarget[3] = { camera.target.x, camera.target.y, camera.target.z };
|
float cameraTarget[3] = { camera.target.x, camera.target.y, camera.target.z };
|
||||||
float cameraUp[3] = { camera.up.x, camera.up.y, camera.up.z };
|
|
||||||
|
|
||||||
float deltaTime = GetFrameTime();
|
float deltaTime = GetFrameTime();
|
||||||
runTime += deltaTime;
|
runTime += deltaTime;
|
||||||
|
|
@ -78,8 +86,6 @@ int main(void)
|
||||||
// Set shader required uniform values
|
// Set shader required uniform values
|
||||||
SetShaderValue(shader, viewEyeLoc, cameraPos, UNIFORM_VEC3);
|
SetShaderValue(shader, viewEyeLoc, cameraPos, UNIFORM_VEC3);
|
||||||
SetShaderValue(shader, viewCenterLoc, cameraTarget, UNIFORM_VEC3);
|
SetShaderValue(shader, viewCenterLoc, cameraTarget, UNIFORM_VEC3);
|
||||||
SetShaderValue(shader, viewUpLoc, cameraUp, UNIFORM_VEC3);
|
|
||||||
SetShaderValue(shader, deltaTimeLoc, &deltaTime, UNIFORM_FLOAT);
|
|
||||||
SetShaderValue(shader, runTimeLoc, &runTime, UNIFORM_FLOAT);
|
SetShaderValue(shader, runTimeLoc, &runTime, UNIFORM_FLOAT);
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -95,7 +101,7 @@ int main(void)
|
||||||
DrawRectangle(0, 0, screenWidth, screenHeight, WHITE);
|
DrawRectangle(0, 0, screenWidth, screenHeight, WHITE);
|
||||||
EndShaderMode();
|
EndShaderMode();
|
||||||
|
|
||||||
DrawText("(c) Raymarching shader by Iñigo Quilez. MIT License.", screenWidth - 280, screenHeight - 20, 10, GRAY);
|
DrawText("(c) Raymarching shader by Iñigo Quilez. MIT License.", screenWidth - 280, screenHeight - 20, 10, BLACK);
|
||||||
|
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -109,4 +115,4 @@ int main(void)
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
139
examples/shaders/shaders_simple_mask.c
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*******************************************************************************************
|
||||||
|
*
|
||||||
|
* raylib [shaders] example - Simple shader mask
|
||||||
|
*
|
||||||
|
* This example has been created using raylib 2.5 (www.raylib.com)
|
||||||
|
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||||
|
*
|
||||||
|
* Example contributed by Chris Camacho (@codifies) and reviewed by Ramon Santamaria (@raysan5)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Chris Camacho (@codifies) and Ramon Santamaria (@raysan5)
|
||||||
|
*
|
||||||
|
********************************************************************************************
|
||||||
|
*
|
||||||
|
* After a model is loaded it has a default material, this material can be
|
||||||
|
* modified in place rather than creating one from scratch...
|
||||||
|
* While all of the maps have particular names, they can be used for any purpose
|
||||||
|
* except for three maps that are applied as cubic maps (see below)
|
||||||
|
*
|
||||||
|
********************************************************************************************/
|
||||||
|
|
||||||
|
#include "raylib.h"
|
||||||
|
#include "raymath.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
// Initialization
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
const int screenWidth = 800;
|
||||||
|
const int screenHeight = 450;
|
||||||
|
|
||||||
|
InitWindow(screenWidth, screenHeight, "raylib - simple shader mask");
|
||||||
|
|
||||||
|
// Define the camera to look into our 3d world
|
||||||
|
Camera camera = { 0 };
|
||||||
|
camera.position = (Vector3){ 0.0f, 1.0f, 2.0f };
|
||||||
|
camera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
|
||||||
|
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
|
||||||
|
camera.fovy = 45.0f;
|
||||||
|
camera.type = CAMERA_PERSPECTIVE;
|
||||||
|
|
||||||
|
// Define our three models to show the shader on
|
||||||
|
Mesh torus = GenMeshTorus(.3, 1, 16, 32);
|
||||||
|
Model model1 = LoadModelFromMesh(torus);
|
||||||
|
|
||||||
|
Mesh cube = GenMeshCube(.8,.8,.8);
|
||||||
|
Model model2 = LoadModelFromMesh(cube);
|
||||||
|
|
||||||
|
// Generate model to be shaded just to see the gaps in the other two
|
||||||
|
Mesh sphere = GenMeshSphere(1, 16, 16);
|
||||||
|
Model model3 = LoadModelFromMesh(sphere);
|
||||||
|
|
||||||
|
// Load the shader
|
||||||
|
Shader shader = LoadShader("resources/shaders/glsl330/mask.vs", "resources/shaders/glsl330/mask.fs");
|
||||||
|
|
||||||
|
// Load and apply the diffuse texture (colour map)
|
||||||
|
Texture texDiffuse = LoadTexture("resources/plasma.png");
|
||||||
|
model1.materials[0].maps[MAP_DIFFUSE].texture = texDiffuse;
|
||||||
|
model2.materials[0].maps[MAP_DIFFUSE].texture = texDiffuse;
|
||||||
|
|
||||||
|
// Using MAP_EMISSION as a spare slot to use for 2nd texture
|
||||||
|
// NOTE: Don't use MAP_IRRADIANCE, MAP_PREFILTER or MAP_CUBEMAP
|
||||||
|
// as they are bound as cube maps
|
||||||
|
Texture texMask = LoadTexture("resources/mask.png");
|
||||||
|
model1.materials[0].maps[MAP_EMISSION].texture = texMask;
|
||||||
|
model2.materials[0].maps[MAP_EMISSION].texture = texMask;
|
||||||
|
shader.locs[LOC_MAP_EMISSION] = GetShaderLocation(shader, "mask");
|
||||||
|
|
||||||
|
// Frame is incremented each frame to animate the shader
|
||||||
|
int shaderFrame = GetShaderLocation(shader, "framesCounter");
|
||||||
|
|
||||||
|
// Apply the shader to the two models
|
||||||
|
model1.materials[0].shader = shader;
|
||||||
|
model2.materials[0].shader = shader;
|
||||||
|
|
||||||
|
int framesCounter = 0;
|
||||||
|
Vector3 rotation = { 0 }; // Model rotation angles
|
||||||
|
|
||||||
|
SetTargetFPS(60); // Set to run at 60 frames-per-second
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Main game loop
|
||||||
|
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||||
|
{
|
||||||
|
// Update
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
framesCounter++;
|
||||||
|
rotation.x += 0.01f;
|
||||||
|
rotation.y += 0.005f;
|
||||||
|
rotation.z -= 0.0025f;
|
||||||
|
|
||||||
|
// Send frames counter to shader for animation
|
||||||
|
SetShaderValue(shader, shaderFrame, &framesCounter, UNIFORM_INT);
|
||||||
|
|
||||||
|
// Rotate one of the models
|
||||||
|
model1.transform = MatrixRotateXYZ(rotation);
|
||||||
|
|
||||||
|
UpdateCamera(&camera);
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
BeginDrawing();
|
||||||
|
|
||||||
|
ClearBackground(DARKBLUE);
|
||||||
|
|
||||||
|
BeginMode3D(camera);
|
||||||
|
|
||||||
|
DrawModel(model1, (Vector3){0.5,0,0}, 1, WHITE);
|
||||||
|
DrawModelEx(model2, (Vector3){-.5,0,0}, (Vector3){1,1,0}, 50, (Vector3){1,1,1}, WHITE);
|
||||||
|
DrawModel(model3,(Vector3){0,0,-1.5}, 1, WHITE);
|
||||||
|
DrawGrid(10, 1.0f); // Draw a grid
|
||||||
|
|
||||||
|
EndMode3D();
|
||||||
|
|
||||||
|
DrawRectangle(16, 698, MeasureText(FormatText("Frame: %i", framesCounter), 20) + 8, 42, BLUE);
|
||||||
|
DrawText(FormatText("Frame: %i", framesCounter), 20, 700, 20, WHITE);
|
||||||
|
|
||||||
|
DrawFPS(10, 10);
|
||||||
|
|
||||||
|
EndDrawing();
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
}
|
||||||
|
|
||||||
|
// De-Initialization
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
UnloadModel(model1);
|
||||||
|
UnloadModel(model2);
|
||||||
|
UnloadModel(model3);
|
||||||
|
|
||||||
|
UnloadTexture(texDiffuse); // Unload default diffuse texture
|
||||||
|
UnloadTexture(texMask); // Unload texture mask
|
||||||
|
|
||||||
|
UnloadShader(shader); // Unload shader
|
||||||
|
|
||||||
|
CloseWindow(); // Close window and OpenGL context
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -33,38 +33,38 @@ int main(void)
|
||||||
const int screenWidth = 800;
|
const int screenWidth = 800;
|
||||||
const int screenHeight = 450;
|
const int screenHeight = 450;
|
||||||
|
|
||||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture waves");
|
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture waves");
|
||||||
|
|
||||||
// Load texture texture to apply shaders
|
// Load texture texture to apply shaders
|
||||||
Texture2D texture = LoadTexture("resources/space.png");
|
Texture2D texture = LoadTexture("resources/space.png");
|
||||||
|
|
||||||
// Load shader and setup location points and values
|
// Load shader and setup location points and values
|
||||||
Shader shader = LoadShader(0, FormatText("resources/shaders/glsl%i/wave.fs", GLSL_VERSION));
|
Shader shader = LoadShader(0, FormatText("resources/shaders/glsl%i/wave.fs", GLSL_VERSION));
|
||||||
|
|
||||||
int secondsLoc = GetShaderLocation(shader, "secondes");
|
int secondsLoc = GetShaderLocation(shader, "secondes");
|
||||||
int freqXLoc = GetShaderLocation(shader, "freqX");
|
int freqXLoc = GetShaderLocation(shader, "freqX");
|
||||||
int freqYLoc = GetShaderLocation(shader, "freqY");
|
int freqYLoc = GetShaderLocation(shader, "freqY");
|
||||||
int ampXLoc = GetShaderLocation(shader, "ampX");
|
int ampXLoc = GetShaderLocation(shader, "ampX");
|
||||||
int ampYLoc = GetShaderLocation(shader, "ampY");
|
int ampYLoc = GetShaderLocation(shader, "ampY");
|
||||||
int speedXLoc = GetShaderLocation(shader, "speedX");
|
int speedXLoc = GetShaderLocation(shader, "speedX");
|
||||||
int speedYLoc = GetShaderLocation(shader, "speedY");
|
int speedYLoc = GetShaderLocation(shader, "speedY");
|
||||||
|
|
||||||
// Shader uniform values that can be updated at any time
|
// Shader uniform values that can be updated at any time
|
||||||
float freqX = 25.0f;
|
float freqX = 25.0f;
|
||||||
float freqY = 25.0f;
|
float freqY = 25.0f;
|
||||||
float ampX = 5.0f;
|
float ampX = 5.0f;
|
||||||
float ampY = 5.0f;
|
float ampY = 5.0f;
|
||||||
float speedX = 8.0f;
|
float speedX = 8.0f;
|
||||||
float speedY = 8.0f;
|
float speedY = 8.0f;
|
||||||
|
|
||||||
float screenSize[2] = { (float)GetScreenWidth(), (float)GetScreenHeight() };
|
float screenSize[2] = { (float)GetScreenWidth(), (float)GetScreenHeight() };
|
||||||
SetShaderValue(shader, GetShaderLocation(shader, "size"), &screenSize, UNIFORM_VEC2);
|
SetShaderValue(shader, GetShaderLocation(shader, "size"), &screenSize, UNIFORM_VEC2);
|
||||||
SetShaderValue(shader, freqXLoc, &freqX, UNIFORM_FLOAT);
|
SetShaderValue(shader, freqXLoc, &freqX, UNIFORM_FLOAT);
|
||||||
SetShaderValue(shader, freqYLoc, &freqY, UNIFORM_FLOAT);
|
SetShaderValue(shader, freqYLoc, &freqY, UNIFORM_FLOAT);
|
||||||
SetShaderValue(shader, ampXLoc, &X, UNIFORM_FLOAT);
|
SetShaderValue(shader, ampXLoc, &X, UNIFORM_FLOAT);
|
||||||
SetShaderValue(shader, ampYLoc, &Y, UNIFORM_FLOAT);
|
SetShaderValue(shader, ampYLoc, &Y, UNIFORM_FLOAT);
|
||||||
SetShaderValue(shader, speedXLoc, &speedX, UNIFORM_FLOAT);
|
SetShaderValue(shader, speedXLoc, &speedX, UNIFORM_FLOAT);
|
||||||
SetShaderValue(shader, speedYLoc, &speedY, UNIFORM_FLOAT);
|
SetShaderValue(shader, speedYLoc, &speedY, UNIFORM_FLOAT);
|
||||||
|
|
||||||
float seconds = 0.0f;
|
float seconds = 0.0f;
|
||||||
|
|
||||||
|
|
@ -76,9 +76,9 @@ int main(void)
|
||||||
{
|
{
|
||||||
// Update
|
// Update
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
seconds += GetFrameTime();
|
seconds += GetFrameTime();
|
||||||
|
|
||||||
SetShaderValue(shader, secondsLoc, &seconds, UNIFORM_FLOAT);
|
SetShaderValue(shader, secondsLoc, &seconds, UNIFORM_FLOAT);
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
|
|
@ -87,12 +87,12 @@ int main(void)
|
||||||
|
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
|
|
||||||
BeginShaderMode(shader);
|
BeginShaderMode(shader);
|
||||||
|
|
||||||
DrawTexture(texture, 0, 0, WHITE);
|
DrawTexture(texture, 0, 0, WHITE);
|
||||||
DrawTexture(texture, texture.width, 0, WHITE);
|
DrawTexture(texture, texture.width, 0, WHITE);
|
||||||
|
|
||||||
EndShaderMode();
|
EndShaderMode();
|
||||||
|
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
/*******************************************************************************************
|
/*******************************************************************************************
|
||||||
*
|
*
|
||||||
* raylib [text] example - TTF loading and usage
|
* raylib [text] example - Font filters
|
||||||
|
*
|
||||||
|
* After font loading, font texture atlas filter could be configured for a softer
|
||||||
|
* display of the font when scaling it to different sizes, that way, it's not required
|
||||||
|
* to generate multiple fonts at multiple sizes (as long as the scaling is not very different)
|
||||||
*
|
*
|
||||||
* This example has been created using raylib 1.3.0 (www.raylib.com)
|
* This example has been created using raylib 1.3.0 (www.raylib.com)
|
||||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||||
|
|
@ -18,9 +22,9 @@ int main(void)
|
||||||
const int screenWidth = 800;
|
const int screenWidth = 800;
|
||||||
const int screenHeight = 450;
|
const int screenHeight = 450;
|
||||||
|
|
||||||
InitWindow(screenWidth, screenHeight, "raylib [text] example - ttf loading");
|
InitWindow(screenWidth, screenHeight, "raylib [text] example - font filters");
|
||||||
|
|
||||||
const char msg[50] = "TTF Font";
|
const char msg[50] = "Loaded Font";
|
||||||
|
|
||||||
// NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required)
|
// NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required)
|
||||||
|
|
||||||
|
|
@ -78,7 +82,8 @@ int main(void)
|
||||||
int count = 0;
|
int count = 0;
|
||||||
char **droppedFiles = GetDroppedFiles(&count);
|
char **droppedFiles = GetDroppedFiles(&count);
|
||||||
|
|
||||||
if (count == 1) // Only support one ttf file dropped
|
// NOTE: We only support first ttf file dropped
|
||||||
|
if (IsFileExtension(droppedFiles[0], ".ttf"))
|
||||||
{
|
{
|
||||||
UnloadFont(font);
|
UnloadFont(font);
|
||||||
font = LoadFontEx(droppedFiles[0], fontSize, 0, 0);
|
font = LoadFontEx(droppedFiles[0], fontSize, 0, 0);
|
||||||
BIN
examples/text/text_font_filters.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
|
|
@ -1,11 +1,20 @@
|
||||||
/*******************************************************************************************
|
/*******************************************************************************************
|
||||||
*
|
*
|
||||||
* raylib [text] example - BMFont and TTF Fonts loading
|
* raylib [text] example - Font loading
|
||||||
*
|
*
|
||||||
* This example has been created using raylib 1.4 (www.raylib.com)
|
* raylib can load fonts from multiple file formats:
|
||||||
|
*
|
||||||
|
* - TTF/OTF > Sprite font atlas is generated on loading, user can configure
|
||||||
|
* some of the generation parameters (size, characters to include)
|
||||||
|
* - BMFonts > Angel code font fileformat, sprite font image must be provided
|
||||||
|
* together with the .fnt file, font generation cna not be configured
|
||||||
|
* - XNA Spritefont > Sprite font image, following XNA Spritefont conventions,
|
||||||
|
* Characters in image must follow some spacing and order rules
|
||||||
|
*
|
||||||
|
* This example has been created using raylib 2.6 (www.raylib.com)
|
||||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016 Ramon Santamaria (@raysan5)
|
* Copyright (c) 2016-2019 Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
********************************************************************************************/
|
********************************************************************************************/
|
||||||
|
|
||||||
|
|
@ -18,7 +27,7 @@ int main(void)
|
||||||
const int screenWidth = 800;
|
const int screenWidth = 800;
|
||||||
const int screenHeight = 450;
|
const int screenHeight = 450;
|
||||||
|
|
||||||
InitWindow(screenWidth, screenHeight, "raylib [text] example - bmfont and ttf sprite fonts loading");
|
InitWindow(screenWidth, screenHeight, "raylib [text] example - font loading");
|
||||||
|
|
||||||
// Define characters to draw
|
// Define characters to draw
|
||||||
// NOTE: raylib supports UTF-8 encoding, following list is actually codified as UTF8 internally
|
// NOTE: raylib supports UTF-8 encoding, following list is actually codified as UTF8 internally
|
||||||
|
|
@ -75,7 +84,7 @@ int main(void)
|
||||||
UnloadFont(fontBm); // AngelCode Font unloading
|
UnloadFont(fontBm); // AngelCode Font unloading
|
||||||
UnloadFont(fontTtf); // TTF Font unloading
|
UnloadFont(fontTtf); // TTF Font unloading
|
||||||
|
|
||||||
CloseWindow(); // Close window and OpenGL context
|
CloseWindow(); // Close window and OpenGL context
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
|
@ -1,6 +1,15 @@
|
||||||
/*******************************************************************************************
|
/*******************************************************************************************
|
||||||
*
|
*
|
||||||
* raylib [text] example - Font loading and usage
|
* raylib [text] example - Sprite font loading
|
||||||
|
*
|
||||||
|
* Loaded sprite fonts have been generated following XNA SpriteFont conventions:
|
||||||
|
* - Characters must be ordered starting with character 32 (Space)
|
||||||
|
* - Every character must be contained within the same Rectangle height
|
||||||
|
* - Every character and every line must be separated the same distance
|
||||||
|
* - Rectangles must be defined by a MAGENTA color background
|
||||||
|
*
|
||||||
|
* If following this constraints, a font can be provided just by an image,
|
||||||
|
* this is quite handy to avoid additional information files (like BMFonts use).
|
||||||
*
|
*
|
||||||
* This example has been created using raylib 1.0 (www.raylib.com)
|
* This example has been created using raylib 1.0 (www.raylib.com)
|
||||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||||
|
|
@ -18,7 +27,7 @@ int main(void)
|
||||||
const int screenWidth = 800;
|
const int screenWidth = 800;
|
||||||
const int screenHeight = 450;
|
const int screenHeight = 450;
|
||||||
|
|
||||||
InitWindow(screenWidth, screenHeight, "raylib [text] example - sprite fonts usage");
|
InitWindow(screenWidth, screenHeight, "raylib [text] example - sprite font loading");
|
||||||
|
|
||||||
const char msg1[50] = "THIS IS A custom SPRITE FONT...";
|
const char msg1[50] = "THIS IS A custom SPRITE FONT...";
|
||||||
const char msg2[50] = "...and this is ANOTHER CUSTOM font...";
|
const char msg2[50] = "...and this is ANOTHER CUSTOM font...";
|
||||||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
|
@ -271,7 +271,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
// Draw the info text below the main message
|
// Draw the info text below the main message
|
||||||
int size = strlen(messages[message].text);
|
int size = strlen(messages[message].text);
|
||||||
unsigned int len = TextCountCodepoints(messages[message].text);
|
int len = GetCodepointsCount(messages[message].text);
|
||||||
const char *info = TextFormat("%s %u characters %i bytes", messages[message].language, len, size);
|
const char *info = TextFormat("%s %u characters %i bytes", messages[message].language, len, size);
|
||||||
sz = MeasureTextEx(GetFontDefault(), info, 10, 1.0f);
|
sz = MeasureTextEx(GetFontDefault(), info, 10, 1.0f);
|
||||||
Vector2 pos = { textRect.x + textRect.width - sz.x, msgRect.y + msgRect.height - sz.y - 2 };
|
Vector2 pos = { textRect.x + textRect.width - sz.x, msgRect.y + msgRect.height - sz.y - 2 };
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
#include <stdlib.h> // Required for: malloc(), free()
|
#include <stdlib.h> // Required for: malloc(), free()
|
||||||
|
|
||||||
#define MAX_BUNNIES 100000 // 100K bunnies limit
|
#define MAX_BUNNIES 50000 // 50K bunnies limit
|
||||||
|
|
||||||
// This is the maximum amount of elements (quads) per batch
|
// This is the maximum amount of elements (quads) per batch
|
||||||
// NOTE: This value is defined in [rlgl] module and can be changed there
|
// NOTE: This value is defined in [rlgl] module and can be changed there
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,8 @@ void UpdateDrawFrame(void); // Update and Draw one frame
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
// Initialization (Note windowTitle is unused on Android)
|
// Initialization (Note windowTitle is unused on Android)
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
InitWindow(screenWidth, screenHeight, "JUST DO [GGJ15]");
|
InitWindow(screenWidth, screenHeight, "JUST DO [GGJ15]");
|
||||||
|
|
||||||
// Load global data here (assets that must be available in all screens, i.e. fonts)
|
// Load global data here (assets that must be available in all screens, i.e. fonts)
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,8 @@ void UpdateDrawFrame(void); // Update and Draw one frame
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
// Initialization (Note windowTitle is unused on Android)
|
// Initialization (Note windowTitle is unused on Android)
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
InitWindow(screenWidth, screenHeight, "KOALA SEASONS");
|
InitWindow(screenWidth, screenHeight, "KOALA SEASONS");
|
||||||
|
|
||||||
// Load global data here (assets that must be available in all screens, i.e. fonts)
|
// Load global data here (assets that must be available in all screens, i.e. fonts)
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,8 @@ void UpdateDrawFrame(void); // Update and Draw one frame
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
// Initialization (Note windowTitle is unused on Android)
|
// Initialization (Note windowTitle is unused on Android)
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
InitWindow(screenWidth, screenHeight, "LIGHT MY RITUAL! [GGJ16]");
|
InitWindow(screenWidth, screenHeight, "LIGHT MY RITUAL! [GGJ16]");
|
||||||
|
|
||||||
// Global data loading (assets that must be available in all screens, i.e. fonts)
|
// Global data loading (assets that must be available in all screens, i.e. fonts)
|
||||||
|
|
@ -69,7 +69,7 @@ int main(void)
|
||||||
UnloadImage(image); // Unload image from CPU memory (RAM)
|
UnloadImage(image); // Unload image from CPU memory (RAM)
|
||||||
|
|
||||||
font = LoadFont("resources/font_arcadian.png");
|
font = LoadFont("resources/font_arcadian.png");
|
||||||
//doors = LoadTexture("resources/textures/doors.png");
|
//doors = LoadTexture("resources/textures/doors.png");
|
||||||
//sndDoor = LoadSound("resources/audio/door.ogg");
|
//sndDoor = LoadSound("resources/audio/door.ogg");
|
||||||
|
|
||||||
music = LoadMusicStream("resources/audio/ambient.ogg");
|
music = LoadMusicStream("resources/audio/ambient.ogg");
|
||||||
|
|
@ -270,7 +270,7 @@ void UpdateDrawFrame(void)
|
||||||
case GAMEPLAY: DrawGameplayScreen(); break;
|
case GAMEPLAY: DrawGameplayScreen(); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onTransition) DrawTransition();
|
if (onTransition) DrawTransition();
|
||||||
|
|
||||||
//DrawFPS(10, 10);
|
//DrawFPS(10, 10);
|
||||||
|
|
|
||||||
|
|
@ -271,11 +271,11 @@ static void DrawLifes(void)
|
||||||
{
|
{
|
||||||
if (player.numLifes != 0)
|
if (player.numLifes != 0)
|
||||||
{
|
{
|
||||||
Vector2 position = { 20, GetScreenHeight() - texLife.height - 20 };
|
Vector2 position = { 20, GetScreenHeight() - texLife.height - 20 };
|
||||||
|
|
||||||
for(int i = 0; i < player.numLifes; i++)
|
for(int i = 0; i < player.numLifes; i++)
|
||||||
{
|
{
|
||||||
DrawTexture(texLife, position.x + i*texLife.width, position.y, Fade(RAYWHITE, 0.7f));
|
DrawTexture(texLife, position.x + i*texLife.width, position.y, Fade(RAYWHITE, 0.7f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -52,8 +52,8 @@ void UpdateDrawFrame(void); // Update and Draw one frame
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
// Initialization (Note windowTitle is unused on Android)
|
// Initialization (Note windowTitle is unused on Android)
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
InitWindow(screenWidth, screenHeight, "SKULLY ESCAPE [KING GAMEJAM 2015]");
|
InitWindow(screenWidth, screenHeight, "SKULLY ESCAPE [KING GAMEJAM 2015]");
|
||||||
|
|
||||||
// Global data loading (assets that must be available in all screens, i.e. fonts)
|
// Global data loading (assets that must be available in all screens, i.e. fonts)
|
||||||
|
|
@ -63,10 +63,10 @@ int main(void)
|
||||||
PlayMusicStream(music);
|
PlayMusicStream(music);
|
||||||
|
|
||||||
font = LoadFont("resources/textures/alagard.png");
|
font = LoadFont("resources/textures/alagard.png");
|
||||||
doors = LoadTexture("resources/textures/doors.png");
|
doors = LoadTexture("resources/textures/doors.png");
|
||||||
sndDoor = LoadSound("resources/audio/door.ogg");
|
sndDoor = LoadSound("resources/audio/door.ogg");
|
||||||
sndScream = LoadSound("resources/audio/scream.ogg");
|
sndScream = LoadSound("resources/audio/scream.ogg");
|
||||||
|
|
||||||
InitPlayer();
|
InitPlayer();
|
||||||
|
|
||||||
// Setup and Init first screen
|
// Setup and Init first screen
|
||||||
|
|
@ -90,7 +90,7 @@ int main(void)
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Unload all global loaded data (i.e. fonts) here!
|
// Unload all global loaded data (i.e. fonts) here!
|
||||||
UnloadPlayer();
|
UnloadPlayer();
|
||||||
UnloadFont(font);
|
UnloadFont(font);
|
||||||
UnloadTexture(doors);
|
UnloadTexture(doors);
|
||||||
UnloadSound(sndDoor);
|
UnloadSound(sndDoor);
|
||||||
|
|
@ -397,7 +397,7 @@ void UpdateDrawFrame(void)
|
||||||
case ENDING: DrawEndingScreen(); break;
|
case ENDING: DrawEndingScreen(); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onTransition) DrawTransition();
|
if (onTransition) DrawTransition();
|
||||||
|
|
||||||
//DrawFPS(10, 10);
|
//DrawFPS(10, 10);
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ int main(void)
|
||||||
fontMission = LoadFontEx("resources/fonts/traveling_typewriter.ttf", 64, 0, 250);
|
fontMission = LoadFontEx("resources/fonts/traveling_typewriter.ttf", 64, 0, 250);
|
||||||
texButton = LoadTexture("resources/textures/title_ribbon.png");
|
texButton = LoadTexture("resources/textures/title_ribbon.png");
|
||||||
|
|
||||||
// UI BUTTON
|
// UI BUTTON
|
||||||
recButton.width = texButton.width;
|
recButton.width = texButton.width;
|
||||||
recButton.height = texButton.height;
|
recButton.height = texButton.height;
|
||||||
recButton.x = screenWidth - recButton.width;
|
recButton.x = screenWidth - recButton.width;
|
||||||
|
|
@ -121,7 +121,7 @@ int main(void)
|
||||||
|
|
||||||
UnloadFont(fontMission);
|
UnloadFont(fontMission);
|
||||||
UnloadTexture(texButton);
|
UnloadTexture(texButton);
|
||||||
|
|
||||||
CloseAudioDevice(); // Close audio context
|
CloseAudioDevice(); // Close audio context
|
||||||
|
|
||||||
CloseWindow(); // Close window and OpenGL context
|
CloseWindow(); // Close window and OpenGL context
|
||||||
|
|
@ -438,7 +438,7 @@ bool IsButtonPressed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else fadeButton = 0.80f;
|
else fadeButton = 0.80f;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,8 @@ static void UpdateDrawFrame(void); // Update and Draw one frame
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
// Initialization
|
// Initialization
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
#if defined(PLATFORM_DESKTOP)
|
#if defined(PLATFORM_DESKTOP)
|
||||||
// TODO: Support for dropped files on the exe
|
// TODO: Support for dropped files on the exe
|
||||||
|
|
||||||
|
|
@ -299,7 +299,7 @@ static void UpdateDrawFrame(void)
|
||||||
case ENDING: DrawEndingScreen(); break;
|
case ENDING: DrawEndingScreen(); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw full screen rectangle in front of everything
|
// Draw full screen rectangle in front of everything
|
||||||
if (onTransition) DrawTransition();
|
if (onTransition) DrawTransition();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,38 +2,38 @@
|
||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
int screenWidth = 800;
|
int screenWidth = 800;
|
||||||
int screenHeight = 450;
|
int screenHeight = 450;
|
||||||
|
|
||||||
InitWindow(screenWidth, screenHeight, "raylib");
|
InitWindow(screenWidth, screenHeight, "raylib");
|
||||||
|
|
||||||
Camera cam;
|
Camera cam;
|
||||||
cam.position = (Vector3){ 0.f, 10.f, 8.f };
|
cam.position = (Vector3){ 0.f, 10.f, 8.f };
|
||||||
cam.target = (Vector3){ 0.f, 0.f, 0.f };
|
cam.target = (Vector3){ 0.f, 0.f, 0.f };
|
||||||
cam.up = (Vector3){ 0.f, 1.f, 0.f };
|
cam.up = (Vector3){ 0.f, 1.f, 0.f };
|
||||||
cam.fovy = 60.f;
|
cam.fovy = 60.f;
|
||||||
cam.type = CAMERA_PERSPECTIVE;
|
cam.type = CAMERA_PERSPECTIVE;
|
||||||
|
|
||||||
Vector3 cubePos = { 0.f, 0.f, 0.f };
|
Vector3 cubePos = { 0.f, 0.f, 0.f };
|
||||||
|
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
|
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
cam.position.x = sin(GetTime()) * 10.f;
|
cam.position.x = sin(GetTime()) * 10.f;
|
||||||
cam.position.z = cos(GetTime()) * 10.f;
|
cam.position.z = cos(GetTime()) * 10.f;
|
||||||
|
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
BeginMode3D(cam);
|
BeginMode3D(cam);
|
||||||
DrawCube(cubePos, 2.f, 2.f, 2.f, RED);
|
DrawCube(cubePos, 2.f, 2.f, 2.f, RED);
|
||||||
DrawCubeWires(cubePos, 2.f, 2.f, 2.f, MAROON);
|
DrawCubeWires(cubePos, 2.f, 2.f, 2.f, MAROON);
|
||||||
DrawGrid(10, 1.f);
|
DrawGrid(10, 1.f);
|
||||||
EndMode3D();
|
EndMode3D();
|
||||||
DrawText("This is a raylib example", 10, 40, 20, DARKGRAY);
|
DrawText("This is a raylib example", 10, 40, 20, DARKGRAY);
|
||||||
DrawFPS(10, 10);
|
DrawFPS(10, 10);
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
cmake_minimum_required(VERSION 3.11) # FetchContent is available in 3.11+
|
cmake_minimum_required(VERSION 3.11) # FetchContent is available in 3.11+
|
||||||
project(example)
|
project(example)
|
||||||
|
|
||||||
find_package(raylib 2.0 QUIET) # Let CMake search for a raylib-config.cmake
|
# Set this to the minimal version you want to support
|
||||||
|
find_package(raylib 2.5 QUIET) # Let CMake search for a raylib-config.cmake
|
||||||
|
|
||||||
# You could change the QUIET above to REQUIRED and remove this if() clause
|
# You could change the QUIET above to REQUIRED and remove this if() clause
|
||||||
# This part downloads raylib and builds it if it's not installed on your system
|
# This part downloads raylib and builds it if it's not installed on your system
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,17 @@ This folder contains raylib templates for some common IDEs.
|
||||||
|
|
||||||
IDE | Platform | Template type | State
|
IDE | Platform | Template type | State
|
||||||
----| ---------| ------------- | -----
|
----| ---------| ------------- | -----
|
||||||
|
[4coder](http://4coder.net/) | Windows | example compiling | DONE
|
||||||
[Builder](https://wiki.gnome.org/Apps/Builder) | Linux | example compiling | DONE
|
[Builder](https://wiki.gnome.org/Apps/Builder) | Linux | example compiling | DONE
|
||||||
[CMake](https://cmake.org/) | n/a | example compiling and raylib source downloading/building if necessary | DONE
|
[CMake](https://cmake.org/) | n/a | example compiling and raylib source downloading/building if necessary | DONE
|
||||||
[CodeBlocks](http://www.codeblocks.org/) | Linux, Windows | example compiling | DONE
|
[CodeBlocks](http://www.codeblocks.org/) | Linux, Windows | example compiling | DONE
|
||||||
[Geany](https://www.geany.org/) | Linux, Windows | - | INCOMPLETE
|
[Geany](https://www.geany.org/) | Linux, Windows | - | DONE
|
||||||
[KDevelop](https://www.kdevelop.org/) | Linux, Windows, macOS | - | INCOMPLETE
|
[KDevelop](https://www.kdevelop.org/) | Linux, Windows, macOS | - | INCOMPLETE
|
||||||
[Notepad++](https://notepad-plus-plus.org/) | Windows | source/example compiling | DONE
|
[Notepad++](https://notepad-plus-plus.org/) | Windows | source/example compiling | DONE
|
||||||
|
[Sublime Text](https://www.sublimetext.com/) | Windows, Linux, macOS | source and example | DONE
|
||||||
[VS2015](https://www.visualstudio.com) | Windows | source/example compiling | DONE
|
[VS2015](https://www.visualstudio.com) | Windows | source/example compiling | DONE
|
||||||
[VS2017](https://www.visualstudio.com) | Windows | source/example compiling | DONE
|
[VS2017](https://www.visualstudio.com) | Windows | source/example compiling | DONE
|
||||||
[VSCode](https://code.visualstudio.com/) | Windows, macOS | example compiling | DONE
|
[VSCode](https://code.visualstudio.com/) | Windows, macOS | example compiling | DONE
|
||||||
|
scripts | Windows, Linux, macOS | source and example | DONE
|
||||||
|
|
||||||
*New IDEs config files are welcome!*
|
*New IDEs config files are welcome!*
|
||||||
|
|
|
||||||
|
|
@ -25,21 +25,21 @@ int main()
|
||||||
{
|
{
|
||||||
// Initialization
|
// Initialization
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
const int screenWidth = 800;
|
const int screenWidth = 800;
|
||||||
const int screenHeight = 450;
|
const int screenHeight = 450;
|
||||||
|
|
||||||
InitWindow(screenWidth, screenHeight, "raylib");
|
InitWindow(screenWidth, screenHeight, "raylib");
|
||||||
|
|
||||||
Camera camera = { 0 };
|
Camera camera = { 0 };
|
||||||
camera.position = (Vector3){ 10.0f, 10.0f, 8.0f };
|
camera.position = (Vector3){ 10.0f, 10.0f, 8.0f };
|
||||||
camera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
|
camera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
|
||||||
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
|
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
|
||||||
camera.fovy = 60.0f;
|
camera.fovy = 60.0f;
|
||||||
camera.type = CAMERA_PERSPECTIVE;
|
camera.type = CAMERA_PERSPECTIVE;
|
||||||
|
|
||||||
SetCameraMode(camera, CAMERA_ORBITAL);
|
SetCameraMode(camera, CAMERA_ORBITAL);
|
||||||
|
|
||||||
Vector3 cubePosition = { 0.0f };
|
Vector3 cubePosition = { 0.0f };
|
||||||
|
|
||||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
@ -49,30 +49,30 @@ int main()
|
||||||
{
|
{
|
||||||
// Update
|
// Update
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
UpdateCamera(&camera);
|
UpdateCamera(&camera);
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
|
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
|
|
||||||
BeginMode3D(camera);
|
BeginMode3D(camera);
|
||||||
|
|
||||||
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED);
|
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED);
|
||||||
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, MAROON);
|
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, MAROON);
|
||||||
DrawGrid(10, 1.0f);
|
DrawGrid(10, 1.0f);
|
||||||
|
|
||||||
EndMode3D();
|
EndMode3D();
|
||||||
|
|
||||||
DrawText("This is a raylib example", 10, 40, 20, DARKGRAY);
|
DrawText("This is a raylib example", 10, 40, 20, DARKGRAY);
|
||||||
|
|
||||||
DrawFPS(10, 10);
|
DrawFPS(10, 10);
|
||||||
|
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
}
|
}
|
||||||
|
|
||||||
// De-Initialization
|
// De-Initialization
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
62
src/Makefile
|
|
@ -147,28 +147,35 @@ endif
|
||||||
|
|
||||||
ifeq ($(PLATFORM),PLATFORM_WEB)
|
ifeq ($(PLATFORM),PLATFORM_WEB)
|
||||||
# Emscripten required variables
|
# Emscripten required variables
|
||||||
EMSDK_PATH ?= C:/emsdk
|
EMSDK_PATH ?= C:/emsdk
|
||||||
EMSCRIPTEN_VERSION ?= 1.38.32
|
EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/fastcomp/emscripten
|
||||||
CLANG_VERSION = e$(EMSCRIPTEN_VERSION)_64bit
|
CLANG_PATH = $(EMSDK_PATH)/fastcomp/bin
|
||||||
PYTHON_VERSION = 2.7.13.1_64bit\python-2.7.13.amd64
|
PYTHON_PATH = $(EMSDK_PATH)/python/2.7.13.1_64bit/python-2.7.13.amd64
|
||||||
NODE_VERSION = 8.9.1_64bit
|
NODE_PATH = $(EMSDK_PATH)/node/12.9.1_64bit/bin
|
||||||
export PATH = $(EMSDK_PATH);$(EMSDK_PATH)\clang\$(CLANG_VERSION);$(EMSDK_PATH)\node\$(NODE_VERSION)\bin;$(EMSDK_PATH)\python\$(PYTHON_VERSION);$(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION);C:\raylib\MinGW\bin:$$(PATH)
|
export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH);C:\raylib\MinGW\bin:$$(PATH)
|
||||||
EMSCRIPTEN = $(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION)
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(PLATFORM),PLATFORM_ANDROID)
|
ifeq ($(PLATFORM),PLATFORM_ANDROID)
|
||||||
# Android architecture: ARM64
|
# Android architecture: ARM64
|
||||||
# Starting at 2019 using ARM64 is mandatory for published apps
|
# Starting at 2019 using ARM64 is mandatory for published apps
|
||||||
ANDROID_ARCH ?= ARM
|
ANDROID_ARCH ?= ARM
|
||||||
ANDROID_API_VERSION = 21
|
ANDROID_API_VERSION = 26
|
||||||
|
|
||||||
# Android required path variables
|
# Android required path variables
|
||||||
# NOTE: Android NDK is just required to generate the standalone toolchain,
|
# NOTE: Android NDK is just required to generate the standalone toolchain,
|
||||||
# in case is not already provided
|
# in case is not already provided
|
||||||
ANDROID_NDK = C:/android-ndk
|
ifeq ($(OS),Windows_NT)
|
||||||
|
ANDROID_NDK = C:/android-ndk
|
||||||
|
else
|
||||||
|
ANDROID_NDK = /usr/lib/android/ndk
|
||||||
|
endif
|
||||||
|
|
||||||
# Android standalone toolchain path
|
# Android standalone toolchain path
|
||||||
ANDROID_TOOLCHAIN = C:/android_toolchain_$(ANDROID_ARCH)_API$(ANDROID_API_VERSION)
|
ifeq ($(OS),Windows_NT)
|
||||||
|
ANDROID_TOOLCHAIN = C:/android_toolchain_$(ANDROID_ARCH)_API$(ANDROID_API_VERSION)
|
||||||
|
else
|
||||||
|
ANDROID_TOOLCHAIN = /usr/lib/android/toolchain_$(ANDROID_ARCH)_API$(ANDROID_API_VERSION)
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(ANDROID_ARCH),ARM)
|
ifeq ($(ANDROID_ARCH),ARM)
|
||||||
ANDROID_ARCH_NAME = armeabi-v7a
|
ANDROID_ARCH_NAME = armeabi-v7a
|
||||||
|
|
@ -176,6 +183,12 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID)
|
||||||
ifeq ($(ANDROID_ARCH),ARM64)
|
ifeq ($(ANDROID_ARCH),ARM64)
|
||||||
ANDROID_ARCH_NAME = arm64-v8a
|
ANDROID_ARCH_NAME = arm64-v8a
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(ANDROID_ARCH),x86)
|
||||||
|
ANDROID_ARCH_NAME = i686
|
||||||
|
endif
|
||||||
|
ifeq ($(ANDROID_ARCH),x86_64)
|
||||||
|
ANDROID_ARCH_NAME = x86_64
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Define raylib source code path
|
# Define raylib source code path
|
||||||
|
|
@ -242,6 +255,14 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID)
|
||||||
CC = $(ANDROID_TOOLCHAIN)/bin/aarch64-linux-android-clang
|
CC = $(ANDROID_TOOLCHAIN)/bin/aarch64-linux-android-clang
|
||||||
AR = $(ANDROID_TOOLCHAIN)/bin/aarch64-linux-android-ar
|
AR = $(ANDROID_TOOLCHAIN)/bin/aarch64-linux-android-ar
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(ANDROID_ARCH),x86)
|
||||||
|
CC = $(ANDROID_TOOLCHAIN)/bin/i686-linux-android$(ANDROID_API_VERSION)-clang
|
||||||
|
AR = $(ANDROID_TOOLCHAIN)/bin/i686-linux-android-ar
|
||||||
|
endif
|
||||||
|
ifeq ($(ANDROID_ARCH),x86_64)
|
||||||
|
CC = $(ANDROID_TOOLCHAIN)/bin/x86_64-linux-android$(ANDROID_API_VERSION)-clang
|
||||||
|
AR = $(ANDROID_TOOLCHAIN)/bin/x86_64-linux-android-ar
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -256,7 +277,13 @@ endif
|
||||||
# -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec
|
# -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec
|
||||||
# -Werror=pointer-arith catch unportable code that does direct arithmetic on void pointers
|
# -Werror=pointer-arith catch unportable code that does direct arithmetic on void pointers
|
||||||
# -fno-strict-aliasing jar_xm.h does shady stuff (breaks strict aliasing)
|
# -fno-strict-aliasing jar_xm.h does shady stuff (breaks strict aliasing)
|
||||||
CFLAGS += -Wall -std=c99 -D_DEFAULT_SOURCE -Wno-missing-braces -Werror=pointer-arith -fno-strict-aliasing
|
CFLAGS += -Wall -D_DEFAULT_SOURCE -Wno-missing-braces -Werror=pointer-arith -fno-strict-aliasing
|
||||||
|
|
||||||
|
ifeq ($(PLATFORM), PLATFORM_WEB)
|
||||||
|
CFLAGS += -std=gnu99
|
||||||
|
else
|
||||||
|
CFLAGS += -std=c99
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(PLATFORM_OS),LINUX)
|
ifeq ($(PLATFORM_OS),LINUX)
|
||||||
CFLAGS += -fPIC
|
CFLAGS += -fPIC
|
||||||
|
|
@ -305,6 +332,12 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID)
|
||||||
ifeq ($(ANDROID_ARCH),ARM64)
|
ifeq ($(ANDROID_ARCH),ARM64)
|
||||||
CFLAGS += -target aarch64 -mfix-cortex-a53-835769
|
CFLAGS += -target aarch64 -mfix-cortex-a53-835769
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(ANDROID_ARCH), x86)
|
||||||
|
CFLAGS += -march=i686
|
||||||
|
endif
|
||||||
|
ifeq ($(ANDROID_ARCH), x86_64)
|
||||||
|
CFLAGS += -march=x86-64
|
||||||
|
endif
|
||||||
# Compilation functions attributes options
|
# Compilation functions attributes options
|
||||||
CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIE -fPIC
|
CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIE -fPIC
|
||||||
# Compiler options for the linker
|
# Compiler options for the linker
|
||||||
|
|
@ -356,11 +389,12 @@ ifeq ($(PLATFORM),PLATFORM_RPI)
|
||||||
INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include/interface/vcos/pthreads
|
INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include/interface/vcos/pthreads
|
||||||
endif
|
endif
|
||||||
ifeq ($(PLATFORM),PLATFORM_ANDROID)
|
ifeq ($(PLATFORM),PLATFORM_ANDROID)
|
||||||
|
NATIVE_APP_GLUE = $(RAYLIB_RELEASE_PATH)/external/android/native_app_glue
|
||||||
|
#NATIVE_APP_GLUE = $(ANDROID_NDK)/sources/android/native_app_glue
|
||||||
# Android required libraries
|
# Android required libraries
|
||||||
INCLUDE_PATHS += -I$(ANDROID_TOOLCHAIN)/sysroot/usr/include
|
INCLUDE_PATHS += -I$(ANDROID_TOOLCHAIN)/sysroot/usr/include
|
||||||
# Include android_native_app_glue.h
|
# Include android_native_app_glue.h
|
||||||
INCLUDE_PATHS += -Iexternal/android/native_app_glue
|
INCLUDE_PATHS += -I$(NATIVE_APP_GLUE)
|
||||||
#INCLUDE_PATHS += -I$(ANDROID_NDK)/sources/android/native_app_glue
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Define linker options
|
# Define linker options
|
||||||
|
|
@ -635,6 +669,6 @@ else
|
||||||
rm -fv *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so*
|
rm -fv *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so*
|
||||||
endif
|
endif
|
||||||
ifeq ($(PLATFORM),PLATFORM_ANDROID)
|
ifeq ($(PLATFORM),PLATFORM_ANDROID)
|
||||||
rm -rf $(ANDROID_TOOLCHAIN)
|
rm -rf $(ANDROID_TOOLCHAIN) $(NATIVE_APP_GLUE)/android_native_app_glue.o
|
||||||
endif
|
endif
|
||||||
@echo "removed all generated files!"
|
@echo "removed all generated files!"
|
||||||
|
|
|
||||||
74
src/camera.h
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
* #define CAMERA_IMPLEMENTATION
|
* #define CAMERA_IMPLEMENTATION
|
||||||
* Generates the implementation of the library into the included file.
|
* Generates the implementation of the library into the included file.
|
||||||
* If not defined, the library is in header only mode and can be included in other headers
|
* If not defined, the library is in header only mode and can be included in other headers
|
||||||
* or source files without problems. But only ONE file should hold the implementation.
|
* or source files without problems. But only ONE file should hold the implementation.
|
||||||
*
|
*
|
||||||
* #define CAMERA_STANDALONE
|
* #define CAMERA_STANDALONE
|
||||||
|
|
@ -77,7 +77,7 @@
|
||||||
} Camera3D;
|
} Camera3D;
|
||||||
|
|
||||||
typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D
|
typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D
|
||||||
|
|
||||||
// Camera system modes
|
// Camera system modes
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CAMERA_CUSTOM = 0,
|
CAMERA_CUSTOM = 0,
|
||||||
|
|
@ -113,8 +113,8 @@ void UpdateCamera(Camera *camera); // Update camera pos
|
||||||
void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera)
|
void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera)
|
||||||
void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera)
|
void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera)
|
||||||
void SetCameraSmoothZoomControl(int szoomKey); // Set camera smooth zoom key to combine with mouse (free camera)
|
void SetCameraSmoothZoomControl(int szoomKey); // Set camera smooth zoom key to combine with mouse (free camera)
|
||||||
void SetCameraMoveControls(int frontKey, int backKey,
|
void SetCameraMoveControls(int frontKey, int backKey,
|
||||||
int rightKey, int leftKey,
|
int rightKey, int leftKey,
|
||||||
int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras)
|
int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -188,21 +188,21 @@ void SetCameraMoveControls(int frontKey, int backKey,
|
||||||
// Types and Structures Definition
|
// Types and Structures Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Camera move modes (first person and third person cameras)
|
// Camera move modes (first person and third person cameras)
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MOVE_FRONT = 0,
|
MOVE_FRONT = 0,
|
||||||
MOVE_BACK,
|
MOVE_BACK,
|
||||||
MOVE_RIGHT,
|
MOVE_RIGHT,
|
||||||
MOVE_LEFT,
|
MOVE_LEFT,
|
||||||
MOVE_UP,
|
MOVE_UP,
|
||||||
MOVE_DOWN
|
MOVE_DOWN
|
||||||
} CameraMove;
|
} CameraMove;
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Global Variables Definition
|
// Global Variables Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
static Vector2 cameraAngle = { 0.0f, 0.0f }; // Camera angle in plane XZ
|
static Vector2 cameraAngle = { 0.0f, 0.0f }; // Camera angle in plane XZ
|
||||||
static float cameraTargetDistance = 0.0f; // Camera distance from position to target
|
static float cameraTargetDistance = 0.0f; // Camera distance from position to target
|
||||||
static float playerEyesPosition = 1.85f; // Default player eyes position from ground (in meters)
|
static float playerEyesPosition = 1.85f; // Default player eyes position from ground (in meters)
|
||||||
|
|
||||||
static int cameraMoveControl[6] = { 'W', 'S', 'D', 'A', 'E', 'Q' };
|
static int cameraMoveControl[6] = { 'W', 'S', 'D', 'A', 'E', 'Q' };
|
||||||
static int cameraPanControlKey = 2; // raylib: MOUSE_MIDDLE_BUTTON
|
static int cameraPanControlKey = 2; // raylib: MOUSE_MIDDLE_BUTTON
|
||||||
|
|
@ -236,21 +236,21 @@ void SetCameraMode(Camera camera, int mode)
|
||||||
{
|
{
|
||||||
Vector3 v1 = camera.position;
|
Vector3 v1 = camera.position;
|
||||||
Vector3 v2 = camera.target;
|
Vector3 v2 = camera.target;
|
||||||
|
|
||||||
float dx = v2.x - v1.x;
|
float dx = v2.x - v1.x;
|
||||||
float dy = v2.y - v1.y;
|
float dy = v2.y - v1.y;
|
||||||
float dz = v2.z - v1.z;
|
float dz = v2.z - v1.z;
|
||||||
|
|
||||||
cameraTargetDistance = sqrtf(dx*dx + dy*dy + dz*dz);
|
cameraTargetDistance = sqrtf(dx*dx + dy*dy + dz*dz);
|
||||||
|
|
||||||
Vector2 distance = { 0.0f, 0.0f };
|
Vector2 distance = { 0.0f, 0.0f };
|
||||||
distance.x = sqrtf(dx*dx + dz*dz);
|
distance.x = sqrtf(dx*dx + dz*dz);
|
||||||
distance.y = sqrtf(dx*dx + dy*dy);
|
distance.y = sqrtf(dx*dx + dy*dy);
|
||||||
|
|
||||||
// Camera angle calculation
|
// Camera angle calculation
|
||||||
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)
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -272,24 +272,24 @@ void UpdateCamera(Camera *camera)
|
||||||
static Vector2 previousMousePosition = { 0.0f, 0.0f };
|
static Vector2 previousMousePosition = { 0.0f, 0.0f };
|
||||||
|
|
||||||
// TODO: Compute cameraTargetDistance and cameraAngle here
|
// TODO: Compute cameraTargetDistance and cameraAngle here
|
||||||
|
|
||||||
// Mouse movement detection
|
// Mouse movement detection
|
||||||
Vector2 mousePositionDelta = { 0.0f, 0.0f };
|
Vector2 mousePositionDelta = { 0.0f, 0.0f };
|
||||||
Vector2 mousePosition = GetMousePosition();
|
Vector2 mousePosition = GetMousePosition();
|
||||||
int mouseWheelMove = GetMouseWheelMove();
|
int mouseWheelMove = GetMouseWheelMove();
|
||||||
|
|
||||||
// Keys input detection
|
// Keys input detection
|
||||||
bool panKey = IsMouseButtonDown(cameraPanControlKey);
|
bool panKey = IsMouseButtonDown(cameraPanControlKey);
|
||||||
bool altKey = IsKeyDown(cameraAltControlKey);
|
bool altKey = IsKeyDown(cameraAltControlKey);
|
||||||
bool szoomKey = IsKeyDown(cameraSmoothZoomControlKey);
|
bool szoomKey = IsKeyDown(cameraSmoothZoomControlKey);
|
||||||
|
|
||||||
bool direction[6] = { IsKeyDown(cameraMoveControl[MOVE_FRONT]),
|
bool direction[6] = { IsKeyDown(cameraMoveControl[MOVE_FRONT]),
|
||||||
IsKeyDown(cameraMoveControl[MOVE_BACK]),
|
IsKeyDown(cameraMoveControl[MOVE_BACK]),
|
||||||
IsKeyDown(cameraMoveControl[MOVE_RIGHT]),
|
IsKeyDown(cameraMoveControl[MOVE_RIGHT]),
|
||||||
IsKeyDown(cameraMoveControl[MOVE_LEFT]),
|
IsKeyDown(cameraMoveControl[MOVE_LEFT]),
|
||||||
IsKeyDown(cameraMoveControl[MOVE_UP]),
|
IsKeyDown(cameraMoveControl[MOVE_UP]),
|
||||||
IsKeyDown(cameraMoveControl[MOVE_DOWN]) };
|
IsKeyDown(cameraMoveControl[MOVE_DOWN]) };
|
||||||
|
|
||||||
// TODO: Consider touch inputs for camera
|
// TODO: Consider touch inputs for camera
|
||||||
|
|
||||||
if (cameraMode != CAMERA_CUSTOM)
|
if (cameraMode != CAMERA_CUSTOM)
|
||||||
|
|
@ -384,7 +384,7 @@ void UpdateCamera(Camera *camera)
|
||||||
camera->target.z += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(cameraAngle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(cameraAngle.x)*sinf(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER);
|
camera->target.z += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(cameraAngle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(cameraAngle.x)*sinf(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update camera position with changes
|
// Update camera position with changes
|
||||||
camera->position.x = sinf(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.x;
|
camera->position.x = sinf(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.x;
|
||||||
camera->position.y = ((cameraAngle.y <= 0.0f)? 1 : -1)*sinf(cameraAngle.y)*cameraTargetDistance*sinf(cameraAngle.y) + camera->target.y;
|
camera->position.y = ((cameraAngle.y <= 0.0f)? 1 : -1)*sinf(cameraAngle.y)*cameraTargetDistance*sinf(cameraAngle.y) + camera->target.y;
|
||||||
|
|
@ -395,15 +395,15 @@ void UpdateCamera(Camera *camera)
|
||||||
{
|
{
|
||||||
cameraAngle.x += CAMERA_ORBITAL_SPEED; // Camera orbit angle
|
cameraAngle.x += CAMERA_ORBITAL_SPEED; // Camera orbit angle
|
||||||
cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom
|
cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom
|
||||||
|
|
||||||
// Camera distance clamp
|
// Camera distance clamp
|
||||||
if (cameraTargetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
|
if (cameraTargetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
|
||||||
|
|
||||||
// Update camera position with changes
|
// Update camera position with changes
|
||||||
camera->position.x = sinf(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.x;
|
camera->position.x = sinf(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.x;
|
||||||
camera->position.y = ((cameraAngle.y <= 0.0f)? 1 : -1)*sinf(cameraAngle.y)*cameraTargetDistance*sinf(cameraAngle.y) + camera->target.y;
|
camera->position.y = ((cameraAngle.y <= 0.0f)? 1 : -1)*sinf(cameraAngle.y)*cameraTargetDistance*sinf(cameraAngle.y) + camera->target.y;
|
||||||
camera->position.z = cosf(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.z;
|
camera->position.z = cosf(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.z;
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case CAMERA_FIRST_PERSON:
|
case CAMERA_FIRST_PERSON:
|
||||||
{
|
{
|
||||||
|
|
@ -411,11 +411,11 @@ void UpdateCamera(Camera *camera)
|
||||||
sinf(cameraAngle.x)*direction[MOVE_FRONT] -
|
sinf(cameraAngle.x)*direction[MOVE_FRONT] -
|
||||||
cosf(cameraAngle.x)*direction[MOVE_LEFT] +
|
cosf(cameraAngle.x)*direction[MOVE_LEFT] +
|
||||||
cosf(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
|
cosf(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
|
||||||
|
|
||||||
camera->position.y += (sinf(cameraAngle.y)*direction[MOVE_FRONT] -
|
camera->position.y += (sinf(cameraAngle.y)*direction[MOVE_FRONT] -
|
||||||
sinf(cameraAngle.y)*direction[MOVE_BACK] +
|
sinf(cameraAngle.y)*direction[MOVE_BACK] +
|
||||||
1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY;
|
1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY;
|
||||||
|
|
||||||
camera->position.z += (cosf(cameraAngle.x)*direction[MOVE_BACK] -
|
camera->position.z += (cosf(cameraAngle.x)*direction[MOVE_BACK] -
|
||||||
cosf(cameraAngle.x)*direction[MOVE_FRONT] +
|
cosf(cameraAngle.x)*direction[MOVE_FRONT] +
|
||||||
sinf(cameraAngle.x)*direction[MOVE_LEFT] -
|
sinf(cameraAngle.x)*direction[MOVE_LEFT] -
|
||||||
|
|
@ -424,11 +424,11 @@ void UpdateCamera(Camera *camera)
|
||||||
bool isMoving = false; // Required for swinging
|
bool isMoving = false; // Required for swinging
|
||||||
|
|
||||||
for (int i = 0; i < 6; i++) if (direction[i]) { isMoving = true; break; }
|
for (int i = 0; i < 6; i++) if (direction[i]) { isMoving = true; break; }
|
||||||
|
|
||||||
// Camera orientation calculation
|
// Camera orientation calculation
|
||||||
cameraAngle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
|
cameraAngle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
|
||||||
cameraAngle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
|
cameraAngle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
|
||||||
|
|
||||||
// Angle clamp
|
// Angle clamp
|
||||||
if (cameraAngle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
|
if (cameraAngle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
|
||||||
else if (cameraAngle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD;
|
else if (cameraAngle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD;
|
||||||
|
|
@ -437,7 +437,7 @@ void UpdateCamera(Camera *camera)
|
||||||
camera->target.x = camera->position.x - sinf(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
|
camera->target.x = camera->position.x - sinf(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
|
||||||
camera->target.y = camera->position.y + sinf(cameraAngle.y)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
|
camera->target.y = camera->position.y + sinf(cameraAngle.y)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
|
||||||
camera->target.z = camera->position.z - cosf(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
|
camera->target.z = camera->position.z - cosf(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
|
||||||
|
|
||||||
if (isMoving) swingCounter++;
|
if (isMoving) swingCounter++;
|
||||||
|
|
||||||
// Camera position update
|
// Camera position update
|
||||||
|
|
@ -446,8 +446,8 @@ void UpdateCamera(Camera *camera)
|
||||||
|
|
||||||
camera->up.x = sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
|
camera->up.x = sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
|
||||||
camera->up.z = -sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
|
camera->up.z = -sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
|
||||||
|
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case CAMERA_THIRD_PERSON:
|
case CAMERA_THIRD_PERSON:
|
||||||
{
|
{
|
||||||
|
|
@ -455,11 +455,11 @@ void UpdateCamera(Camera *camera)
|
||||||
sinf(cameraAngle.x)*direction[MOVE_FRONT] -
|
sinf(cameraAngle.x)*direction[MOVE_FRONT] -
|
||||||
cosf(cameraAngle.x)*direction[MOVE_LEFT] +
|
cosf(cameraAngle.x)*direction[MOVE_LEFT] +
|
||||||
cosf(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
|
cosf(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
|
||||||
|
|
||||||
camera->position.y += (sinf(cameraAngle.y)*direction[MOVE_FRONT] -
|
camera->position.y += (sinf(cameraAngle.y)*direction[MOVE_FRONT] -
|
||||||
sinf(cameraAngle.y)*direction[MOVE_BACK] +
|
sinf(cameraAngle.y)*direction[MOVE_BACK] +
|
||||||
1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY;
|
1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY;
|
||||||
|
|
||||||
camera->position.z += (cosf(cameraAngle.x)*direction[MOVE_BACK] -
|
camera->position.z += (cosf(cameraAngle.x)*direction[MOVE_BACK] -
|
||||||
cosf(cameraAngle.x)*direction[MOVE_FRONT] +
|
cosf(cameraAngle.x)*direction[MOVE_FRONT] +
|
||||||
sinf(cameraAngle.x)*direction[MOVE_LEFT] -
|
sinf(cameraAngle.x)*direction[MOVE_LEFT] -
|
||||||
|
|
@ -468,7 +468,7 @@ void UpdateCamera(Camera *camera)
|
||||||
// Camera orientation calculation
|
// Camera orientation calculation
|
||||||
cameraAngle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
|
cameraAngle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
|
||||||
cameraAngle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
|
cameraAngle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
|
||||||
|
|
||||||
// Angle clamp
|
// Angle clamp
|
||||||
if (cameraAngle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD;
|
if (cameraAngle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD;
|
||||||
else if (cameraAngle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD;
|
else if (cameraAngle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD;
|
||||||
|
|
@ -487,7 +487,7 @@ void UpdateCamera(Camera *camera)
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set camera pan key to combine with mouse movement (free camera)
|
// Set camera pan key to combine with mouse movement (free camera)
|
||||||
|
|
|
||||||
17
src/config.h
|
|
@ -25,7 +25,7 @@
|
||||||
*
|
*
|
||||||
**********************************************************************************************/
|
**********************************************************************************************/
|
||||||
|
|
||||||
#define RAYLIB_VERSION "2.5"
|
#define RAYLIB_VERSION "2.6-dev"
|
||||||
|
|
||||||
// Edit to control what features Makefile'd raylib is compiled with
|
// Edit to control what features Makefile'd raylib is compiled with
|
||||||
#if defined(RAYLIB_CMAKE)
|
#if defined(RAYLIB_CMAKE)
|
||||||
|
|
@ -44,6 +44,8 @@
|
||||||
#define SUPPORT_MOUSE_GESTURES 1
|
#define SUPPORT_MOUSE_GESTURES 1
|
||||||
// Reconfigure standard input to receive key inputs, works with SSH connection.
|
// Reconfigure standard input to receive key inputs, works with SSH connection.
|
||||||
#define SUPPORT_SSH_KEYBOARD_RPI 1
|
#define SUPPORT_SSH_KEYBOARD_RPI 1
|
||||||
|
// Draw a mouse reference on screen (square cursor box)
|
||||||
|
#define SUPPORT_MOUSE_CURSOR_RPI 1
|
||||||
// Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used
|
// Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used
|
||||||
//#define SUPPORT_BUSY_WAIT_LOOP 1
|
//#define SUPPORT_BUSY_WAIT_LOOP 1
|
||||||
// Wait for events passively (sleeping while no events) instead of polling them actively every frame
|
// Wait for events passively (sleeping while no events) instead of polling them actively every frame
|
||||||
|
|
@ -54,7 +56,8 @@
|
||||||
#define SUPPORT_GIF_RECORDING 1
|
#define SUPPORT_GIF_RECORDING 1
|
||||||
// Allow scale all the drawn content to match the high-DPI equivalent size (only PLATFORM_DESKTOP)
|
// Allow scale all the drawn content to match the high-DPI equivalent size (only PLATFORM_DESKTOP)
|
||||||
//#define SUPPORT_HIGH_DPI 1
|
//#define SUPPORT_HIGH_DPI 1
|
||||||
|
// Support CompressData() and DecompressData() functions
|
||||||
|
#define SUPPORT_COMPRESSION_API 1
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: rlgl - Configuration Flags
|
// Module: rlgl - Configuration Flags
|
||||||
|
|
@ -83,10 +86,10 @@
|
||||||
//#define SUPPORT_FILEFORMAT_JPG 1
|
//#define SUPPORT_FILEFORMAT_JPG 1
|
||||||
//#define SUPPORT_FILEFORMAT_GIF 1
|
//#define SUPPORT_FILEFORMAT_GIF 1
|
||||||
//#define SUPPORT_FILEFORMAT_PSD 1
|
//#define SUPPORT_FILEFORMAT_PSD 1
|
||||||
#define SUPPORT_FILEFORMAT_DDS 1
|
//#define SUPPORT_FILEFORMAT_DDS 1
|
||||||
#define SUPPORT_FILEFORMAT_HDR 1
|
#define SUPPORT_FILEFORMAT_HDR 1
|
||||||
#define SUPPORT_FILEFORMAT_KTX 1
|
//#define SUPPORT_FILEFORMAT_KTX 1
|
||||||
#define SUPPORT_FILEFORMAT_ASTC 1
|
//#define SUPPORT_FILEFORMAT_ASTC 1
|
||||||
//#define SUPPORT_FILEFORMAT_PKM 1
|
//#define SUPPORT_FILEFORMAT_PKM 1
|
||||||
//#define SUPPORT_FILEFORMAT_PVR 1
|
//#define SUPPORT_FILEFORMAT_PVR 1
|
||||||
|
|
||||||
|
|
@ -131,8 +134,8 @@
|
||||||
#define SUPPORT_FILEFORMAT_OGG 1
|
#define SUPPORT_FILEFORMAT_OGG 1
|
||||||
#define SUPPORT_FILEFORMAT_XM 1
|
#define SUPPORT_FILEFORMAT_XM 1
|
||||||
#define SUPPORT_FILEFORMAT_MOD 1
|
#define SUPPORT_FILEFORMAT_MOD 1
|
||||||
//#define SUPPORT_FILEFORMAT_FLAC 1
|
#define SUPPORT_FILEFORMAT_FLAC 1
|
||||||
#define SUPPORT_FILEFORMAT_MP3 1
|
#define SUPPORT_FILEFORMAT_MP3 1
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@
|
||||||
#cmakedefine SUPPORT_GIF_RECORDING 1
|
#cmakedefine SUPPORT_GIF_RECORDING 1
|
||||||
// Support high DPI displays
|
// Support high DPI displays
|
||||||
#cmakedefine SUPPORT_HIGH_DPI 1
|
#cmakedefine SUPPORT_HIGH_DPI 1
|
||||||
|
// Support CompressData() and DecompressData() functions
|
||||||
|
#cmakedefine SUPPORT_COMPRESSION_API 1
|
||||||
|
|
||||||
// rlgl.h
|
// rlgl.h
|
||||||
// Support VR simulation functionality (stereo rendering)
|
// Support VR simulation functionality (stereo rendering)
|
||||||
|
|
|
||||||
396
src/core.c
|
|
@ -8,7 +8,7 @@
|
||||||
* - PLATFORM_DESKTOP: FreeBSD, OpenBSD, NetBSD, DragonFly (X11 desktop)
|
* - PLATFORM_DESKTOP: FreeBSD, OpenBSD, NetBSD, DragonFly (X11 desktop)
|
||||||
* - PLATFORM_DESKTOP: OSX/macOS
|
* - PLATFORM_DESKTOP: OSX/macOS
|
||||||
* - PLATFORM_ANDROID: Android 4.0 (ARM, ARM64)
|
* - PLATFORM_ANDROID: Android 4.0 (ARM, ARM64)
|
||||||
* - PLATFORM_RPI: Raspberry Pi 0,1,2,3 (Raspbian)
|
* - PLATFORM_RPI: Raspberry Pi 0,1,2,3,4 (Raspbian)
|
||||||
* - PLATFORM_WEB: HTML5 with asm.js (Chrome, Firefox)
|
* - PLATFORM_WEB: HTML5 with asm.js (Chrome, Firefox)
|
||||||
* - PLATFORM_UWP: Windows 10 App, Windows Phone, Xbox One
|
* - PLATFORM_UWP: Windows 10 App, Windows Phone, Xbox One
|
||||||
*
|
*
|
||||||
|
|
@ -55,6 +55,9 @@
|
||||||
* WARNING: Reconfiguring standard input could lead to undesired effects, like breaking other running processes or
|
* WARNING: Reconfiguring standard input could lead to undesired effects, like breaking other running processes or
|
||||||
* blocking the device is not restored properly. Use with care.
|
* blocking the device is not restored properly. Use with care.
|
||||||
*
|
*
|
||||||
|
* #define SUPPORT_MOUSE_CURSOR_RPI (Raspberry Pi only)
|
||||||
|
* Draw a mouse reference on screen (square cursor box)
|
||||||
|
*
|
||||||
* #define SUPPORT_BUSY_WAIT_LOOP
|
* #define SUPPORT_BUSY_WAIT_LOOP
|
||||||
* Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used
|
* Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used
|
||||||
*
|
*
|
||||||
|
|
@ -71,6 +74,11 @@
|
||||||
* Allow scale all the drawn content to match the high-DPI equivalent size (only PLATFORM_DESKTOP)
|
* Allow scale all the drawn content to match the high-DPI equivalent size (only PLATFORM_DESKTOP)
|
||||||
* NOTE: This flag is forced on macOS, since most displays are high-DPI
|
* NOTE: This flag is forced on macOS, since most displays are high-DPI
|
||||||
*
|
*
|
||||||
|
* #define SUPPORT_COMPRESSION_API
|
||||||
|
* Support CompressData() and DecompressData() functions, those functions use zlib implementation
|
||||||
|
* provided by stb_image and stb_image_write libraries, so, those libraries must be enabled on textures module
|
||||||
|
* for linkage
|
||||||
|
*
|
||||||
* DEPENDENCIES:
|
* DEPENDENCIES:
|
||||||
* rglfw - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX. FreeBSD, OpenBSD, NetBSD, DragonFly)
|
* rglfw - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX. FreeBSD, OpenBSD, NetBSD, DragonFly)
|
||||||
* raymath - 3D math functionality (Vector2, Vector3, Matrix, Quaternion)
|
* raymath - 3D math functionality (Vector2, Vector3, Matrix, Quaternion)
|
||||||
|
|
@ -105,7 +113,7 @@
|
||||||
#if !defined(EXTERNAL_CONFIG_FLAGS)
|
#if !defined(EXTERNAL_CONFIG_FLAGS)
|
||||||
#include "config.h" // Defines module configuration flags
|
#include "config.h" // Defines module configuration flags
|
||||||
#else
|
#else
|
||||||
#define RAYLIB_VERSION "2.5"
|
#define RAYLIB_VERSION "2.6-dev"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_C_SOURCE < 199309L
|
#if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_C_SOURCE < 199309L
|
||||||
|
|
@ -249,6 +257,12 @@
|
||||||
#include <emscripten/html5.h> // Emscripten HTML5 library
|
#include <emscripten/html5.h> // Emscripten HTML5 library
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(SUPPORT_COMPRESSION_API)
|
||||||
|
// NOTE: Those declarations require stb_image and stb_image_write definitions, included in textures module
|
||||||
|
unsigned char *stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality);
|
||||||
|
char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen);
|
||||||
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Defines and Macros
|
// Defines and Macros
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -423,7 +437,6 @@ static double targetTime = 0.0; // Desired time for one frame, if 0
|
||||||
// Config internal variables
|
// Config internal variables
|
||||||
//-----------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------
|
||||||
static unsigned int configFlags = 0; // Configuration flags (bit based)
|
static unsigned int configFlags = 0; // Configuration flags (bit based)
|
||||||
static bool showLogo = false; // Track if showing logo at init is enabled
|
|
||||||
|
|
||||||
static char **dropFilesPath; // Store dropped files paths as strings
|
static char **dropFilesPath; // Store dropped files paths as strings
|
||||||
static int dropFilesCount = 0; // Count dropped files strings
|
static int dropFilesCount = 0; // Count dropped files strings
|
||||||
|
|
@ -466,8 +479,6 @@ static int GetGamepadButton(int button); // Get gamepad button ge
|
||||||
static int GetGamepadAxis(int axis); // Get gamepad axis generic to all platforms
|
static int GetGamepadAxis(int axis); // Get gamepad axis generic to all platforms
|
||||||
static void PollInputEvents(void); // Register user events
|
static void PollInputEvents(void); // Register user events
|
||||||
|
|
||||||
static void LogoAnimation(void); // Plays raylib logo appearing animation
|
|
||||||
|
|
||||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
||||||
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
|
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
|
||||||
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
|
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
|
||||||
|
|
@ -568,7 +579,7 @@ static void InitTerminal(void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE);
|
ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -579,7 +590,7 @@ static void InitTerminal(void)
|
||||||
static void RestoreTerminal(void)
|
static void RestoreTerminal(void)
|
||||||
{
|
{
|
||||||
TraceLog(LOG_INFO, "Restore Terminal ...");
|
TraceLog(LOG_INFO, "Restore Terminal ...");
|
||||||
|
|
||||||
// Reset to default keyboard settings
|
// Reset to default keyboard settings
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &defaultKeyboardSettings);
|
tcsetattr(STDIN_FILENO, TCSANOW, &defaultKeyboardSettings);
|
||||||
|
|
||||||
|
|
@ -697,13 +708,6 @@ void InitWindow(int width, int height, const char *title)
|
||||||
|
|
||||||
mousePosition.x = (float)screenWidth/2.0f;
|
mousePosition.x = (float)screenWidth/2.0f;
|
||||||
mousePosition.y = (float)screenHeight/2.0f;
|
mousePosition.y = (float)screenHeight/2.0f;
|
||||||
|
|
||||||
// raylib logo appearing animation (if enabled)
|
|
||||||
if (showLogo)
|
|
||||||
{
|
|
||||||
SetTargetFPS(60);
|
|
||||||
LogoAnimation();
|
|
||||||
}
|
|
||||||
#endif // PLATFORM_ANDROID
|
#endif // PLATFORM_ANDROID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -770,7 +774,7 @@ void CloseWindow(void)
|
||||||
pthread_join(eventWorkers[i].threadId, NULL);
|
pthread_join(eventWorkers[i].threadId, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gamepadThreadId) pthread_join(gamepadThreadId, NULL);
|
if (gamepadThreadId) pthread_join(gamepadThreadId, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -1060,6 +1064,17 @@ int GetMonitorPhysicalHeight(int monitor)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get window position XY on monitor
|
||||||
|
Vector2 GetWindowPosition(void)
|
||||||
|
{
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
#if defined(PLATFORM_DESKTOP)
|
||||||
|
glfwGetWindowPos(window, &x, &y);
|
||||||
|
#endif
|
||||||
|
return (Vector2){ (float)x, (float)y };
|
||||||
|
}
|
||||||
|
|
||||||
// Get the human-readable, UTF-8 encoded name of the primary monitor
|
// Get the human-readable, UTF-8 encoded name of the primary monitor
|
||||||
const char *GetMonitorName(int monitor)
|
const char *GetMonitorName(int monitor)
|
||||||
{
|
{
|
||||||
|
|
@ -1187,6 +1202,12 @@ void BeginDrawing(void)
|
||||||
// End canvas drawing and swap buffers (double buffering)
|
// End canvas drawing and swap buffers (double buffering)
|
||||||
void EndDrawing(void)
|
void EndDrawing(void)
|
||||||
{
|
{
|
||||||
|
#if defined(PLATFORM_RPI) && defined(SUPPORT_MOUSE_CURSOR_RPI)
|
||||||
|
// On RPI native mode we have no system mouse cursor, so,
|
||||||
|
// we draw a small rectangle for user reference
|
||||||
|
DrawRectangle(mousePosition.x, mousePosition.y, 3, 3, MAROON);
|
||||||
|
#endif
|
||||||
|
|
||||||
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
|
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
|
||||||
|
|
||||||
#if defined(SUPPORT_GIF_RECORDING)
|
#if defined(SUPPORT_GIF_RECORDING)
|
||||||
|
|
@ -1249,17 +1270,12 @@ void BeginMode2D(Camera2D camera)
|
||||||
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
|
rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2)
|
||||||
|
|
||||||
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
|
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
|
||||||
rlMultMatrixf(MatrixToFloat(screenScaling)); // Apply screen scaling if required
|
|
||||||
|
|
||||||
// Camera rotation and scaling is always relative to target
|
// Apply screen scaling if required
|
||||||
Matrix matOrigin = MatrixTranslate(-camera.target.x, -camera.target.y, 0.0f);
|
rlMultMatrixf(MatrixToFloat(screenScaling));
|
||||||
Matrix matRotation = MatrixRotate((Vector3){ 0.0f, 0.0f, 1.0f }, camera.rotation*DEG2RAD);
|
|
||||||
Matrix matScale = MatrixScale(camera.zoom, camera.zoom, 1.0f);
|
|
||||||
Matrix matTranslation = MatrixTranslate(camera.offset.x + camera.target.x, camera.offset.y + camera.target.y, 0.0f);
|
|
||||||
|
|
||||||
Matrix matTransform = MatrixMultiply(MatrixMultiply(matOrigin, MatrixMultiply(matScale, matRotation)), matTranslation);
|
// Apply 2d camera transformation to modelview
|
||||||
|
rlMultMatrixf(MatrixToFloat(GetCameraMatrix2D(camera)));
|
||||||
rlMultMatrixf(MatrixToFloat(matTransform)); // Apply transformation to modelview
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ends 2D mode with custom camera
|
// Ends 2D mode with custom camera
|
||||||
|
|
@ -1370,6 +1386,23 @@ void EndTextureMode(void)
|
||||||
currentHeight = GetScreenHeight();
|
currentHeight = GetScreenHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Begin scissor mode (define screen area for following drawing)
|
||||||
|
// NOTE: Scissor rec refers to bottom-left corner, we change it to upper-left
|
||||||
|
void BeginScissorMode(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
rlglDraw(); // Force drawing elements
|
||||||
|
|
||||||
|
rlEnableScissorTest();
|
||||||
|
rlScissor(x, GetScreenHeight() - (y + height), width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// End scissor mode
|
||||||
|
void EndScissorMode(void)
|
||||||
|
{
|
||||||
|
rlglDraw(); // Force drawing elements
|
||||||
|
rlDisableScissorTest();
|
||||||
|
}
|
||||||
|
|
||||||
// Returns a ray trace from mouse position
|
// Returns a ray trace from mouse position
|
||||||
Ray GetMouseRay(Vector2 mousePosition, Camera camera)
|
Ray GetMouseRay(Vector2 mousePosition, Camera camera)
|
||||||
{
|
{
|
||||||
|
|
@ -1425,6 +1458,40 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera)
|
||||||
return ray;
|
return ray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get transform matrix for camera
|
||||||
|
Matrix GetCameraMatrix(Camera camera)
|
||||||
|
{
|
||||||
|
return MatrixLookAt(camera.position, camera.target, camera.up);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns camera 2d transform matrix
|
||||||
|
Matrix GetCameraMatrix2D(Camera2D camera)
|
||||||
|
{
|
||||||
|
Matrix matTransform = { 0 };
|
||||||
|
// The camera in world-space is set by
|
||||||
|
// 1. Move it to target
|
||||||
|
// 2. Rotate by -rotation and scale by (1/zoom)
|
||||||
|
// When setting higher scale, it's more intuitive for the world to become bigger (= camera become smaller),
|
||||||
|
// not for the camera getting bigger, hence the invert. Same deal with rotation.
|
||||||
|
// 3. Move it by (-offset);
|
||||||
|
// Offset defines target transform relative to screen, but since we're effectively "moving" screen (camera)
|
||||||
|
// we need to do it into opposite direction (inverse transform)
|
||||||
|
|
||||||
|
// Having camera transform in world-space, inverse of it gives the modelview transform.
|
||||||
|
// Since (A*B*C)' = C'*B'*A', the modelview is
|
||||||
|
// 1. Move to offset
|
||||||
|
// 2. Rotate and Scale
|
||||||
|
// 3. Move by -target
|
||||||
|
Matrix matOrigin = MatrixTranslate(-camera.target.x, -camera.target.y, 0.0f);
|
||||||
|
Matrix matRotation = MatrixRotate((Vector3){ 0.0f, 0.0f, 1.0f }, camera.rotation*DEG2RAD);
|
||||||
|
Matrix matScale = MatrixScale(camera.zoom, camera.zoom, 1.0f);
|
||||||
|
Matrix matTranslation = MatrixTranslate(camera.offset.x, camera.offset.y, 0.0f);
|
||||||
|
|
||||||
|
matTransform = MatrixMultiply(MatrixMultiply(matOrigin, MatrixMultiply(matScale, matRotation)), matTranslation);
|
||||||
|
|
||||||
|
return matTransform;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the screen space position from a 3d world space position
|
// Returns the screen space position from a 3d world space position
|
||||||
Vector2 GetWorldToScreen(Vector3 position, Camera camera)
|
Vector2 GetWorldToScreen(Vector3 position, Camera camera)
|
||||||
{
|
{
|
||||||
|
|
@ -1467,10 +1534,22 @@ Vector2 GetWorldToScreen(Vector3 position, Camera camera)
|
||||||
return screenPosition;
|
return screenPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get transform matrix for camera
|
// Returns the screen space position for a 2d camera world space position
|
||||||
Matrix GetCameraMatrix(Camera camera)
|
Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera)
|
||||||
{
|
{
|
||||||
return MatrixLookAt(camera.position, camera.target, camera.up);
|
Matrix matCamera = GetCameraMatrix2D(camera);
|
||||||
|
Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, matCamera);
|
||||||
|
|
||||||
|
return (Vector2){ transform.x, transform.y };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the world space position for a 2d camera screen space position
|
||||||
|
Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera)
|
||||||
|
{
|
||||||
|
Matrix invMatCamera = MatrixInvert(GetCameraMatrix2D(camera));
|
||||||
|
Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, invMatCamera);
|
||||||
|
|
||||||
|
return (Vector2){ transform.x, transform.y };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set target FPS (maximum)
|
// Set target FPS (maximum)
|
||||||
|
|
@ -1664,7 +1743,6 @@ void SetConfigFlags(unsigned int flags)
|
||||||
{
|
{
|
||||||
configFlags = flags;
|
configFlags = flags;
|
||||||
|
|
||||||
if (configFlags & FLAG_SHOW_LOGO) showLogo = true;
|
|
||||||
if (configFlags & FLAG_FULLSCREEN_MODE) fullscreen = true;
|
if (configFlags & FLAG_FULLSCREEN_MODE) fullscreen = true;
|
||||||
if (configFlags & FLAG_WINDOW_ALWAYS_RUN) alwaysRun = true;
|
if (configFlags & FLAG_WINDOW_ALWAYS_RUN) alwaysRun = true;
|
||||||
}
|
}
|
||||||
|
|
@ -1718,29 +1796,36 @@ bool FileExists(const char *fileName)
|
||||||
bool IsFileExtension(const char *fileName, const char *ext)
|
bool IsFileExtension(const char *fileName, const char *ext)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
const char *fileExt;
|
const char *fileExt = GetExtension(fileName);
|
||||||
|
|
||||||
if ((fileExt = strrchr(fileName, '.')) != NULL)
|
if (fileExt != NULL)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
int extCount = 0;
|
||||||
result = true;
|
const char **checkExts = TextSplit(ext, ';', &extCount);
|
||||||
int extLen = strlen(ext);
|
|
||||||
|
|
||||||
if (strlen(fileExt) == extLen)
|
for (int i = 0; i < extCount; i++)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < extLen; i++)
|
if (strcmp(fileExt, checkExts[i] + 1) == 0)
|
||||||
{
|
{
|
||||||
if (tolower(fileExt[i]) != tolower(ext[i]))
|
result = true;
|
||||||
{
|
break;
|
||||||
result = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else result = false;
|
}
|
||||||
#else
|
|
||||||
if (strcmp(fileExt, ext) == 0) result = true;
|
return result;
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
// Check if a directory path exists
|
||||||
|
bool DirectoryExists(const char *dirPath)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
DIR *dir = opendir(dirPath);
|
||||||
|
|
||||||
|
if (dir != NULL)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
closedir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -1767,22 +1852,23 @@ static const char *strprbrk(const char *s, const char *charset)
|
||||||
// Get pointer to filename for a path string
|
// Get pointer to filename for a path string
|
||||||
const char *GetFileName(const char *filePath)
|
const char *GetFileName(const char *filePath)
|
||||||
{
|
{
|
||||||
const char *fileName = strprbrk(filePath, "\\/");
|
const char *fileName = NULL;
|
||||||
|
if (filePath != NULL) fileName = strprbrk(filePath, "\\/");
|
||||||
|
|
||||||
if (!fileName || fileName == filePath) return filePath;
|
if (!fileName || (fileName == filePath)) return filePath;
|
||||||
|
|
||||||
return fileName + 1;
|
return fileName + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get filename string without extension (memory should be freed)
|
// Get filename string without extension (uses static string)
|
||||||
const char *GetFileNameWithoutExt(const char *filePath)
|
const char *GetFileNameWithoutExt(const char *filePath)
|
||||||
{
|
{
|
||||||
#define MAX_FILENAMEWITHOUTEXT_LENGTH 64
|
#define MAX_FILENAMEWITHOUTEXT_LENGTH 128
|
||||||
|
|
||||||
static char fileName[MAX_FILENAMEWITHOUTEXT_LENGTH];
|
static char fileName[MAX_FILENAMEWITHOUTEXT_LENGTH];
|
||||||
memset(fileName, 0, MAX_FILENAMEWITHOUTEXT_LENGTH);
|
memset(fileName, 0, MAX_FILENAMEWITHOUTEXT_LENGTH);
|
||||||
|
|
||||||
strcpy(fileName, GetFileName(filePath)); // Get filename with extension
|
if (filePath != NULL) strcpy(fileName, GetFileName(filePath)); // Get filename with extension
|
||||||
|
|
||||||
int len = strlen(fileName);
|
int len = strlen(fileName);
|
||||||
|
|
||||||
|
|
@ -1799,21 +1885,43 @@ const char *GetFileNameWithoutExt(const char *filePath)
|
||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get directory for a given fileName (with path)
|
// Get directory for a given filePath
|
||||||
const char *GetDirectoryPath(const char *fileName)
|
const char *GetDirectoryPath(const char *filePath)
|
||||||
{
|
{
|
||||||
const char *lastSlash = NULL;
|
const char *lastSlash = NULL;
|
||||||
static char filePath[MAX_FILEPATH_LENGTH];
|
static char dirPath[MAX_FILEPATH_LENGTH];
|
||||||
memset(filePath, 0, MAX_FILEPATH_LENGTH);
|
memset(dirPath, 0, MAX_FILEPATH_LENGTH);
|
||||||
|
|
||||||
lastSlash = strprbrk(fileName, "\\/");
|
lastSlash = strprbrk(filePath, "\\/");
|
||||||
if (!lastSlash) return NULL;
|
if (!lastSlash) return NULL;
|
||||||
|
|
||||||
// NOTE: Be careful, strncpy() is not safe, it does not care about '\0'
|
// NOTE: Be careful, strncpy() is not safe, it does not care about '\0'
|
||||||
strncpy(filePath, fileName, strlen(fileName) - (strlen(lastSlash) - 1));
|
strncpy(dirPath, filePath, strlen(filePath) - (strlen(lastSlash) - 1));
|
||||||
filePath[strlen(fileName) - strlen(lastSlash)] = '\0'; // Add '\0' manually
|
dirPath[strlen(filePath) - strlen(lastSlash)] = '\0'; // Add '\0' manually
|
||||||
|
|
||||||
return filePath;
|
return dirPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get previous directory path for a given path
|
||||||
|
const char *GetPrevDirectoryPath(const char *dirPath)
|
||||||
|
{
|
||||||
|
static char prevDirPath[MAX_FILEPATH_LENGTH];
|
||||||
|
memset(prevDirPath, 0, MAX_FILEPATH_LENGTH);
|
||||||
|
int pathLen = strlen(dirPath);
|
||||||
|
|
||||||
|
if (pathLen <= 3) strcpy(prevDirPath, dirPath);
|
||||||
|
|
||||||
|
for (int i = (pathLen - 1); (i > 0) && (pathLen > 3); i--)
|
||||||
|
{
|
||||||
|
if ((dirPath[i] == '\\') || (dirPath[i] == '/'))
|
||||||
|
{
|
||||||
|
if (i == 2) i++; // Check for root: "C:\"
|
||||||
|
strncpy(prevDirPath, dirPath, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return prevDirPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current working directory
|
// Get current working directory
|
||||||
|
|
@ -1870,11 +1978,12 @@ void ClearDirectoryFiles(void)
|
||||||
{
|
{
|
||||||
if (dirFilesCount > 0)
|
if (dirFilesCount > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < dirFilesCount; i++) RL_FREE(dirFilesPath[i]);
|
for (int i = 0; i < MAX_DIRECTORY_FILES; i++) RL_FREE(dirFilesPath[i]);
|
||||||
|
|
||||||
RL_FREE(dirFilesPath);
|
RL_FREE(dirFilesPath);
|
||||||
dirFilesCount = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dirFilesCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change working directory, returns true if success
|
// Change working directory, returns true if success
|
||||||
|
|
@ -1925,6 +2034,32 @@ long GetFileModTime(const char *fileName)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compress data (DEFLATE algorythm)
|
||||||
|
unsigned char *CompressData(unsigned char *data, int dataLength, int *compDataLength)
|
||||||
|
{
|
||||||
|
#define COMPRESSION_QUALITY_DEFLATE 8
|
||||||
|
|
||||||
|
unsigned char *compData = NULL;
|
||||||
|
|
||||||
|
#if defined(SUPPORT_COMPRESSION_API)
|
||||||
|
compData = stbi_zlib_compress(data, dataLength, compDataLength, COMPRESSION_QUALITY_DEFLATE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return compData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decompress data (DEFLATE algorythm)
|
||||||
|
unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *dataLength)
|
||||||
|
{
|
||||||
|
char *data = NULL;
|
||||||
|
|
||||||
|
#if defined(SUPPORT_COMPRESSION_API)
|
||||||
|
data = stbi_zlib_decode_malloc((char *)compData, compDataLength, dataLength);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (unsigned char *)data;
|
||||||
|
}
|
||||||
|
|
||||||
// Save integer value to storage file (to defined position)
|
// Save integer value to storage file (to defined position)
|
||||||
// NOTE: Storage positions is directly related to file memory layout (4 bytes each integer)
|
// NOTE: Storage positions is directly related to file memory layout (4 bytes each integer)
|
||||||
void StorageSaveValue(int position, int value)
|
void StorageSaveValue(int position, int value)
|
||||||
|
|
@ -2287,7 +2422,7 @@ int GetMouseX(void)
|
||||||
int GetMouseY(void)
|
int GetMouseY(void)
|
||||||
{
|
{
|
||||||
#if defined(PLATFORM_ANDROID)
|
#if defined(PLATFORM_ANDROID)
|
||||||
return (int)touchPosition[0].x;
|
return (int)touchPosition[0].y;
|
||||||
#else
|
#else
|
||||||
return (int)((mousePosition.y + mouseOffset.y)*mouseScale.y);
|
return (int)((mousePosition.y + mouseOffset.y)*mouseScale.y);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -2457,9 +2592,6 @@ static bool InitGraphicsDevice(int width, int height)
|
||||||
if (screenHeight <= 0) screenHeight = displayHeight;
|
if (screenHeight <= 0) screenHeight = displayHeight;
|
||||||
#endif // PLATFORM_DESKTOP
|
#endif // PLATFORM_DESKTOP
|
||||||
|
|
||||||
currentWidth = screenWidth;
|
|
||||||
currentHeight = screenHeight;
|
|
||||||
|
|
||||||
#if defined(PLATFORM_WEB)
|
#if defined(PLATFORM_WEB)
|
||||||
displayWidth = screenWidth;
|
displayWidth = screenWidth;
|
||||||
displayHeight = screenHeight;
|
displayHeight = screenHeight;
|
||||||
|
|
@ -2525,9 +2657,9 @@ static bool InitGraphicsDevice(int width, int height)
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
||||||
#if defined(PLATFORM_DESKTOP)
|
#if defined(PLATFORM_DESKTOP)
|
||||||
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
|
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
|
||||||
#else
|
#else
|
||||||
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API);
|
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2990,6 +3122,9 @@ static bool InitGraphicsDevice(int width, int height)
|
||||||
// Setup default viewport
|
// Setup default viewport
|
||||||
SetupViewport(fbWidth, fbHeight);
|
SetupViewport(fbWidth, fbHeight);
|
||||||
|
|
||||||
|
currentWidth = screenWidth;
|
||||||
|
currentHeight = screenHeight;
|
||||||
|
|
||||||
ClearBackground(RAYWHITE); // Default background color for raylib games :P
|
ClearBackground(RAYWHITE); // Default background color for raylib games :P
|
||||||
|
|
||||||
#if defined(PLATFORM_ANDROID)
|
#if defined(PLATFORM_ANDROID)
|
||||||
|
|
@ -3818,7 +3953,7 @@ static void WindowIconifyCallback(GLFWwindow *window, int iconified)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GLFW3 Window Drop Callback, runs when drop files into window
|
// GLFW3 Window Drop Callback, runs when drop files into window
|
||||||
// NOTE: Paths are stored in dinamic memory for further retrieval
|
// NOTE: Paths are stored in dynamic memory for further retrieval
|
||||||
// Everytime new files are dropped, old ones are discarded
|
// Everytime new files are dropped, old ones are discarded
|
||||||
static void WindowDropCallback(GLFWwindow *window, int count, const char **paths)
|
static void WindowDropCallback(GLFWwindow *window, int count, const char **paths)
|
||||||
{
|
{
|
||||||
|
|
@ -3898,13 +4033,6 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// raylib logo appearing animation (if enabled)
|
|
||||||
if (showLogo)
|
|
||||||
{
|
|
||||||
SetTargetFPS(60); // Not required on Android
|
|
||||||
LogoAnimation();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
@ -4235,8 +4363,8 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE
|
||||||
eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state",
|
eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state",
|
||||||
gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping);
|
gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping);
|
||||||
|
|
||||||
for(int i = 0; i < gamepadEvent->numAxes; ++i) TraceLog(LOG_DEBUG, "Axis %d: %g", i, gamepadEvent->axis[i]);
|
for (int i = 0; i < gamepadEvent->numAxes; ++i) TraceLog(LOG_DEBUG, "Axis %d: %g", i, gamepadEvent->axis[i]);
|
||||||
for(int i = 0; i < gamepadEvent->numButtons; ++i) TraceLog(LOG_DEBUG, "Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]);
|
for (int i = 0; i < gamepadEvent->numButtons; ++i) TraceLog(LOG_DEBUG, "Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS)) gamepadReady[gamepadEvent->index] = true;
|
if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS)) gamepadReady[gamepadEvent->index] = true;
|
||||||
|
|
@ -4796,7 +4924,7 @@ static void *EventThread(void *arg)
|
||||||
// TODO: This fifo is not fully threadsafe with multiple writers, so multiple keyboards hitting a key at the exact same time could miss a key (double write to head before it was incremented)
|
// TODO: This fifo is not fully threadsafe with multiple writers, so multiple keyboards hitting a key at the exact same time could miss a key (double write to head before it was incremented)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
currentKeyState[keycode] = event.value;
|
currentKeyState[keycode] = event.value;
|
||||||
if (event.value == 1) lastKeyPressed = keycode; // Register last key pressed
|
if (event.value == 1) lastKeyPressed = keycode; // Register last key pressed
|
||||||
|
|
||||||
|
|
@ -4810,7 +4938,7 @@ static void *EventThread(void *arg)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (currentKeyState[exitKey] == 1) windowShouldClose = true;
|
if (currentKeyState[exitKey] == 1) windowShouldClose = true;
|
||||||
|
|
||||||
TraceLog(LOG_DEBUG, "KEY%s ScanCode: %4i KeyCode: %4i",event.value == 0 ? "UP":"DOWN", event.code, keycode);
|
TraceLog(LOG_DEBUG, "KEY%s ScanCode: %4i KeyCode: %4i",event.value == 0 ? "UP":"DOWN", event.code, keycode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4952,117 +5080,3 @@ static void *GamepadThread(void *arg)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif // PLATFORM_RPI
|
#endif // PLATFORM_RPI
|
||||||
|
|
||||||
// Plays raylib logo appearing animation
|
|
||||||
static void LogoAnimation(void)
|
|
||||||
{
|
|
||||||
#if !defined(PLATFORM_WEB) && !defined(PLATFORM_UWP)
|
|
||||||
int logoPositionX = screenWidth/2 - 128;
|
|
||||||
int logoPositionY = screenHeight/2 - 128;
|
|
||||||
|
|
||||||
int framesCounter = 0;
|
|
||||||
int lettersCount = 0;
|
|
||||||
|
|
||||||
int topSideRecWidth = 16;
|
|
||||||
int leftSideRecHeight = 16;
|
|
||||||
|
|
||||||
int bottomSideRecWidth = 16;
|
|
||||||
int rightSideRecHeight = 16;
|
|
||||||
|
|
||||||
int state = 0; // Tracking animation states (State Machine)
|
|
||||||
float alpha = 1.0f; // Useful for fading
|
|
||||||
|
|
||||||
while (!WindowShouldClose() && (state != 4)) // Detect window close button or ESC key
|
|
||||||
{
|
|
||||||
// Update
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
if (state == 0) // State 0: Small box blinking
|
|
||||||
{
|
|
||||||
framesCounter++;
|
|
||||||
|
|
||||||
if (framesCounter == 84)
|
|
||||||
{
|
|
||||||
state = 1;
|
|
||||||
framesCounter = 0; // Reset counter... will be used later...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (state == 1) // State 1: Top and left bars growing
|
|
||||||
{
|
|
||||||
topSideRecWidth += 4;
|
|
||||||
leftSideRecHeight += 4;
|
|
||||||
|
|
||||||
if (topSideRecWidth == 256) state = 2;
|
|
||||||
}
|
|
||||||
else if (state == 2) // State 2: Bottom and right bars growing
|
|
||||||
{
|
|
||||||
bottomSideRecWidth += 4;
|
|
||||||
rightSideRecHeight += 4;
|
|
||||||
|
|
||||||
if (bottomSideRecWidth == 256) state = 3;
|
|
||||||
}
|
|
||||||
else if (state == 3) // State 3: Letters appearing (one by one)
|
|
||||||
{
|
|
||||||
framesCounter++;
|
|
||||||
|
|
||||||
if (framesCounter/12) // Every 12 frames, one more letter!
|
|
||||||
{
|
|
||||||
lettersCount++;
|
|
||||||
framesCounter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lettersCount >= 10) // When all letters have appeared, just fade out everything
|
|
||||||
{
|
|
||||||
alpha -= 0.02f;
|
|
||||||
|
|
||||||
if (alpha <= 0.0f)
|
|
||||||
{
|
|
||||||
alpha = 0.0f;
|
|
||||||
state = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Draw
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
BeginDrawing();
|
|
||||||
|
|
||||||
ClearBackground(RAYWHITE);
|
|
||||||
|
|
||||||
if (state == 0)
|
|
||||||
{
|
|
||||||
if ((framesCounter/12)%2) DrawRectangle(logoPositionX, logoPositionY, 16, 16, BLACK);
|
|
||||||
}
|
|
||||||
else if (state == 1)
|
|
||||||
{
|
|
||||||
DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK);
|
|
||||||
DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK);
|
|
||||||
}
|
|
||||||
else if (state == 2)
|
|
||||||
{
|
|
||||||
DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK);
|
|
||||||
DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK);
|
|
||||||
|
|
||||||
DrawRectangle(logoPositionX + 240, logoPositionY, 16, rightSideRecHeight, BLACK);
|
|
||||||
DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, BLACK);
|
|
||||||
}
|
|
||||||
else if (state == 3)
|
|
||||||
{
|
|
||||||
DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, Fade(BLACK, alpha));
|
|
||||||
DrawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, Fade(BLACK, alpha));
|
|
||||||
|
|
||||||
DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, Fade(BLACK, alpha));
|
|
||||||
DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, Fade(BLACK, alpha));
|
|
||||||
|
|
||||||
DrawRectangle(screenWidth/2 - 112, screenHeight/2 - 112, 224, 224, Fade(RAYWHITE, alpha));
|
|
||||||
|
|
||||||
DrawText(TextSubtext("raylib", 0, lettersCount), screenWidth/2 - 44, screenHeight/2 + 48, 50, Fade(BLACK, alpha));
|
|
||||||
}
|
|
||||||
|
|
||||||
EndDrawing();
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
showLogo = false; // Prevent for repeating when reloading window (Android)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ EASEDEF float EaseQuadOut(float t, float b, float c, float d) { t /= d; return (
|
||||||
EASEDEF float EaseQuadInOut(float t, float b, float c, float d)
|
EASEDEF float EaseQuadInOut(float t, float b, float c, float d)
|
||||||
{
|
{
|
||||||
if ((t/=d/2) < 1) return (((c/2)*(t*t)) + b);
|
if ((t/=d/2) < 1) return (((c/2)*(t*t)) + b);
|
||||||
return (-c/2.0f*(((t - 1.0f)*(t - 3.0f)) - 1.0f) + b);
|
return (-c/2.0f*(((t - 1.0f)*(t - 3.0f)) - 1.0f) + b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exponential Easing functions
|
// Exponential Easing functions
|
||||||
|
|
@ -147,7 +147,7 @@ EASEDEF float EaseExpoInOut(float t, float b, float c, float d)
|
||||||
if (t == d) return (b + c);
|
if (t == d) return (b + c);
|
||||||
if ((t/=d/2.0f) < 1.0f) return (c/2.0f*pow(2.0f, 10.0f*(t - 1.0f)) + b);
|
if ((t/=d/2.0f) < 1.0f) return (c/2.0f*pow(2.0f, 10.0f*(t - 1.0f)) + b);
|
||||||
|
|
||||||
return (c/2.0f*(-pow(2.0f, -10.0f*(t - 1.0f)) + 2.0f) + b);
|
return (c/2.0f*(-pow(2.0f, -10.0f*(t - 1.0f)) + 2.0f) + b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Back Easing functions
|
// Back Easing functions
|
||||||
|
|
|
||||||
598
src/external/cgltf.h
vendored
109
src/external/dr_flac.h
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
|
FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||||
dr_flac - v0.11.7 - 2019-05-06
|
dr_flac - v0.11.10 - 2019-06-26
|
||||||
|
|
||||||
David Reid - mackron@gmail.com
|
David Reid - mackron@gmail.com
|
||||||
*/
|
*/
|
||||||
|
|
@ -149,7 +149,7 @@ typedef drflac_uint32 drflac_bool32;
|
||||||
#elif (defined(__GNUC__) && __GNUC__ >= 4) /* GCC 4 */
|
#elif (defined(__GNUC__) && __GNUC__ >= 4) /* GCC 4 */
|
||||||
#define DRFLAC_DEPRECATED __attribute__((deprecated))
|
#define DRFLAC_DEPRECATED __attribute__((deprecated))
|
||||||
#elif defined(__has_feature) /* Clang */
|
#elif defined(__has_feature) /* Clang */
|
||||||
#if defined(__has_feature(attribute_deprecated))
|
#if __has_feature(attribute_deprecated)
|
||||||
#define DRFLAC_DEPRECATED __attribute__((deprecated))
|
#define DRFLAC_DEPRECATED __attribute__((deprecated))
|
||||||
#else
|
#else
|
||||||
#define DRFLAC_DEPRECATED
|
#define DRFLAC_DEPRECATED
|
||||||
|
|
@ -1008,7 +1008,7 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse2()
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
#else
|
#else
|
||||||
int info[4];
|
int info[4];
|
||||||
drflac_cpuid(info, 1);
|
drflac__cpuid(info, 1);
|
||||||
return (info[3] & (1 << 26)) != 0;
|
return (info[3] & (1 << 26)) != 0;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1033,7 +1033,7 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41()
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
#else
|
#else
|
||||||
int info[4];
|
int info[4];
|
||||||
drflac_cpuid(info, 1);
|
drflac__cpuid(info, 1);
|
||||||
return (info[2] & (1 << 19)) != 0;
|
return (info[2] & (1 << 19)) != 0;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1141,21 +1141,43 @@ reference excess prior samples.
|
||||||
/* CPU caps. */
|
/* CPU caps. */
|
||||||
static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE;
|
static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE;
|
||||||
#ifndef DRFLAC_NO_CPUID
|
#ifndef DRFLAC_NO_CPUID
|
||||||
|
/*
|
||||||
|
I've had a bug report that Clang's ThreadSanitizer presents a warning in this function. Having reviewed this, this does
|
||||||
|
actually make sense. However, since CPU caps should never differ for a running process, I don't think the trade off of
|
||||||
|
complicating internal API's by passing around CPU caps versus just disabling the warnings is worthwhile. I'm therefore
|
||||||
|
just going to disable these warnings.
|
||||||
|
*/
|
||||||
|
#if defined(__has_feature)
|
||||||
|
#if __has_feature(thread_sanitizer)
|
||||||
|
#define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread")))
|
||||||
|
#else
|
||||||
|
#define DRFLAC_NO_THREAD_SANITIZE
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define DRFLAC_NO_THREAD_SANITIZE
|
||||||
|
#endif
|
||||||
static drflac_bool32 drflac__gIsSSE2Supported = DRFLAC_FALSE;
|
static drflac_bool32 drflac__gIsSSE2Supported = DRFLAC_FALSE;
|
||||||
static drflac_bool32 drflac__gIsSSE41Supported = DRFLAC_FALSE;
|
static drflac_bool32 drflac__gIsSSE41Supported = DRFLAC_FALSE;
|
||||||
static void drflac__init_cpu_caps()
|
DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps()
|
||||||
{
|
{
|
||||||
int info[4] = {0};
|
static drflac_bool32 isCPUCapsInitialized = DRFLAC_FALSE;
|
||||||
|
|
||||||
/* LZCNT */
|
if (!isCPUCapsInitialized) {
|
||||||
drflac__cpuid(info, 0x80000001);
|
int info[4] = {0};
|
||||||
drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0;
|
|
||||||
|
|
||||||
/* SSE2 */
|
/* LZCNT */
|
||||||
drflac__gIsSSE2Supported = drflac_has_sse2();
|
drflac__cpuid(info, 0x80000001);
|
||||||
|
drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0;
|
||||||
|
|
||||||
/* SSE4.1 */
|
/* SSE2 */
|
||||||
drflac__gIsSSE41Supported = drflac_has_sse41();
|
drflac__gIsSSE2Supported = drflac_has_sse2();
|
||||||
|
|
||||||
|
/* SSE4.1 */
|
||||||
|
drflac__gIsSSE41Supported = drflac_has_sse41();
|
||||||
|
|
||||||
|
/* Initialized. */
|
||||||
|
isCPUCapsInitialized = DRFLAC_TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -4897,9 +4919,9 @@ typedef struct
|
||||||
static DRFLAC_INLINE void drflac__decode_block_header(drflac_uint32 blockHeader, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize)
|
static DRFLAC_INLINE void drflac__decode_block_header(drflac_uint32 blockHeader, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize)
|
||||||
{
|
{
|
||||||
blockHeader = drflac__be2host_32(blockHeader);
|
blockHeader = drflac__be2host_32(blockHeader);
|
||||||
*isLastBlock = (blockHeader & (0x01 << 31)) >> 31;
|
*isLastBlock = (blockHeader & 0x80000000UL) >> 31;
|
||||||
*blockType = (blockHeader & (0x7F << 24)) >> 24;
|
*blockType = (blockHeader & 0x7F000000UL) >> 24;
|
||||||
*blockSize = (blockHeader & 0xFFFFFF);
|
*blockSize = (blockHeader & 0x00FFFFFFUL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DRFLAC_INLINE drflac_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize)
|
static DRFLAC_INLINE drflac_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize)
|
||||||
|
|
@ -6759,10 +6781,10 @@ drflac_uint64 drflac__read_s32__misaligned(drflac* pFlac, drflac_uint64 samplesT
|
||||||
case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
|
case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
|
||||||
{
|
{
|
||||||
if (channelIndex == 0) {
|
if (channelIndex == 0) {
|
||||||
decodedSample = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample;
|
decodedSample = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample);
|
||||||
} else {
|
} else {
|
||||||
int side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample;
|
int side = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample);
|
||||||
int left = pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex - 1].wastedBitsPerSample;
|
int left = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex - 1].wastedBitsPerSample);
|
||||||
decodedSample = left - side;
|
decodedSample = left - side;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
@ -6770,11 +6792,11 @@ drflac_uint64 drflac__read_s32__misaligned(drflac* pFlac, drflac_uint64 samplesT
|
||||||
case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
|
case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
|
||||||
{
|
{
|
||||||
if (channelIndex == 0) {
|
if (channelIndex == 0) {
|
||||||
int side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample;
|
int side = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample);
|
||||||
int right = pFlac->currentFrame.subframes[channelIndex + 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 1].wastedBitsPerSample;
|
int right = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 1].wastedBitsPerSample);
|
||||||
decodedSample = side + right;
|
decodedSample = side + right;
|
||||||
} else {
|
} else {
|
||||||
decodedSample = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample;
|
decodedSample = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
@ -6783,14 +6805,14 @@ drflac_uint64 drflac__read_s32__misaligned(drflac* pFlac, drflac_uint64 samplesT
|
||||||
int mid;
|
int mid;
|
||||||
int side;
|
int side;
|
||||||
if (channelIndex == 0) {
|
if (channelIndex == 0) {
|
||||||
mid = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample;
|
mid = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample);
|
||||||
side = pFlac->currentFrame.subframes[channelIndex + 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 1].wastedBitsPerSample;
|
side = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 1].wastedBitsPerSample);
|
||||||
|
|
||||||
mid = (((unsigned int)mid) << 1) | (side & 0x01);
|
mid = (((unsigned int)mid) << 1) | (side & 0x01);
|
||||||
decodedSample = (mid + side) >> 1;
|
decodedSample = (mid + side) >> 1;
|
||||||
} else {
|
} else {
|
||||||
mid = pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex - 1].wastedBitsPerSample;
|
mid = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex - 1].wastedBitsPerSample);
|
||||||
side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample;
|
side = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample);
|
||||||
|
|
||||||
mid = (((unsigned int)mid) << 1) | (side & 0x01);
|
mid = (((unsigned int)mid) << 1) | (side & 0x01);
|
||||||
decodedSample = (mid - side) >> 1;
|
decodedSample = (mid - side) >> 1;
|
||||||
|
|
@ -6800,11 +6822,11 @@ drflac_uint64 drflac__read_s32__misaligned(drflac* pFlac, drflac_uint64 samplesT
|
||||||
case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
|
case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
decodedSample = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample;
|
decodedSample = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
decodedSample <<= (32 - pFlac->bitsPerSample);
|
decodedSample = (int)((drflac_uint32)decodedSample << (32 - pFlac->bitsPerSample));
|
||||||
|
|
||||||
if (bufferOut) {
|
if (bufferOut) {
|
||||||
*bufferOut++ = decodedSample;
|
*bufferOut++ = decodedSample;
|
||||||
|
|
@ -6876,8 +6898,8 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac
|
||||||
const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
|
const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
|
||||||
|
|
||||||
for (i = 0; i < alignedSampleCountPerChannel; ++i) {
|
for (i = 0; i < alignedSampleCountPerChannel; ++i) {
|
||||||
int left = pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample);
|
int left = (int)((drflac_uint32)pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample));
|
||||||
int side = pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample);
|
int side = (int)((drflac_uint32)pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample));
|
||||||
int right = left - side;
|
int right = left - side;
|
||||||
|
|
||||||
bufferOut[i*2+0] = left;
|
bufferOut[i*2+0] = left;
|
||||||
|
|
@ -6892,8 +6914,8 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac
|
||||||
const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
|
const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
|
||||||
|
|
||||||
for (i = 0; i < alignedSampleCountPerChannel; ++i) {
|
for (i = 0; i < alignedSampleCountPerChannel; ++i) {
|
||||||
int side = pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample);
|
int side = (int)((drflac_uint32)pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample));
|
||||||
int right = pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample);
|
int right = (int)((drflac_uint32)pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample));
|
||||||
int left = right + side;
|
int left = right + side;
|
||||||
|
|
||||||
bufferOut[i*2+0] = left;
|
bufferOut[i*2+0] = left;
|
||||||
|
|
@ -6908,13 +6930,13 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac
|
||||||
const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
|
const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
|
||||||
|
|
||||||
for (i = 0; i < alignedSampleCountPerChannel; ++i) {
|
for (i = 0; i < alignedSampleCountPerChannel; ++i) {
|
||||||
int mid = pDecodedSamples0[i] << pFlac->currentFrame.subframes[0].wastedBitsPerSample;
|
int mid = (int)((drflac_uint32)pDecodedSamples0[i] << pFlac->currentFrame.subframes[0].wastedBitsPerSample);
|
||||||
int side = pDecodedSamples1[i] << pFlac->currentFrame.subframes[1].wastedBitsPerSample;
|
int side = (int)((drflac_uint32)pDecodedSamples1[i] << pFlac->currentFrame.subframes[1].wastedBitsPerSample);
|
||||||
|
|
||||||
mid = (((drflac_uint32)mid) << 1) | (side & 0x01);
|
mid = (((drflac_uint32)mid) << 1) | (side & 0x01);
|
||||||
|
|
||||||
bufferOut[i*2+0] = ((mid + side) >> 1) << (unusedBitsPerSample);
|
bufferOut[i*2+0] = (drflac_int32)((drflac_uint32)((mid + side) >> 1) << (unusedBitsPerSample));
|
||||||
bufferOut[i*2+1] = ((mid - side) >> 1) << (unusedBitsPerSample);
|
bufferOut[i*2+1] = (drflac_int32)((drflac_uint32)((mid - side) >> 1) << (unusedBitsPerSample));
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
@ -6929,8 +6951,8 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac
|
||||||
const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
|
const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
|
||||||
|
|
||||||
for (i = 0; i < alignedSampleCountPerChannel; ++i) {
|
for (i = 0; i < alignedSampleCountPerChannel; ++i) {
|
||||||
bufferOut[i*2+0] = pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample);
|
bufferOut[i*2+0] = (drflac_int32)((drflac_uint32)pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample));
|
||||||
bufferOut[i*2+1] = pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample);
|
bufferOut[i*2+1] = (drflac_int32)((drflac_uint32)pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -6940,7 +6962,7 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac
|
||||||
for (i = 0; i < alignedSampleCountPerChannel; ++i) {
|
for (i = 0; i < alignedSampleCountPerChannel; ++i) {
|
||||||
unsigned int j;
|
unsigned int j;
|
||||||
for (j = 0; j < channelCount; ++j) {
|
for (j = 0; j < channelCount; ++j) {
|
||||||
bufferOut[(i*channelCount)+j] = (pFlac->currentFrame.subframes[j].pDecodedSamples[firstAlignedSampleInFrame + i]) << (unusedBitsPerSample + pFlac->currentFrame.subframes[j].wastedBitsPerSample);
|
bufferOut[(i*channelCount)+j] = (drflac_int32)((drflac_uint32)(pFlac->currentFrame.subframes[j].pDecodedSamples[firstAlignedSampleInFrame + i]) << (unusedBitsPerSample + pFlac->currentFrame.subframes[j].wastedBitsPerSample));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8649,6 +8671,15 @@ drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter,
|
||||||
/*
|
/*
|
||||||
REVISION HISTORY
|
REVISION HISTORY
|
||||||
================
|
================
|
||||||
|
v0.11.10 - 2019-06-26
|
||||||
|
- Fix a compiler error.
|
||||||
|
|
||||||
|
v0.11.9 - 2019-06-16
|
||||||
|
- Silence some ThreadSanitizer warnings.
|
||||||
|
|
||||||
|
v0.11.8 - 2019-05-21
|
||||||
|
- Fix warnings.
|
||||||
|
|
||||||
v0.11.7 - 2019-05-06
|
v0.11.7 - 2019-05-06
|
||||||
- C89 fixes.
|
- C89 fixes.
|
||||||
|
|
||||||
|
|
|
||||||
114
src/external/dr_mp3.h
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
|
MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||||
dr_mp3 - v0.4.4 - 2019-05-06
|
dr_mp3 - v0.4.7 - 2019-07-28
|
||||||
|
|
||||||
David Reid - mackron@gmail.com
|
David Reid - mackron@gmail.com
|
||||||
|
|
||||||
|
|
@ -1143,41 +1143,72 @@ static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *g
|
||||||
int sfb_cnt = gr_info->region_count[ireg++];
|
int sfb_cnt = gr_info->region_count[ireg++];
|
||||||
const drmp3_int16 *codebook = tabs + tabindex[tab_num];
|
const drmp3_int16 *codebook = tabs + tabindex[tab_num];
|
||||||
int linbits = g_linbits[tab_num];
|
int linbits = g_linbits[tab_num];
|
||||||
do
|
if (linbits)
|
||||||
{
|
{
|
||||||
np = *sfb++ / 2;
|
|
||||||
pairs_to_decode = DRMP3_MIN(big_val_cnt, np);
|
|
||||||
one = *scf++;
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int j, w = 5;
|
np = *sfb++ / 2;
|
||||||
int leaf = codebook[DRMP3_PEEK_BITS(w)];
|
pairs_to_decode = DRMP3_MIN(big_val_cnt, np);
|
||||||
while (leaf < 0)
|
one = *scf++;
|
||||||
|
do
|
||||||
{
|
{
|
||||||
DRMP3_FLUSH_BITS(w);
|
int j, w = 5;
|
||||||
w = leaf & 7;
|
int leaf = codebook[DRMP3_PEEK_BITS(w)];
|
||||||
leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)];
|
while (leaf < 0)
|
||||||
}
|
|
||||||
DRMP3_FLUSH_BITS(leaf >> 8);
|
|
||||||
|
|
||||||
for (j = 0; j < 2; j++, dst++, leaf >>= 4)
|
|
||||||
{
|
|
||||||
int lsb = leaf & 0x0F;
|
|
||||||
if (lsb == 15 && linbits)
|
|
||||||
{
|
{
|
||||||
lsb += DRMP3_PEEK_BITS(linbits);
|
DRMP3_FLUSH_BITS(w);
|
||||||
DRMP3_FLUSH_BITS(linbits);
|
w = leaf & 7;
|
||||||
DRMP3_CHECK_BITS;
|
leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)];
|
||||||
*dst = one*drmp3_L3_pow_43(lsb)*((drmp3_int32)bs_cache < 0 ? -1: 1);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
*dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one;
|
|
||||||
}
|
}
|
||||||
DRMP3_FLUSH_BITS(lsb ? 1 : 0);
|
DRMP3_FLUSH_BITS(leaf >> 8);
|
||||||
}
|
|
||||||
DRMP3_CHECK_BITS;
|
for (j = 0; j < 2; j++, dst++, leaf >>= 4)
|
||||||
} while (--pairs_to_decode);
|
{
|
||||||
} while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0);
|
int lsb = leaf & 0x0F;
|
||||||
|
if (lsb == 15)
|
||||||
|
{
|
||||||
|
lsb += DRMP3_PEEK_BITS(linbits);
|
||||||
|
DRMP3_FLUSH_BITS(linbits);
|
||||||
|
DRMP3_CHECK_BITS;
|
||||||
|
*dst = one*drmp3_L3_pow_43(lsb)*((drmp3_int32)bs_cache < 0 ? -1: 1);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
*dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one;
|
||||||
|
}
|
||||||
|
DRMP3_FLUSH_BITS(lsb ? 1 : 0);
|
||||||
|
}
|
||||||
|
DRMP3_CHECK_BITS;
|
||||||
|
} while (--pairs_to_decode);
|
||||||
|
} while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
np = *sfb++ / 2;
|
||||||
|
pairs_to_decode = DRMP3_MIN(big_val_cnt, np);
|
||||||
|
one = *scf++;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
int j, w = 5;
|
||||||
|
int leaf = codebook[DRMP3_PEEK_BITS(w)];
|
||||||
|
while (leaf < 0)
|
||||||
|
{
|
||||||
|
DRMP3_FLUSH_BITS(w);
|
||||||
|
w = leaf & 7;
|
||||||
|
leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)];
|
||||||
|
}
|
||||||
|
DRMP3_FLUSH_BITS(leaf >> 8);
|
||||||
|
|
||||||
|
for (j = 0; j < 2; j++, dst++, leaf >>= 4)
|
||||||
|
{
|
||||||
|
int lsb = leaf & 0x0F;
|
||||||
|
*dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one;
|
||||||
|
DRMP3_FLUSH_BITS(lsb ? 1 : 0);
|
||||||
|
}
|
||||||
|
DRMP3_CHECK_BITS;
|
||||||
|
} while (--pairs_to_decode);
|
||||||
|
} while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (np = 1 - big_val_cnt;; dst += 4)
|
for (np = 1 - big_val_cnt;; dst += 4)
|
||||||
|
|
@ -2133,14 +2164,14 @@ void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, int num_samples)
|
||||||
int aligned_count = num_samples & ~7;
|
int aligned_count = num_samples & ~7;
|
||||||
for(; i < aligned_count; i+=8)
|
for(; i < aligned_count; i+=8)
|
||||||
{
|
{
|
||||||
static const drmp3_f4 g_scale = { 32768.0f, 32768.0f, 32768.0f, 32768.0f };
|
drmp3_f4 scale = DRMP3_VSET(32768.0f);
|
||||||
drmp3_f4 a = DRMP3_VMUL(DRMP3_VLD(&in[i ]), g_scale);
|
drmp3_f4 a = DRMP3_VMUL(DRMP3_VLD(&in[i ]), scale);
|
||||||
drmp3_f4 b = DRMP3_VMUL(DRMP3_VLD(&in[i+4]), g_scale);
|
drmp3_f4 b = DRMP3_VMUL(DRMP3_VLD(&in[i+4]), scale);
|
||||||
#if DRMP3_HAVE_SSE
|
#if DRMP3_HAVE_SSE
|
||||||
static const drmp3_f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f };
|
drmp3_f4 s16max = DRMP3_VSET( 32767.0f);
|
||||||
static const drmp3_f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f };
|
drmp3_f4 s16min = DRMP3_VSET(-32768.0f);
|
||||||
__m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)),
|
__m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, s16max), s16min)),
|
||||||
_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min)));
|
_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, s16max), s16min)));
|
||||||
out[i ] = (drmp3_int16)_mm_extract_epi16(pcm8, 0);
|
out[i ] = (drmp3_int16)_mm_extract_epi16(pcm8, 0);
|
||||||
out[i+1] = (drmp3_int16)_mm_extract_epi16(pcm8, 1);
|
out[i+1] = (drmp3_int16)_mm_extract_epi16(pcm8, 1);
|
||||||
out[i+2] = (drmp3_int16)_mm_extract_epi16(pcm8, 2);
|
out[i+2] = (drmp3_int16)_mm_extract_epi16(pcm8, 2);
|
||||||
|
|
@ -3779,6 +3810,15 @@ DIFFERENCES BETWEEN minimp3 AND dr_mp3
|
||||||
/*
|
/*
|
||||||
REVISION HISTORY
|
REVISION HISTORY
|
||||||
================
|
================
|
||||||
|
v0.4.7 - 2019-07-28
|
||||||
|
- Fix a compiler error.
|
||||||
|
|
||||||
|
v0.4.6 - 2019-06-14
|
||||||
|
- Fix a compiler error.
|
||||||
|
|
||||||
|
v0.4.5 - 2019-06-06
|
||||||
|
- Bring up to date with minimp3.
|
||||||
|
|
||||||
v0.4.4 - 2019-05-06
|
v0.4.4 - 2019-05-06
|
||||||
- Fixes to the VC6 build.
|
- Fixes to the VC6 build.
|
||||||
|
|
||||||
|
|
|
||||||
17
src/external/dr_wav.h
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file.
|
WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||||
dr_wav - v0.9.1 - 2019-05-05
|
dr_wav - v0.9.2 - 2019-05-21
|
||||||
|
|
||||||
David Reid - mackron@gmail.com
|
David Reid - mackron@gmail.com
|
||||||
*/
|
*/
|
||||||
|
|
@ -2040,7 +2040,7 @@ drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc
|
||||||
|
|
||||||
drwav_uint32 drwav_riff_chunk_size_riff(drwav_uint64 dataChunkSize)
|
drwav_uint32 drwav_riff_chunk_size_riff(drwav_uint64 dataChunkSize)
|
||||||
{
|
{
|
||||||
if (dataChunkSize <= (0xFFFFFFFF - 36)) {
|
if (dataChunkSize <= (0xFFFFFFFFUL - 36)) {
|
||||||
return 36 + (drwav_uint32)dataChunkSize;
|
return 36 + (drwav_uint32)dataChunkSize;
|
||||||
} else {
|
} else {
|
||||||
return 0xFFFFFFFF;
|
return 0xFFFFFFFF;
|
||||||
|
|
@ -2049,10 +2049,10 @@ drwav_uint32 drwav_riff_chunk_size_riff(drwav_uint64 dataChunkSize)
|
||||||
|
|
||||||
drwav_uint32 drwav_data_chunk_size_riff(drwav_uint64 dataChunkSize)
|
drwav_uint32 drwav_data_chunk_size_riff(drwav_uint64 dataChunkSize)
|
||||||
{
|
{
|
||||||
if (dataChunkSize <= 0xFFFFFFFF) {
|
if (dataChunkSize <= 0xFFFFFFFFUL) {
|
||||||
return (drwav_uint32)dataChunkSize;
|
return (drwav_uint32)dataChunkSize;
|
||||||
} else {
|
} else {
|
||||||
return 0xFFFFFFFF;
|
return 0xFFFFFFFFUL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2121,7 +2121,7 @@ drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pF
|
||||||
so for the sake of simplicity I'm not doing any validation for that.
|
so for the sake of simplicity I'm not doing any validation for that.
|
||||||
*/
|
*/
|
||||||
if (pFormat->container == drwav_container_riff) {
|
if (pFormat->container == drwav_container_riff) {
|
||||||
if (initialDataChunkSize > (0xFFFFFFFF - 36)) {
|
if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) {
|
||||||
return DRWAV_FALSE; /* Not enough room to store every sample. */
|
return DRWAV_FALSE; /* Not enough room to store every sample. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3195,8 +3195,8 @@ void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCou
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < sampleCount; ++i) {
|
for (i = 0; i < sampleCount; ++i) {
|
||||||
int x = pIn[i];
|
int x = pIn[i];
|
||||||
r = x - 128;
|
r = x << 8;
|
||||||
r = r << 8;
|
r = r - 32768;
|
||||||
pOut[i] = (short)r;
|
pOut[i] = (short)r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4675,6 +4675,9 @@ void drwav_free(void* pDataReturnedByOpenAndRead)
|
||||||
/*
|
/*
|
||||||
REVISION HISTORY
|
REVISION HISTORY
|
||||||
================
|
================
|
||||||
|
v0.9.2 - 2019-05-21
|
||||||
|
- Fix warnings.
|
||||||
|
|
||||||
v0.9.1 - 2019-05-05
|
v0.9.1 - 2019-05-05
|
||||||
- Add support for C89.
|
- Add support for C89.
|
||||||
- Change license to choice of public domain or MIT-0.
|
- Change license to choice of public domain or MIT-0.
|
||||||
|
|
|
||||||
1215
src/external/miniaudio.h
vendored
20
src/external/stb_image.h
vendored
|
|
@ -1,4 +1,4 @@
|
||||||
/* stb_image - v2.22 - public domain image loader - http://nothings.org/stb
|
/* stb_image - v2.23 - public domain image loader - http://nothings.org/stb
|
||||||
no warranty implied; use at your own risk
|
no warranty implied; use at your own risk
|
||||||
|
|
||||||
Do this:
|
Do this:
|
||||||
|
|
@ -48,6 +48,7 @@ LICENSE
|
||||||
|
|
||||||
RECENT REVISION HISTORY:
|
RECENT REVISION HISTORY:
|
||||||
|
|
||||||
|
2.23 (2019-08-11) fix clang static analysis warning
|
||||||
2.22 (2019-03-04) gif fixes, fix warnings
|
2.22 (2019-03-04) gif fixes, fix warnings
|
||||||
2.21 (2019-02-25) fix typo in comment
|
2.21 (2019-02-25) fix typo in comment
|
||||||
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
|
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
|
||||||
|
|
@ -5079,7 +5080,7 @@ static int stbi__high_bit(unsigned int z)
|
||||||
if (z >= 0x00100) { n += 8; z >>= 8; }
|
if (z >= 0x00100) { n += 8; z >>= 8; }
|
||||||
if (z >= 0x00010) { n += 4; z >>= 4; }
|
if (z >= 0x00010) { n += 4; z >>= 4; }
|
||||||
if (z >= 0x00004) { n += 2; z >>= 2; }
|
if (z >= 0x00004) { n += 2; z >>= 2; }
|
||||||
if (z >= 0x00002) { n += 1; z >>= 1; }
|
if (z >= 0x00002) { n += 1;/* >>= 1;*/ }
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5237,7 +5238,10 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
|
||||||
psize = (info.offset - 14 - info.hsz) >> 2;
|
psize = (info.offset - 14 - info.hsz) >> 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->img_n = ma ? 4 : 3;
|
if (info.bpp == 24 && ma == 0xff000000)
|
||||||
|
s->img_n = 3;
|
||||||
|
else
|
||||||
|
s->img_n = ma ? 4 : 3;
|
||||||
if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
|
if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
|
||||||
target = req_comp;
|
target = req_comp;
|
||||||
else
|
else
|
||||||
|
|
@ -5547,6 +5551,8 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req
|
||||||
int RLE_repeating = 0;
|
int RLE_repeating = 0;
|
||||||
int read_next_pixel = 1;
|
int read_next_pixel = 1;
|
||||||
STBI_NOTUSED(ri);
|
STBI_NOTUSED(ri);
|
||||||
|
STBI_NOTUSED(tga_x_origin); // @TODO
|
||||||
|
STBI_NOTUSED(tga_y_origin); // @TODO
|
||||||
|
|
||||||
// do a tiny bit of precessing
|
// do a tiny bit of precessing
|
||||||
if ( tga_image_type >= 8 )
|
if ( tga_image_type >= 8 )
|
||||||
|
|
@ -5710,6 +5716,7 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req
|
||||||
// Microsoft's C compilers happy... [8^(
|
// Microsoft's C compilers happy... [8^(
|
||||||
tga_palette_start = tga_palette_len = tga_palette_bits =
|
tga_palette_start = tga_palette_len = tga_palette_bits =
|
||||||
tga_x_origin = tga_y_origin = 0;
|
tga_x_origin = tga_y_origin = 0;
|
||||||
|
STBI_NOTUSED(tga_palette_start);
|
||||||
// OK, done
|
// OK, done
|
||||||
return tga_data;
|
return tga_data;
|
||||||
}
|
}
|
||||||
|
|
@ -6936,7 +6943,12 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
|
||||||
return 0;
|
return 0;
|
||||||
if (x) *x = s->img_x;
|
if (x) *x = s->img_x;
|
||||||
if (y) *y = s->img_y;
|
if (y) *y = s->img_y;
|
||||||
if (comp) *comp = info.ma ? 4 : 3;
|
if (comp) {
|
||||||
|
if (info.bpp == 24 && info.ma == 0xff000000)
|
||||||
|
*comp = 3;
|
||||||
|
else
|
||||||
|
*comp = info.ma ? 4 : 3;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
11
src/external/stb_image_write.h
vendored
|
|
@ -1,4 +1,4 @@
|
||||||
/* stb_image_write - v1.13 - public domain - http://nothings.org/stb/stb_image_write.h
|
/* stb_image_write - v1.13 - public domain - http://nothings.org/stb
|
||||||
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
|
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
|
||||||
no warranty implied; use at your own risk
|
no warranty implied; use at your own risk
|
||||||
|
|
||||||
|
|
@ -10,11 +10,6 @@
|
||||||
|
|
||||||
Will probably not work correctly with strict-aliasing optimizations.
|
Will probably not work correctly with strict-aliasing optimizations.
|
||||||
|
|
||||||
If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause
|
|
||||||
compilation warnings or even errors. To avoid this, also before #including,
|
|
||||||
|
|
||||||
#define STBI_MSC_SECURE_CRT
|
|
||||||
|
|
||||||
ABOUT:
|
ABOUT:
|
||||||
|
|
||||||
This header file is a library for writing images to C stdio or a callback.
|
This header file is a library for writing images to C stdio or a callback.
|
||||||
|
|
@ -873,7 +868,7 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
|
||||||
unsigned int bitbuf=0;
|
unsigned int bitbuf=0;
|
||||||
int i,j, bitcount=0;
|
int i,j, bitcount=0;
|
||||||
unsigned char *out = NULL;
|
unsigned char *out = NULL;
|
||||||
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
|
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**));
|
||||||
if (hash_table == NULL)
|
if (hash_table == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (quality < 5) quality = 5;
|
if (quality < 5) quality = 5;
|
||||||
|
|
@ -1535,6 +1530,8 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
|
||||||
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
|
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
|
||||||
/* Revision history
|
/* Revision history
|
||||||
|
1.11 (2019-08-11)
|
||||||
|
|
||||||
1.10 (2019-02-07)
|
1.10 (2019-02-07)
|
||||||
support utf8 filenames in Windows; fix warnings and platform ifdefs
|
support utf8 filenames in Windows; fix warnings and platform ifdefs
|
||||||
1.09 (2018-02-11)
|
1.09 (2018-02-11)
|
||||||
|
|
|
||||||
61
src/external/stb_perlin.h
vendored
|
|
@ -81,6 +81,7 @@ extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap
|
||||||
extern float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves);
|
extern float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves);
|
||||||
extern float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
|
extern float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
|
||||||
extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
|
extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
|
||||||
|
extern float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -321,6 +322,66 @@ float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity,
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed)
|
||||||
|
{
|
||||||
|
float u,v,w;
|
||||||
|
float n000,n001,n010,n011,n100,n101,n110,n111;
|
||||||
|
float n00,n01,n10,n11;
|
||||||
|
float n0,n1;
|
||||||
|
|
||||||
|
int px = stb__perlin_fastfloor(x);
|
||||||
|
int py = stb__perlin_fastfloor(y);
|
||||||
|
int pz = stb__perlin_fastfloor(z);
|
||||||
|
int x_wrap2 = (x_wrap ? x_wrap : 256);
|
||||||
|
int y_wrap2 = (y_wrap ? y_wrap : 256);
|
||||||
|
int z_wrap2 = (z_wrap ? z_wrap : 256);
|
||||||
|
int x0 = px % x_wrap2, x1;
|
||||||
|
int y0 = py % y_wrap2, y1;
|
||||||
|
int z0 = pz % z_wrap2, z1;
|
||||||
|
int r0,r1, r00,r01,r10,r11;
|
||||||
|
|
||||||
|
if (x0 < 0) x0 += x_wrap2;
|
||||||
|
if (y0 < 0) y0 += y_wrap2;
|
||||||
|
if (z0 < 0) z0 += z_wrap2;
|
||||||
|
x1 = (x0+1) % x_wrap2;
|
||||||
|
y1 = (y0+1) % y_wrap2;
|
||||||
|
z1 = (z0+1) % z_wrap2;
|
||||||
|
|
||||||
|
#define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a)
|
||||||
|
|
||||||
|
x -= px; u = stb__perlin_ease(x);
|
||||||
|
y -= py; v = stb__perlin_ease(y);
|
||||||
|
z -= pz; w = stb__perlin_ease(z);
|
||||||
|
|
||||||
|
r0 = stb__perlin_randtab[x0];
|
||||||
|
r0 = stb__perlin_randtab[r0+seed];
|
||||||
|
r1 = stb__perlin_randtab[x1];
|
||||||
|
r1 = stb__perlin_randtab[r1+seed];
|
||||||
|
|
||||||
|
r00 = stb__perlin_randtab[r0+y0];
|
||||||
|
r01 = stb__perlin_randtab[r0+y1];
|
||||||
|
r10 = stb__perlin_randtab[r1+y0];
|
||||||
|
r11 = stb__perlin_randtab[r1+y1];
|
||||||
|
|
||||||
|
n000 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z0], x , y , z );
|
||||||
|
n001 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z1], x , y , z-1 );
|
||||||
|
n010 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z0], x , y-1, z );
|
||||||
|
n011 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z1], x , y-1, z-1 );
|
||||||
|
n100 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z0], x-1, y , z );
|
||||||
|
n101 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z1], x-1, y , z-1 );
|
||||||
|
n110 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z0], x-1, y-1, z );
|
||||||
|
n111 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z1], x-1, y-1, z-1 );
|
||||||
|
|
||||||
|
n00 = stb__perlin_lerp(n000,n001,w);
|
||||||
|
n01 = stb__perlin_lerp(n010,n011,w);
|
||||||
|
n10 = stb__perlin_lerp(n100,n101,w);
|
||||||
|
n11 = stb__perlin_lerp(n110,n111,w);
|
||||||
|
|
||||||
|
n0 = stb__perlin_lerp(n00,n01,v);
|
||||||
|
n1 = stb__perlin_lerp(n10,n11,v);
|
||||||
|
|
||||||
|
return stb__perlin_lerp(n0,n1,u);
|
||||||
|
}
|
||||||
#endif // STB_PERLIN_IMPLEMENTATION
|
#endif // STB_PERLIN_IMPLEMENTATION
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
30
src/external/stb_truetype.h
vendored
|
|
@ -1,5 +1,5 @@
|
||||||
// stb_truetype.h - v1.21 - public domain
|
// stb_truetype.h - v1.22 - public domain
|
||||||
// authored from 2009-2016 by Sean Barrett / RAD Game Tools
|
// authored from 2009-2019 by Sean Barrett / RAD Game Tools
|
||||||
//
|
//
|
||||||
// This library processes TrueType files:
|
// This library processes TrueType files:
|
||||||
// parse files
|
// parse files
|
||||||
|
|
@ -46,9 +46,11 @@
|
||||||
// Rob Loach Cort Stratton
|
// Rob Loach Cort Stratton
|
||||||
// Kenney Phillis Jr. github:oyvindjam
|
// Kenney Phillis Jr. github:oyvindjam
|
||||||
// Brian Costabile github:vassvik
|
// Brian Costabile github:vassvik
|
||||||
|
// Ken Voskuil (kaesve) Ryan Griege
|
||||||
//
|
//
|
||||||
// VERSION HISTORY
|
// VERSION HISTORY
|
||||||
//
|
//
|
||||||
|
// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
|
||||||
// 1.21 (2019-02-25) fix warning
|
// 1.21 (2019-02-25) fix warning
|
||||||
// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
|
// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
|
||||||
// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
|
// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
|
||||||
|
|
@ -2540,8 +2542,7 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int
|
||||||
|
|
||||||
if (info->gpos)
|
if (info->gpos)
|
||||||
xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
|
xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
|
||||||
|
else if (info->kern)
|
||||||
if (info->kern)
|
|
||||||
xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
|
xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
|
||||||
|
|
||||||
return xAdvance;
|
return xAdvance;
|
||||||
|
|
@ -3968,6 +3969,7 @@ static float stbtt__oversample_shift(int oversample)
|
||||||
STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
||||||
{
|
{
|
||||||
int i,j,k;
|
int i,j,k;
|
||||||
|
int missing_glyph_added = 0;
|
||||||
|
|
||||||
k=0;
|
k=0;
|
||||||
for (i=0; i < num_ranges; ++i) {
|
for (i=0; i < num_ranges; ++i) {
|
||||||
|
|
@ -3979,7 +3981,7 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb
|
||||||
int x0,y0,x1,y1;
|
int x0,y0,x1,y1;
|
||||||
int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
|
int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
|
||||||
int glyph = stbtt_FindGlyphIndex(info, codepoint);
|
int glyph = stbtt_FindGlyphIndex(info, codepoint);
|
||||||
if (glyph == 0 && spc->skip_missing) {
|
if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) {
|
||||||
rects[k].w = rects[k].h = 0;
|
rects[k].w = rects[k].h = 0;
|
||||||
} else {
|
} else {
|
||||||
stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
|
stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
|
||||||
|
|
@ -3989,6 +3991,8 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb
|
||||||
&x0,&y0,&x1,&y1);
|
&x0,&y0,&x1,&y1);
|
||||||
rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
|
rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
|
||||||
rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
|
rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
|
||||||
|
if (glyph == 0)
|
||||||
|
missing_glyph_added = 1;
|
||||||
}
|
}
|
||||||
++k;
|
++k;
|
||||||
}
|
}
|
||||||
|
|
@ -4023,7 +4027,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info
|
||||||
// rects array must be big enough to accommodate all characters in the given ranges
|
// rects array must be big enough to accommodate all characters in the given ranges
|
||||||
STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
||||||
{
|
{
|
||||||
int i,j,k, return_value = 1;
|
int i,j,k, missing_glyph = -1, return_value = 1;
|
||||||
|
|
||||||
// save current values
|
// save current values
|
||||||
int old_h_over = spc->h_oversample;
|
int old_h_over = spc->h_oversample;
|
||||||
|
|
@ -4088,6 +4092,13 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const
|
||||||
bc->yoff = (float) y0 * recip_v + sub_y;
|
bc->yoff = (float) y0 * recip_v + sub_y;
|
||||||
bc->xoff2 = (x0 + r->w) * recip_h + sub_x;
|
bc->xoff2 = (x0 + r->w) * recip_h + sub_x;
|
||||||
bc->yoff2 = (y0 + r->h) * recip_v + sub_y;
|
bc->yoff2 = (y0 + r->h) * recip_v + sub_y;
|
||||||
|
|
||||||
|
if (glyph == 0)
|
||||||
|
missing_glyph = j;
|
||||||
|
} else if (spc->skip_missing) {
|
||||||
|
return_value = 0;
|
||||||
|
} else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) {
|
||||||
|
ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph];
|
||||||
} else {
|
} else {
|
||||||
return_value = 0; // if any fail, report failure
|
return_value = 0; // if any fail, report failure
|
||||||
}
|
}
|
||||||
|
|
@ -4389,12 +4400,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
||||||
int w,h;
|
int w,h;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
// if one scale is 0, use same scale for both
|
if (scale == 0) return NULL;
|
||||||
if (scale_x == 0) scale_x = scale_y;
|
|
||||||
if (scale_y == 0) {
|
|
||||||
if (scale_x == 0) return NULL; // if both scales are 0, return NULL
|
|
||||||
scale_y = scale_x;
|
|
||||||
}
|
|
||||||
|
|
||||||
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
|
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
|
||||||
|
|
||||||
|
|
|
||||||
19
src/external/tinyobj_loader_c.h
vendored
|
|
@ -453,6 +453,11 @@ static void parseFloat3(float *x, float *y, float *z, const char **token) {
|
||||||
(*z) = parseFloat(token);
|
(*z) = parseFloat(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int my_strnlen(const char *s, unsigned int n) {
|
||||||
|
const char *p = memchr(s, 0, n);
|
||||||
|
return p ? (unsigned int)(p - s) : n;
|
||||||
|
}
|
||||||
|
|
||||||
static char *my_strdup(const char *s, unsigned int max_length) {
|
static char *my_strdup(const char *s, unsigned int max_length) {
|
||||||
char *d;
|
char *d;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
|
|
@ -478,15 +483,13 @@ static char *my_strndup(const char *s, unsigned int len) {
|
||||||
if (s == NULL) return NULL;
|
if (s == NULL) return NULL;
|
||||||
if (len == 0) return NULL;
|
if (len == 0) return NULL;
|
||||||
|
|
||||||
d = (char *)TINYOBJ_MALLOC(len + 1); /* + '\0' */
|
slen = my_strnlen(s, len);
|
||||||
slen = strlen(s);
|
d = (char *)TINYOBJ_MALLOC(slen + 1); /* + '\0' */
|
||||||
if (slen < len) {
|
if (!d) {
|
||||||
memcpy(d, s, slen);
|
return NULL;
|
||||||
d[slen] = '\0';
|
|
||||||
} else {
|
|
||||||
memcpy(d, s, len);
|
|
||||||
d[len] = '\0';
|
|
||||||
}
|
}
|
||||||
|
memcpy(d, s, slen);
|
||||||
|
d[slen] = '\0';
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
* #define GESTURES_IMPLEMENTATION
|
* #define GESTURES_IMPLEMENTATION
|
||||||
* Generates the implementation of the library into the included file.
|
* Generates the implementation of the library into the included file.
|
||||||
* If not defined, the library is in header only mode and can be included in other headers
|
* If not defined, the library is in header only mode and can be included in other headers
|
||||||
* or source files without problems. But only ONE file should hold the implementation.
|
* or source files without problems. But only ONE file should hold the implementation.
|
||||||
*
|
*
|
||||||
* #define GESTURES_STANDALONE
|
* #define GESTURES_STANDALONE
|
||||||
|
|
@ -216,8 +216,8 @@ static float pinchDistance = 0.0f; // PINCH displacement distance (
|
||||||
|
|
||||||
static int currentGesture = GESTURE_NONE; // Current detected gesture
|
static int currentGesture = GESTURE_NONE; // Current detected gesture
|
||||||
|
|
||||||
// Enabled gestures flags, all gestures enabled by default
|
// Enabled gestures flags, all gestures enabled by default
|
||||||
static unsigned int enabledGestures = 0b0000001111111111;
|
static unsigned int enabledGestures = 0b0000001111111111;
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module specific Functions Declaration
|
// Module specific Functions Declaration
|
||||||
|
|
@ -251,13 +251,13 @@ void ProcessGestureEvent(GestureEvent event)
|
||||||
{
|
{
|
||||||
// Reset required variables
|
// Reset required variables
|
||||||
pointCount = event.pointCount; // Required on UpdateGestures()
|
pointCount = event.pointCount; // Required on UpdateGestures()
|
||||||
|
|
||||||
if (pointCount < 2)
|
if (pointCount < 2)
|
||||||
{
|
{
|
||||||
if (event.touchAction == TOUCH_DOWN)
|
if (event.touchAction == TOUCH_DOWN)
|
||||||
{
|
{
|
||||||
tapCounter++; // Tap counter
|
tapCounter++; // Tap counter
|
||||||
|
|
||||||
// Detect GESTURE_DOUBLE_TAP
|
// Detect GESTURE_DOUBLE_TAP
|
||||||
if ((currentGesture == GESTURE_NONE) && (tapCounter >= 2) && ((GetCurrentTime() - eventTime) < TAP_TIMEOUT) && (Vector2Distance(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE))
|
if ((currentGesture == GESTURE_NONE) && (tapCounter >= 2) && ((GetCurrentTime() - eventTime) < TAP_TIMEOUT) && (Vector2Distance(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE))
|
||||||
{
|
{
|
||||||
|
|
@ -269,15 +269,15 @@ void ProcessGestureEvent(GestureEvent event)
|
||||||
tapCounter = 1;
|
tapCounter = 1;
|
||||||
currentGesture = GESTURE_TAP;
|
currentGesture = GESTURE_TAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
touchDownPosition = event.position[0];
|
touchDownPosition = event.position[0];
|
||||||
touchDownDragPosition = event.position[0];
|
touchDownDragPosition = event.position[0];
|
||||||
|
|
||||||
touchUpPosition = touchDownPosition;
|
touchUpPosition = touchDownPosition;
|
||||||
eventTime = GetCurrentTime();
|
eventTime = GetCurrentTime();
|
||||||
|
|
||||||
firstTouchId = event.pointerId[0];
|
firstTouchId = event.pointerId[0];
|
||||||
|
|
||||||
dragVector = (Vector2){ 0.0f, 0.0f };
|
dragVector = (Vector2){ 0.0f, 0.0f };
|
||||||
}
|
}
|
||||||
else if (event.touchAction == TOUCH_UP)
|
else if (event.touchAction == TOUCH_UP)
|
||||||
|
|
@ -287,15 +287,15 @@ void ProcessGestureEvent(GestureEvent event)
|
||||||
// NOTE: dragIntensity dependend on the resolution of the screen
|
// NOTE: dragIntensity dependend on the resolution of the screen
|
||||||
dragDistance = Vector2Distance(touchDownPosition, touchUpPosition);
|
dragDistance = Vector2Distance(touchDownPosition, touchUpPosition);
|
||||||
dragIntensity = dragDistance/(float)((GetCurrentTime() - swipeTime));
|
dragIntensity = dragDistance/(float)((GetCurrentTime() - swipeTime));
|
||||||
|
|
||||||
startMoving = false;
|
startMoving = false;
|
||||||
|
|
||||||
// Detect GESTURE_SWIPE
|
// Detect GESTURE_SWIPE
|
||||||
if ((dragIntensity > FORCE_TO_SWIPE) && (firstTouchId == event.pointerId[0]))
|
if ((dragIntensity > FORCE_TO_SWIPE) && (firstTouchId == event.pointerId[0]))
|
||||||
{
|
{
|
||||||
// NOTE: Angle should be inverted in Y
|
// NOTE: Angle should be inverted in Y
|
||||||
dragAngle = 360.0f - Vector2Angle(touchDownPosition, touchUpPosition);
|
dragAngle = 360.0f - Vector2Angle(touchDownPosition, touchUpPosition);
|
||||||
|
|
||||||
if ((dragAngle < 30) || (dragAngle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right
|
if ((dragAngle < 30) || (dragAngle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right
|
||||||
else if ((dragAngle > 30) && (dragAngle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up
|
else if ((dragAngle > 30) && (dragAngle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up
|
||||||
else if ((dragAngle > 120) && (dragAngle < 210)) currentGesture = GESTURE_SWIPE_LEFT; // Left
|
else if ((dragAngle > 120) && (dragAngle < 210)) currentGesture = GESTURE_SWIPE_LEFT; // Left
|
||||||
|
|
@ -307,31 +307,31 @@ void ProcessGestureEvent(GestureEvent event)
|
||||||
dragDistance = 0.0f;
|
dragDistance = 0.0f;
|
||||||
dragIntensity = 0.0f;
|
dragIntensity = 0.0f;
|
||||||
dragAngle = 0.0f;
|
dragAngle = 0.0f;
|
||||||
|
|
||||||
currentGesture = GESTURE_NONE;
|
currentGesture = GESTURE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
touchDownDragPosition = (Vector2){ 0.0f, 0.0f };
|
touchDownDragPosition = (Vector2){ 0.0f, 0.0f };
|
||||||
pointCount = 0;
|
pointCount = 0;
|
||||||
}
|
}
|
||||||
else if (event.touchAction == TOUCH_MOVE)
|
else if (event.touchAction == TOUCH_MOVE)
|
||||||
{
|
{
|
||||||
if (currentGesture == GESTURE_DRAG) eventTime = GetCurrentTime();
|
if (currentGesture == GESTURE_DRAG) eventTime = GetCurrentTime();
|
||||||
|
|
||||||
if (!startMoving)
|
if (!startMoving)
|
||||||
{
|
{
|
||||||
swipeTime = GetCurrentTime();
|
swipeTime = GetCurrentTime();
|
||||||
startMoving = true;
|
startMoving = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
moveDownPosition = event.position[0];
|
moveDownPosition = event.position[0];
|
||||||
|
|
||||||
if (currentGesture == GESTURE_HOLD)
|
if (currentGesture == GESTURE_HOLD)
|
||||||
{
|
{
|
||||||
if (resetHold) touchDownPosition = event.position[0];
|
if (resetHold) touchDownPosition = event.position[0];
|
||||||
|
|
||||||
resetHold = false;
|
resetHold = false;
|
||||||
|
|
||||||
// Detect GESTURE_DRAG
|
// Detect GESTURE_DRAG
|
||||||
if (Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_DRAG)
|
if (Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_DRAG)
|
||||||
{
|
{
|
||||||
|
|
@ -339,7 +339,7 @@ void ProcessGestureEvent(GestureEvent event)
|
||||||
currentGesture = GESTURE_DRAG;
|
currentGesture = GESTURE_DRAG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dragVector.x = moveDownPosition.x - touchDownDragPosition.x;
|
dragVector.x = moveDownPosition.x - touchDownDragPosition.x;
|
||||||
dragVector.y = moveDownPosition.y - touchDownDragPosition.y;
|
dragVector.y = moveDownPosition.y - touchDownDragPosition.y;
|
||||||
}
|
}
|
||||||
|
|
@ -350,28 +350,28 @@ void ProcessGestureEvent(GestureEvent event)
|
||||||
{
|
{
|
||||||
touchDownPosition = event.position[0];
|
touchDownPosition = event.position[0];
|
||||||
touchDownPosition2 = event.position[1];
|
touchDownPosition2 = event.position[1];
|
||||||
|
|
||||||
//pinchDistance = Vector2Distance(touchDownPosition, touchDownPosition2);
|
//pinchDistance = Vector2Distance(touchDownPosition, touchDownPosition2);
|
||||||
|
|
||||||
pinchVector.x = touchDownPosition2.x - touchDownPosition.x;
|
pinchVector.x = touchDownPosition2.x - touchDownPosition.x;
|
||||||
pinchVector.y = touchDownPosition2.y - touchDownPosition.y;
|
pinchVector.y = touchDownPosition2.y - touchDownPosition.y;
|
||||||
|
|
||||||
currentGesture = GESTURE_HOLD;
|
currentGesture = GESTURE_HOLD;
|
||||||
timeHold = GetCurrentTime();
|
timeHold = GetCurrentTime();
|
||||||
}
|
}
|
||||||
else if (event.touchAction == TOUCH_MOVE)
|
else if (event.touchAction == TOUCH_MOVE)
|
||||||
{
|
{
|
||||||
pinchDistance = Vector2Distance(moveDownPosition, moveDownPosition2);
|
pinchDistance = Vector2Distance(moveDownPosition, moveDownPosition2);
|
||||||
|
|
||||||
touchDownPosition = moveDownPosition;
|
touchDownPosition = moveDownPosition;
|
||||||
touchDownPosition2 = moveDownPosition2;
|
touchDownPosition2 = moveDownPosition2;
|
||||||
|
|
||||||
moveDownPosition = event.position[0];
|
moveDownPosition = event.position[0];
|
||||||
moveDownPosition2 = event.position[1];
|
moveDownPosition2 = event.position[1];
|
||||||
|
|
||||||
pinchVector.x = moveDownPosition2.x - moveDownPosition.x;
|
pinchVector.x = moveDownPosition2.x - moveDownPosition.x;
|
||||||
pinchVector.y = moveDownPosition2.y - moveDownPosition.y;
|
pinchVector.y = moveDownPosition2.y - moveDownPosition.y;
|
||||||
|
|
||||||
if ((Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_PINCH) || (Vector2Distance(touchDownPosition2, moveDownPosition2) >= MINIMUM_PINCH))
|
if ((Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_PINCH) || (Vector2Distance(touchDownPosition2, moveDownPosition2) >= MINIMUM_PINCH))
|
||||||
{
|
{
|
||||||
if ((Vector2Distance(moveDownPosition, moveDownPosition2) - pinchDistance) < 0) currentGesture = GESTURE_PINCH_IN;
|
if ((Vector2Distance(moveDownPosition, moveDownPosition2) - pinchDistance) < 0) currentGesture = GESTURE_PINCH_IN;
|
||||||
|
|
@ -382,7 +382,7 @@ void ProcessGestureEvent(GestureEvent event)
|
||||||
currentGesture = GESTURE_HOLD;
|
currentGesture = GESTURE_HOLD;
|
||||||
timeHold = GetCurrentTime();
|
timeHold = GetCurrentTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Angle should be inverted in Y
|
// NOTE: Angle should be inverted in Y
|
||||||
pinchAngle = 360.0f - Vector2Angle(moveDownPosition, moveDownPosition2);
|
pinchAngle = 360.0f - Vector2Angle(moveDownPosition, moveDownPosition2);
|
||||||
}
|
}
|
||||||
|
|
@ -392,7 +392,7 @@ void ProcessGestureEvent(GestureEvent event)
|
||||||
pinchAngle = 0.0f;
|
pinchAngle = 0.0f;
|
||||||
pinchVector = (Vector2){ 0.0f, 0.0f };
|
pinchVector = (Vector2){ 0.0f, 0.0f };
|
||||||
pointCount = 0;
|
pointCount = 0;
|
||||||
|
|
||||||
currentGesture = GESTURE_NONE;
|
currentGesture = GESTURE_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -409,14 +409,14 @@ void UpdateGestures(void)
|
||||||
currentGesture = GESTURE_HOLD;
|
currentGesture = GESTURE_HOLD;
|
||||||
timeHold = GetCurrentTime();
|
timeHold = GetCurrentTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((GetCurrentTime() - eventTime) > TAP_TIMEOUT) && (currentGesture == GESTURE_DRAG) && (pointCount < 2))
|
if (((GetCurrentTime() - eventTime) > TAP_TIMEOUT) && (currentGesture == GESTURE_DRAG) && (pointCount < 2))
|
||||||
{
|
{
|
||||||
currentGesture = GESTURE_HOLD;
|
currentGesture = GESTURE_HOLD;
|
||||||
timeHold = GetCurrentTime();
|
timeHold = GetCurrentTime();
|
||||||
resetHold = true;
|
resetHold = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect GESTURE_NONE
|
// Detect GESTURE_NONE
|
||||||
if ((currentGesture == GESTURE_SWIPE_RIGHT) || (currentGesture == GESTURE_SWIPE_UP) || (currentGesture == GESTURE_SWIPE_LEFT) || (currentGesture == GESTURE_SWIPE_DOWN))
|
if ((currentGesture == GESTURE_SWIPE_RIGHT) || (currentGesture == GESTURE_SWIPE_UP) || (currentGesture == GESTURE_SWIPE_LEFT) || (currentGesture == GESTURE_SWIPE_DOWN))
|
||||||
{
|
{
|
||||||
|
|
@ -428,7 +428,7 @@ void UpdateGestures(void)
|
||||||
int GetTouchPointsCount(void)
|
int GetTouchPointsCount(void)
|
||||||
{
|
{
|
||||||
// NOTE: point count is calculated when ProcessGestureEvent(GestureEvent event) is called
|
// NOTE: point count is calculated when ProcessGestureEvent(GestureEvent event) is called
|
||||||
|
|
||||||
return pointCount;
|
return pointCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -443,11 +443,11 @@ int GetGestureDetected(void)
|
||||||
float GetGestureHoldDuration(void)
|
float GetGestureHoldDuration(void)
|
||||||
{
|
{
|
||||||
// NOTE: time is calculated on current gesture HOLD
|
// NOTE: time is calculated on current gesture HOLD
|
||||||
|
|
||||||
double time = 0.0;
|
double time = 0.0;
|
||||||
|
|
||||||
if (currentGesture == GESTURE_HOLD) time = GetCurrentTime() - timeHold;
|
if (currentGesture == GESTURE_HOLD) time = GetCurrentTime() - timeHold;
|
||||||
|
|
||||||
return (float)time;
|
return (float)time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -455,7 +455,7 @@ float GetGestureHoldDuration(void)
|
||||||
Vector2 GetGestureDragVector(void)
|
Vector2 GetGestureDragVector(void)
|
||||||
{
|
{
|
||||||
// NOTE: drag vector is calculated on one touch points TOUCH_MOVE
|
// NOTE: drag vector is calculated on one touch points TOUCH_MOVE
|
||||||
|
|
||||||
return dragVector;
|
return dragVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -464,7 +464,7 @@ Vector2 GetGestureDragVector(void)
|
||||||
float GetGestureDragAngle(void)
|
float GetGestureDragAngle(void)
|
||||||
{
|
{
|
||||||
// NOTE: drag angle is calculated on one touch points TOUCH_UP
|
// NOTE: drag angle is calculated on one touch points TOUCH_UP
|
||||||
|
|
||||||
return dragAngle;
|
return dragAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -473,7 +473,7 @@ Vector2 GetGesturePinchVector(void)
|
||||||
{
|
{
|
||||||
// NOTE: The position values used for pinchDistance are not modified like the position values of [core.c]-->GetTouchPosition(int index)
|
// NOTE: The position values used for pinchDistance are not modified like the position values of [core.c]-->GetTouchPosition(int index)
|
||||||
// NOTE: pinch distance is calculated on two touch points TOUCH_MOVE
|
// NOTE: pinch distance is calculated on two touch points TOUCH_MOVE
|
||||||
|
|
||||||
return pinchVector;
|
return pinchVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -482,7 +482,7 @@ Vector2 GetGesturePinchVector(void)
|
||||||
float GetGesturePinchAngle(void)
|
float GetGesturePinchAngle(void)
|
||||||
{
|
{
|
||||||
// NOTE: pinch angle is calculated on two touch points TOUCH_MOVE
|
// NOTE: pinch angle is calculated on two touch points TOUCH_MOVE
|
||||||
|
|
||||||
return pinchAngle;
|
return pinchAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -494,7 +494,7 @@ float GetGesturePinchAngle(void)
|
||||||
static float Vector2Angle(Vector2 v1, Vector2 v2)
|
static float Vector2Angle(Vector2 v1, Vector2 v2)
|
||||||
{
|
{
|
||||||
float angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI);
|
float angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI);
|
||||||
|
|
||||||
if (angle < 0) angle += 360.0f;
|
if (angle < 0) angle += 360.0f;
|
||||||
|
|
||||||
return angle;
|
return angle;
|
||||||
|
|
@ -518,13 +518,13 @@ static float Vector2Distance(Vector2 v1, Vector2 v2)
|
||||||
static double GetCurrentTime(void)
|
static double GetCurrentTime(void)
|
||||||
{
|
{
|
||||||
double time = 0;
|
double time = 0;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
unsigned long long int clockFrequency, currentTime;
|
unsigned long long int clockFrequency, currentTime;
|
||||||
|
|
||||||
QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation!
|
QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation!
|
||||||
QueryPerformanceCounter(¤tTime);
|
QueryPerformanceCounter(¤tTime);
|
||||||
|
|
||||||
time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds
|
time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -533,24 +533,24 @@ static double GetCurrentTime(void)
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds
|
uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds
|
||||||
|
|
||||||
time = ((double)nowTime/1000000.0); // Time in miliseconds
|
time = ((double)nowTime/1000000.0); // Time in miliseconds
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
//#define CLOCK_REALTIME CALENDAR_CLOCK // returns UTC time since 1970-01-01
|
//#define CLOCK_REALTIME CALENDAR_CLOCK // returns UTC time since 1970-01-01
|
||||||
//#define CLOCK_MONOTONIC SYSTEM_CLOCK // returns the time since boot time
|
//#define CLOCK_MONOTONIC SYSTEM_CLOCK // returns the time since boot time
|
||||||
|
|
||||||
clock_serv_t cclock;
|
clock_serv_t cclock;
|
||||||
mach_timespec_t now;
|
mach_timespec_t now;
|
||||||
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
|
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
|
||||||
|
|
||||||
// NOTE: OS X does not have clock_gettime(), using clock_get_time()
|
// NOTE: OS X does not have clock_gettime(), using clock_get_time()
|
||||||
clock_get_time(cclock, &now);
|
clock_get_time(cclock, &now);
|
||||||
mach_port_deallocate(mach_task_self(), cclock);
|
mach_port_deallocate(mach_task_self(), cclock);
|
||||||
uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds
|
uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds
|
||||||
|
|
||||||
time = ((double)nowTime/1000000.0); // Time in miliseconds
|
time = ((double)nowTime/1000000.0); // Time in miliseconds
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return time;
|
return time;
|
||||||
|
|
|
||||||
841
src/models.c
|
|
@ -1896,7 +1896,7 @@ static Vector2 TriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3)
|
||||||
static void InitTimer(void)
|
static void InitTimer(void)
|
||||||
{
|
{
|
||||||
srand(time(NULL)); // Initialize random seed
|
srand(time(NULL)); // Initialize random seed
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
QueryPerformanceFrequency((unsigned long long int *) &frequency);
|
QueryPerformanceFrequency((unsigned long long int *) &frequency);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1911,7 +1911,7 @@ static void InitTimer(void)
|
||||||
mach_timebase_info(&timebase);
|
mach_timebase_info(&timebase);
|
||||||
frequency = (timebase.denom*1e9)/timebase.numer;
|
frequency = (timebase.denom*1e9)/timebase.numer;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
baseTime = GetTimeCount(); // Get MONOTONIC clock time offset
|
baseTime = GetTimeCount(); // Get MONOTONIC clock time offset
|
||||||
startTime = GetCurrentTime(); // Get current time
|
startTime = GetCurrentTime(); // Get current time
|
||||||
}
|
}
|
||||||
|
|
@ -1920,7 +1920,7 @@ static void InitTimer(void)
|
||||||
static uint64_t GetTimeCount(void)
|
static uint64_t GetTimeCount(void)
|
||||||
{
|
{
|
||||||
uint64_t value = 0;
|
uint64_t value = 0;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
QueryPerformanceCounter((unsigned long long int *) &value);
|
QueryPerformanceCounter((unsigned long long int *) &value);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
415
src/raudio.c
|
|
@ -124,7 +124,7 @@
|
||||||
// After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds and a
|
// After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds and a
|
||||||
// standard double-buffering system, a 4096 samples buffer has been chosen, it should be enough
|
// standard double-buffering system, a 4096 samples buffer has been chosen, it should be enough
|
||||||
// In case of music-stalls, just increase this number
|
// In case of music-stalls, just increase this number
|
||||||
#define AUDIO_BUFFER_SIZE 4096 // PCM data samples (i.e. 16bit, Mono: 8Kb)
|
#define AUDIO_BUFFER_SIZE 4096 // PCM data samples (i.e. 16bit, Mono: 8Kb)
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Types and Structures Definition
|
// Types and Structures Definition
|
||||||
|
|
@ -189,6 +189,8 @@ void TraceLog(int msgType, const char *text, ...); // Show trace lo
|
||||||
#define DEVICE_CHANNELS 2
|
#define DEVICE_CHANNELS 2
|
||||||
#define DEVICE_SAMPLE_RATE 44100
|
#define DEVICE_SAMPLE_RATE 44100
|
||||||
|
|
||||||
|
#define MAX_AUDIO_BUFFER_POOL_CHANNELS 16
|
||||||
|
|
||||||
typedef enum { AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STREAM } AudioBufferUsage;
|
typedef enum { AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STREAM } AudioBufferUsage;
|
||||||
|
|
||||||
// Audio buffer structure
|
// Audio buffer structure
|
||||||
|
|
@ -196,25 +198,31 @@ typedef enum { AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STREAM } AudioB
|
||||||
// playback device depending on whether or not data is streamed
|
// playback device depending on whether or not data is streamed
|
||||||
struct rAudioBuffer {
|
struct rAudioBuffer {
|
||||||
ma_pcm_converter dsp; // PCM data converter
|
ma_pcm_converter dsp; // PCM data converter
|
||||||
|
|
||||||
float volume; // Audio buffer volume
|
float volume; // Audio buffer volume
|
||||||
float pitch; // Audio buffer pitch
|
float pitch; // Audio buffer pitch
|
||||||
|
|
||||||
bool playing; // Audio buffer state: AUDIO_PLAYING
|
bool playing; // Audio buffer state: AUDIO_PLAYING
|
||||||
bool paused; // Audio buffer state: AUDIO_PAUSED
|
bool paused; // Audio buffer state: AUDIO_PAUSED
|
||||||
bool looping; // Audio buffer looping, always true for AudioStreams
|
bool looping; // Audio buffer looping, always true for AudioStreams
|
||||||
int usage; // Audio buffer usage mode: STATIC or STREAM
|
int usage; // Audio buffer usage mode: STATIC or STREAM
|
||||||
|
|
||||||
bool isSubBufferProcessed[2];
|
bool isSubBufferProcessed[2]; // SubBuffer processed (virtual double buffer)
|
||||||
unsigned int frameCursorPos;
|
unsigned int frameCursorPos; // Frame cursor position
|
||||||
unsigned int bufferSizeInFrames;
|
unsigned int bufferSizeInFrames; // Total buffer size in frames
|
||||||
|
unsigned int totalFramesProcessed; // Total frames processed in this buffer (required for play timming)
|
||||||
rAudioBuffer *next;
|
|
||||||
rAudioBuffer *prev;
|
unsigned char *buffer; // Data buffer, on music stream keeps filling
|
||||||
unsigned char *buffer;
|
|
||||||
|
rAudioBuffer *next; // Next audio buffer on the list
|
||||||
|
rAudioBuffer *prev; // Previous audio buffer on the list
|
||||||
};
|
};
|
||||||
|
|
||||||
#define AudioBuffer rAudioBuffer // HACK: To avoid CoreAudio (macOS) symbol collision
|
#define AudioBuffer rAudioBuffer // HACK: To avoid CoreAudio (macOS) symbol collision
|
||||||
|
|
||||||
|
// Audio buffers are tracked in a linked list
|
||||||
|
static AudioBuffer *firstAudioBuffer = NULL;
|
||||||
|
static AudioBuffer *lastAudioBuffer = NULL;
|
||||||
|
|
||||||
// miniaudio global variables
|
// miniaudio global variables
|
||||||
static ma_context context;
|
static ma_context context;
|
||||||
|
|
@ -223,9 +231,10 @@ static ma_mutex audioLock;
|
||||||
static bool isAudioInitialized = false;
|
static bool isAudioInitialized = false;
|
||||||
static float masterVolume = 1.0f;
|
static float masterVolume = 1.0f;
|
||||||
|
|
||||||
// Audio buffers are tracked in a linked list
|
// Multi channel playback global variables
|
||||||
static AudioBuffer *firstAudioBuffer = NULL;
|
AudioBuffer *audioBufferPool[MAX_AUDIO_BUFFER_POOL_CHANNELS] = { 0 };
|
||||||
static AudioBuffer *lastAudioBuffer = NULL;
|
unsigned int audioBufferPoolCounter = 0;
|
||||||
|
unsigned int audioBufferPoolChannels[MAX_AUDIO_BUFFER_POOL_CHANNELS] = { 0 };
|
||||||
|
|
||||||
// miniaudio functions declaration
|
// miniaudio functions declaration
|
||||||
static void OnLog(ma_context *pContext, ma_device *pDevice, ma_uint32 logLevel, const char *message);
|
static void OnLog(ma_context *pContext, ma_device *pDevice, ma_uint32 logLevel, const char *message);
|
||||||
|
|
@ -247,19 +256,9 @@ void SetAudioBufferPitch(AudioBuffer *buffer, float pitch);
|
||||||
void TrackAudioBuffer(AudioBuffer *buffer);
|
void TrackAudioBuffer(AudioBuffer *buffer);
|
||||||
void UntrackAudioBuffer(AudioBuffer *buffer);
|
void UntrackAudioBuffer(AudioBuffer *buffer);
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Multi channel playback globals
|
// miniaudio functions definitions
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Number of channels in the audio pool
|
|
||||||
#define MAX_AUDIO_BUFFER_POOL_CHANNELS 16
|
|
||||||
|
|
||||||
// Audio buffer pool
|
|
||||||
AudioBuffer *audioBufferPool[MAX_AUDIO_BUFFER_POOL_CHANNELS] = { 0 };
|
|
||||||
|
|
||||||
// These are used to determine the oldest playing channel
|
|
||||||
unsigned long audioBufferPoolCounter = 0;
|
|
||||||
unsigned long audioBufferPoolChannels[MAX_AUDIO_BUFFER_POOL_CHANNELS] = { 0 };
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Log callback function
|
// Log callback function
|
||||||
|
|
@ -290,7 +289,7 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const
|
||||||
if (!audioBuffer->playing || audioBuffer->paused) continue;
|
if (!audioBuffer->playing || audioBuffer->paused) continue;
|
||||||
|
|
||||||
ma_uint32 framesRead = 0;
|
ma_uint32 framesRead = 0;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (framesRead > frameCount)
|
if (framesRead > frameCount)
|
||||||
|
|
@ -303,7 +302,7 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const
|
||||||
|
|
||||||
// Just read as much data as we can from the stream
|
// Just read as much data as we can from the stream
|
||||||
ma_uint32 framesToRead = (frameCount - framesRead);
|
ma_uint32 framesToRead = (frameCount - framesRead);
|
||||||
|
|
||||||
while (framesToRead > 0)
|
while (framesToRead > 0)
|
||||||
{
|
{
|
||||||
float tempBuffer[1024]; // 512 frames for stereo
|
float tempBuffer[1024]; // 512 frames for stereo
|
||||||
|
|
@ -319,6 +318,7 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const
|
||||||
{
|
{
|
||||||
float *framesOut = (float *)pFramesOut + (framesRead*device.playback.channels);
|
float *framesOut = (float *)pFramesOut + (framesRead*device.playback.channels);
|
||||||
float *framesIn = tempBuffer;
|
float *framesIn = tempBuffer;
|
||||||
|
|
||||||
MixAudioFrames(framesOut, framesIn, framesJustRead, audioBuffer->volume);
|
MixAudioFrames(framesOut, framesIn, framesJustRead, audioBuffer->volume);
|
||||||
|
|
||||||
framesToRead -= framesJustRead;
|
framesToRead -= framesJustRead;
|
||||||
|
|
@ -387,7 +387,7 @@ static ma_uint32 OnAudioBufferDSPRead(ma_pcm_converter *pDSP, void *pFramesOut,
|
||||||
{
|
{
|
||||||
if (framesRead >= frameCount) break;
|
if (framesRead >= frameCount) break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (isSubBufferProcessed[currentSubBufferIndex]) break;
|
if (isSubBufferProcessed[currentSubBufferIndex]) break;
|
||||||
}
|
}
|
||||||
|
|
@ -402,7 +402,7 @@ static ma_uint32 OnAudioBufferDSPRead(ma_pcm_converter *pDSP, void *pFramesOut,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ma_uint32 firstFrameIndexOfThisSubBuffer = subBufferSizeInFrames * currentSubBufferIndex;
|
ma_uint32 firstFrameIndexOfThisSubBuffer = subBufferSizeInFrames*currentSubBufferIndex;
|
||||||
framesRemainingInOutputBuffer = subBufferSizeInFrames - (audioBuffer->frameCursorPos - firstFrameIndexOfThisSubBuffer);
|
framesRemainingInOutputBuffer = subBufferSizeInFrames - (audioBuffer->frameCursorPos - firstFrameIndexOfThisSubBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -410,7 +410,7 @@ static ma_uint32 OnAudioBufferDSPRead(ma_pcm_converter *pDSP, void *pFramesOut,
|
||||||
if (framesToRead > framesRemainingInOutputBuffer) framesToRead = framesRemainingInOutputBuffer;
|
if (framesToRead > framesRemainingInOutputBuffer) framesToRead = framesRemainingInOutputBuffer;
|
||||||
|
|
||||||
memcpy((unsigned char *)pFramesOut + (framesRead*frameSizeInBytes), audioBuffer->buffer + (audioBuffer->frameCursorPos*frameSizeInBytes), framesToRead*frameSizeInBytes);
|
memcpy((unsigned char *)pFramesOut + (framesRead*frameSizeInBytes), audioBuffer->buffer + (audioBuffer->frameCursorPos*frameSizeInBytes), framesToRead*frameSizeInBytes);
|
||||||
audioBuffer->frameCursorPos = (audioBuffer->frameCursorPos + framesToRead) % audioBuffer->bufferSizeInFrames;
|
audioBuffer->frameCursorPos = (audioBuffer->frameCursorPos + framesToRead)%audioBuffer->bufferSizeInFrames;
|
||||||
framesRead += framesToRead;
|
framesRead += framesToRead;
|
||||||
|
|
||||||
// If we've read to the end of the buffer, mark it as processed
|
// If we've read to the end of the buffer, mark it as processed
|
||||||
|
|
@ -465,7 +465,7 @@ static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 fr
|
||||||
static void InitAudioBufferPool()
|
static void InitAudioBufferPool()
|
||||||
{
|
{
|
||||||
// Dummy buffers
|
// Dummy buffers
|
||||||
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
|
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
|
||||||
{
|
{
|
||||||
audioBufferPool[i] = InitAudioBuffer(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, 0, AUDIO_BUFFER_USAGE_STATIC);
|
audioBufferPool[i] = InitAudioBuffer(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, 0, AUDIO_BUFFER_USAGE_STATIC);
|
||||||
}
|
}
|
||||||
|
|
@ -474,7 +474,11 @@ static void InitAudioBufferPool()
|
||||||
// Close the audio buffers pool
|
// Close the audio buffers pool
|
||||||
static void CloseAudioBufferPool()
|
static void CloseAudioBufferPool()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) RL_FREE(audioBufferPool[i]);
|
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
|
||||||
|
{
|
||||||
|
RL_FREE(audioBufferPool[i]->buffer);
|
||||||
|
RL_FREE(audioBufferPool[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -485,9 +489,8 @@ void InitAudioDevice(void)
|
||||||
{
|
{
|
||||||
// Init audio context
|
// Init audio context
|
||||||
ma_context_config contextConfig = ma_context_config_init();
|
ma_context_config contextConfig = ma_context_config_init();
|
||||||
|
|
||||||
contextConfig.logCallback = OnLog;
|
contextConfig.logCallback = OnLog;
|
||||||
|
|
||||||
ma_result result = ma_context_init(NULL, 0, &contextConfig, &context);
|
ma_result result = ma_context_init(NULL, 0, &contextConfig, &context);
|
||||||
if (result != MA_SUCCESS)
|
if (result != MA_SUCCESS)
|
||||||
{
|
{
|
||||||
|
|
@ -553,11 +556,7 @@ void InitAudioDevice(void)
|
||||||
// Close the audio device for all contexts
|
// Close the audio device for all contexts
|
||||||
void CloseAudioDevice(void)
|
void CloseAudioDevice(void)
|
||||||
{
|
{
|
||||||
if (!isAudioInitialized)
|
if (isAudioInitialized)
|
||||||
{
|
|
||||||
TraceLog(LOG_WARNING, "Could not close audio device because it is not currently initialized");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
ma_mutex_uninit(&audioLock);
|
ma_mutex_uninit(&audioLock);
|
||||||
ma_device_uninit(&device);
|
ma_device_uninit(&device);
|
||||||
|
|
@ -567,6 +566,7 @@ void CloseAudioDevice(void)
|
||||||
|
|
||||||
TraceLog(LOG_INFO, "Audio device closed successfully");
|
TraceLog(LOG_INFO, "Audio device closed successfully");
|
||||||
}
|
}
|
||||||
|
else TraceLog(LOG_WARNING, "Could not close audio device because it is not currently initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if device has been initialized successfully
|
// Check if device has been initialized successfully
|
||||||
|
|
@ -588,12 +588,12 @@ void SetMasterVolume(float volume)
|
||||||
// Module Functions Definition - Audio Buffer management
|
// Module Functions Definition - Audio Buffer management
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Create a new audio buffer. Initially filled with silence
|
// Initialize a new audio buffer (filled with silence)
|
||||||
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)
|
||||||
{
|
{
|
||||||
AudioBuffer *audioBuffer = (AudioBuffer *)RL_CALLOC(sizeof(*audioBuffer), 1);
|
AudioBuffer *audioBuffer = (AudioBuffer *)RL_CALLOC(1, sizeof(AudioBuffer));
|
||||||
audioBuffer->buffer = RL_CALLOC((bufferSizeInFrames*channels*ma_get_bytes_per_sample(format)), 1);
|
audioBuffer->buffer = RL_CALLOC(bufferSizeInFrames*channels*ma_get_bytes_per_sample(format), 1);
|
||||||
|
|
||||||
if (audioBuffer == NULL)
|
if (audioBuffer == NULL)
|
||||||
{
|
{
|
||||||
TraceLog(LOG_ERROR, "InitAudioBuffer() : Failed to allocate memory for audio buffer");
|
TraceLog(LOG_ERROR, "InitAudioBuffer() : Failed to allocate memory for audio buffer");
|
||||||
|
|
@ -612,7 +612,7 @@ AudioBuffer *InitAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
|
||||||
dspConfig.onRead = OnAudioBufferDSPRead; // Callback on data reading
|
dspConfig.onRead = OnAudioBufferDSPRead; // Callback on data reading
|
||||||
dspConfig.pUserData = audioBuffer; // Audio data pointer
|
dspConfig.pUserData = audioBuffer; // Audio data pointer
|
||||||
dspConfig.allowDynamicSampleRate = true; // Required for pitch shifting
|
dspConfig.allowDynamicSampleRate = true; // Required for pitch shifting
|
||||||
|
|
||||||
ma_result result = ma_pcm_converter_init(&dspConfig, &audioBuffer->dsp);
|
ma_result result = ma_pcm_converter_init(&dspConfig, &audioBuffer->dsp);
|
||||||
|
|
||||||
if (result != MA_SUCCESS)
|
if (result != MA_SUCCESS)
|
||||||
|
|
@ -659,7 +659,7 @@ void CloseAudioBuffer(AudioBuffer *buffer)
|
||||||
bool IsAudioBufferPlaying(AudioBuffer *buffer)
|
bool IsAudioBufferPlaying(AudioBuffer *buffer)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
if (buffer != NULL) result = (buffer->playing && !buffer->paused);
|
if (buffer != NULL) result = (buffer->playing && !buffer->paused);
|
||||||
else TraceLog(LOG_ERROR, "IsAudioBufferPlaying() : No audio buffer");
|
else TraceLog(LOG_ERROR, "IsAudioBufferPlaying() : No audio buffer");
|
||||||
|
|
||||||
|
|
@ -690,6 +690,7 @@ void StopAudioBuffer(AudioBuffer *buffer)
|
||||||
buffer->playing = false;
|
buffer->playing = false;
|
||||||
buffer->paused = false;
|
buffer->paused = false;
|
||||||
buffer->frameCursorPos = 0;
|
buffer->frameCursorPos = 0;
|
||||||
|
buffer->totalFramesProcessed = 0;
|
||||||
buffer->isSubBufferProcessed[0] = true;
|
buffer->isSubBufferProcessed[0] = true;
|
||||||
buffer->isSubBufferProcessed[1] = true;
|
buffer->isSubBufferProcessed[1] = true;
|
||||||
}
|
}
|
||||||
|
|
@ -701,7 +702,7 @@ void StopAudioBuffer(AudioBuffer *buffer)
|
||||||
void PauseAudioBuffer(AudioBuffer *buffer)
|
void PauseAudioBuffer(AudioBuffer *buffer)
|
||||||
{
|
{
|
||||||
if (buffer != NULL) buffer->paused = true;
|
if (buffer != NULL) buffer->paused = true;
|
||||||
else TraceLog(LOG_ERROR, "PauseAudioBuffer() : No audio buffer");
|
else TraceLog(LOG_ERROR, "PauseAudioBuffer() : No audio buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resume an audio buffer
|
// Resume an audio buffer
|
||||||
|
|
@ -725,8 +726,10 @@ void SetAudioBufferPitch(AudioBuffer *buffer, float pitch)
|
||||||
{
|
{
|
||||||
float pitchMul = pitch/buffer->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
|
// Pitching is just an adjustment of the sample rate.
|
||||||
// will make the sound faster; lower pitches make it slower.
|
// 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)buffer->dsp.src.config.sampleRateOut/pitchMul);
|
ma_uint32 newOutputSampleRate = (ma_uint32)((float)buffer->dsp.src.config.sampleRateOut/pitchMul);
|
||||||
buffer->pitch *= (float)buffer->dsp.src.config.sampleRateOut/newOutputSampleRate;
|
buffer->pitch *= (float)buffer->dsp.src.config.sampleRateOut/newOutputSampleRate;
|
||||||
|
|
||||||
|
|
@ -817,7 +820,7 @@ Sound LoadSoundFromWave(Wave wave)
|
||||||
|
|
||||||
if (wave.data != NULL)
|
if (wave.data != NULL)
|
||||||
{
|
{
|
||||||
// When using miniaudio we need to do our own mixing.
|
// When using miniaudio we need to do our own mixing.
|
||||||
// To simplify this we need convert the format of each sound to be consistent with
|
// To simplify this we need convert the format of each sound to be consistent with
|
||||||
// the format used to open the playback device. We can do this two ways:
|
// the format used to open the playback device. We can do this two ways:
|
||||||
//
|
//
|
||||||
|
|
@ -869,16 +872,14 @@ void UpdateSound(Sound sound, const void *data, int samplesCount)
|
||||||
{
|
{
|
||||||
AudioBuffer *audioBuffer = sound.stream.buffer;
|
AudioBuffer *audioBuffer = sound.stream.buffer;
|
||||||
|
|
||||||
if (audioBuffer == NULL)
|
if (audioBuffer != NULL)
|
||||||
{
|
{
|
||||||
TraceLog(LOG_ERROR, "UpdateSound() : Invalid sound - no audio buffer");
|
StopAudioBuffer(audioBuffer);
|
||||||
return;
|
|
||||||
|
// TODO: May want to lock/unlock this since this data buffer is read at mixing time
|
||||||
|
memcpy(audioBuffer->buffer, data, samplesCount*audioBuffer->dsp.formatConverterIn.config.channels*ma_get_bytes_per_sample(audioBuffer->dsp.formatConverterIn.config.formatIn));
|
||||||
}
|
}
|
||||||
|
else TraceLog(LOG_ERROR, "UpdateSound() : Invalid sound - no audio buffer");
|
||||||
StopAudioBuffer(audioBuffer);
|
|
||||||
|
|
||||||
// TODO: May want to lock/unlock this since this data buffer is read at mixing time.
|
|
||||||
memcpy(audioBuffer->buffer, data, samplesCount*audioBuffer->dsp.formatConverterIn.config.channels*ma_get_bytes_per_sample(audioBuffer->dsp.formatConverterIn.config.formatIn));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export wave data to file
|
// Export wave data to file
|
||||||
|
|
@ -913,37 +914,40 @@ void ExportWaveAsCode(Wave wave, const char *fileName)
|
||||||
|
|
||||||
FILE *txtFile = fopen(fileName, "wt");
|
FILE *txtFile = fopen(fileName, "wt");
|
||||||
|
|
||||||
fprintf(txtFile, "\n//////////////////////////////////////////////////////////////////////////////////\n");
|
if (txtFile != NULL)
|
||||||
fprintf(txtFile, "// //\n");
|
{
|
||||||
fprintf(txtFile, "// WaveAsCode exporter v1.0 - Wave data exported as an array of bytes //\n");
|
fprintf(txtFile, "\n//////////////////////////////////////////////////////////////////////////////////\n");
|
||||||
fprintf(txtFile, "// //\n");
|
fprintf(txtFile, "// //\n");
|
||||||
fprintf(txtFile, "// more info and bugs-report: github.com/raysan5/raylib //\n");
|
fprintf(txtFile, "// WaveAsCode exporter v1.0 - Wave data exported as an array of bytes //\n");
|
||||||
fprintf(txtFile, "// feedback and support: ray[at]raylib.com //\n");
|
fprintf(txtFile, "// //\n");
|
||||||
fprintf(txtFile, "// //\n");
|
fprintf(txtFile, "// more info and bugs-report: github.com/raysan5/raylib //\n");
|
||||||
fprintf(txtFile, "// Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n");
|
fprintf(txtFile, "// feedback and support: ray[at]raylib.com //\n");
|
||||||
fprintf(txtFile, "// //\n");
|
fprintf(txtFile, "// //\n");
|
||||||
fprintf(txtFile, "//////////////////////////////////////////////////////////////////////////////////\n\n");
|
fprintf(txtFile, "// Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n");
|
||||||
|
fprintf(txtFile, "// //\n");
|
||||||
|
fprintf(txtFile, "//////////////////////////////////////////////////////////////////////////////////\n\n");
|
||||||
|
|
||||||
#if !defined(RAUDIO_STANDALONE)
|
#if !defined(RAUDIO_STANDALONE)
|
||||||
// Get file name from path and convert variable name to uppercase
|
// Get file name from path and convert variable name to uppercase
|
||||||
strcpy(varFileName, GetFileNameWithoutExt(fileName));
|
strcpy(varFileName, GetFileNameWithoutExt(fileName));
|
||||||
for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; }
|
for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; }
|
||||||
#else
|
#else
|
||||||
strcpy(varFileName, fileName);
|
strcpy(varFileName, fileName);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fprintf(txtFile, "// Wave data information\n");
|
fprintf(txtFile, "// Wave data information\n");
|
||||||
fprintf(txtFile, "#define %s_SAMPLE_COUNT %i\n", varFileName, wave.sampleCount);
|
fprintf(txtFile, "#define %s_SAMPLE_COUNT %i\n", varFileName, wave.sampleCount);
|
||||||
fprintf(txtFile, "#define %s_SAMPLE_RATE %i\n", varFileName, wave.sampleRate);
|
fprintf(txtFile, "#define %s_SAMPLE_RATE %i\n", varFileName, wave.sampleRate);
|
||||||
fprintf(txtFile, "#define %s_SAMPLE_SIZE %i\n", varFileName, wave.sampleSize);
|
fprintf(txtFile, "#define %s_SAMPLE_SIZE %i\n", varFileName, wave.sampleSize);
|
||||||
fprintf(txtFile, "#define %s_CHANNELS %i\n\n", varFileName, wave.channels);
|
fprintf(txtFile, "#define %s_CHANNELS %i\n\n", varFileName, wave.channels);
|
||||||
|
|
||||||
// Write byte data as hexadecimal text
|
// Write byte data as hexadecimal text
|
||||||
fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize);
|
fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize);
|
||||||
for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]);
|
for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]);
|
||||||
fprintf(txtFile, "0x%x };\n", ((unsigned char *)wave.data)[dataSize - 1]);
|
fprintf(txtFile, "0x%x };\n", ((unsigned char *)wave.data)[dataSize - 1]);
|
||||||
|
|
||||||
fclose(txtFile);
|
fclose(txtFile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Play a sound
|
// Play a sound
|
||||||
|
|
@ -956,7 +960,7 @@ void PlaySound(Sound sound)
|
||||||
void PlaySoundMulti(Sound sound)
|
void PlaySoundMulti(Sound sound)
|
||||||
{
|
{
|
||||||
int index = -1;
|
int index = -1;
|
||||||
unsigned long oldAge = 0;
|
unsigned int oldAge = 0;
|
||||||
int oldIndex = -1;
|
int oldIndex = -1;
|
||||||
|
|
||||||
// find the first non playing pool entry
|
// find the first non playing pool entry
|
||||||
|
|
@ -967,7 +971,7 @@ void PlaySoundMulti(Sound sound)
|
||||||
oldAge = audioBufferPoolChannels[i];
|
oldAge = audioBufferPoolChannels[i];
|
||||||
oldIndex = i;
|
oldIndex = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsAudioBufferPlaying(audioBufferPool[i]))
|
if (!IsAudioBufferPlaying(audioBufferPool[i]))
|
||||||
{
|
{
|
||||||
index = i;
|
index = i;
|
||||||
|
|
@ -979,17 +983,17 @@ void PlaySoundMulti(Sound sound)
|
||||||
if (index == -1)
|
if (index == -1)
|
||||||
{
|
{
|
||||||
TraceLog(LOG_WARNING,"pool age %i ended a sound early no room in buffer pool", audioBufferPoolCounter);
|
TraceLog(LOG_WARNING,"pool age %i ended a sound early no room in buffer pool", audioBufferPoolCounter);
|
||||||
|
|
||||||
if (oldIndex == -1)
|
if (oldIndex == -1)
|
||||||
{
|
{
|
||||||
// Shouldn't be able to get here... but just in case something odd happens!
|
// Shouldn't be able to get here... but just in case something odd happens!
|
||||||
TraceLog(LOG_ERROR,"sound buffer pool couldn't determine oldest buffer not playing sound");
|
TraceLog(LOG_ERROR,"sound buffer pool couldn't determine oldest buffer not playing sound");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
index = oldIndex;
|
index = oldIndex;
|
||||||
|
|
||||||
// Just in case...
|
// Just in case...
|
||||||
StopAudioBuffer(audioBufferPool[index]);
|
StopAudioBuffer(audioBufferPool[index]);
|
||||||
}
|
}
|
||||||
|
|
@ -1000,7 +1004,7 @@ void PlaySoundMulti(Sound sound)
|
||||||
|
|
||||||
audioBufferPoolChannels[index] = audioBufferPoolCounter;
|
audioBufferPoolChannels[index] = audioBufferPoolCounter;
|
||||||
audioBufferPoolCounter++;
|
audioBufferPoolCounter++;
|
||||||
|
|
||||||
audioBufferPool[index]->volume = sound.stream.buffer->volume;
|
audioBufferPool[index]->volume = sound.stream.buffer->volume;
|
||||||
audioBufferPool[index]->pitch = sound.stream.buffer->pitch;
|
audioBufferPool[index]->pitch = sound.stream.buffer->pitch;
|
||||||
audioBufferPool[index]->looping = sound.stream.buffer->looping;
|
audioBufferPool[index]->looping = sound.stream.buffer->looping;
|
||||||
|
|
@ -1023,12 +1027,12 @@ void StopSoundMulti(void)
|
||||||
int GetSoundsPlaying(void)
|
int GetSoundsPlaying(void)
|
||||||
{
|
{
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
|
|
||||||
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
|
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
|
||||||
{
|
{
|
||||||
if (IsAudioBufferPlaying(audioBufferPool[i])) counter++;
|
if (IsAudioBufferPlaying(audioBufferPool[i])) counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1184,14 +1188,8 @@ Music LoadMusicStream(const char *fileName)
|
||||||
// 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.loopCount = 0; // Infinite loop by default
|
music.loopCount = 0; // Infinite loop by default
|
||||||
musicLoaded = true;
|
musicLoaded = true;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1207,14 +1205,8 @@ Music LoadMusicStream(const char *fileName)
|
||||||
|
|
||||||
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.loopCount = 0; // Infinite loop by default
|
music.loopCount = 0; // Infinite loop by default
|
||||||
musicLoaded = true;
|
musicLoaded = true;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1223,7 +1215,7 @@ Music LoadMusicStream(const char *fileName)
|
||||||
{
|
{
|
||||||
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 > 0)
|
if (result > 0)
|
||||||
|
|
@ -1232,14 +1224,8 @@ Music LoadMusicStream(const char *fileName)
|
||||||
|
|
||||||
music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels);
|
music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels);
|
||||||
music.sampleCount = drmp3_get_pcm_frame_count(ctxMp3)*ctxMp3->channels;
|
music.sampleCount = drmp3_get_pcm_frame_count(ctxMp3)*ctxMp3->channels;
|
||||||
music.sampleLeft = music.sampleCount;
|
|
||||||
music.loopCount = 0; // Infinite loop by default
|
music.loopCount = 0; // Infinite loop by default
|
||||||
musicLoaded = true;
|
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);
|
|
||||||
TraceLog(LOG_INFO, "[%s] MP3 total samples: %i", fileName, music.sampleCount);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1250,7 +1236,7 @@ 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 > 0) // XM context created successfully
|
if (result == 0) // XM context created successfully
|
||||||
{
|
{
|
||||||
music.ctxType = MUSIC_MODULE_XM;
|
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
|
||||||
|
|
@ -1258,14 +1244,10 @@ Music LoadMusicStream(const char *fileName)
|
||||||
// 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.loopCount = 0; // Infinite loop by default
|
music.loopCount = 0; // Infinite loop by default
|
||||||
musicLoaded = true;
|
musicLoaded = true;
|
||||||
|
|
||||||
music.ctxData = ctxXm;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1274,7 +1256,7 @@ Music LoadMusicStream(const char *fileName)
|
||||||
{
|
{
|
||||||
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);
|
int result = jar_mod_load_file(ctxMod, fileName);
|
||||||
|
|
||||||
|
|
@ -1285,12 +1267,8 @@ Music LoadMusicStream(const char *fileName)
|
||||||
// NOTE: Only stereo is supported for MOD
|
// NOTE: Only stereo is supported for MOD
|
||||||
music.stream = InitAudioStream(48000, 16, 2);
|
music.stream = InitAudioStream(48000, 16, 2);
|
||||||
music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod);
|
music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod);
|
||||||
music.sampleLeft = music.sampleCount;
|
|
||||||
music.loopCount = 0; // Infinite loop by default
|
music.loopCount = 0; // Infinite loop by default
|
||||||
musicLoaded = true;
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1316,6 +1294,15 @@ Music LoadMusicStream(const char *fileName)
|
||||||
|
|
||||||
TraceLog(LOG_WARNING, "[%s] Music file could not be opened", fileName);
|
TraceLog(LOG_WARNING, "[%s] Music file could not be opened", fileName);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Show some music stream info
|
||||||
|
TraceLog(LOG_INFO, "[%s] Music file successfully loaded:", fileName);
|
||||||
|
TraceLog(LOG_INFO, " Total samples: %i", music.sampleCount);
|
||||||
|
TraceLog(LOG_INFO, " Sample rate: %i Hz", music.stream.sampleRate);
|
||||||
|
TraceLog(LOG_INFO, " Sample size: %i bits", music.stream.sampleSize);
|
||||||
|
TraceLog(LOG_INFO, " Channels: %i (%s)", music.stream.channels, (music.stream.channels == 1)? "Mono" : (music.stream.channels == 2)? "Stereo" : "Multi");
|
||||||
|
}
|
||||||
|
|
||||||
return music;
|
return music;
|
||||||
}
|
}
|
||||||
|
|
@ -1348,21 +1335,18 @@ void PlayMusicStream(Music music)
|
||||||
{
|
{
|
||||||
AudioBuffer *audioBuffer = music.stream.buffer;
|
AudioBuffer *audioBuffer = music.stream.buffer;
|
||||||
|
|
||||||
if (audioBuffer == NULL)
|
if (audioBuffer != NULL)
|
||||||
{
|
{
|
||||||
TraceLog(LOG_ERROR, "PlayMusicStream() : No audio buffer");
|
// For music streams, we need to make sure we maintain the frame cursor position
|
||||||
return;
|
// This is a hack for this section of code in UpdateMusicStream()
|
||||||
|
// NOTE: In case window is minimized, music stream is stopped, just make sure to
|
||||||
|
// play again on window restore: if (IsMusicPlaying(music)) PlayMusicStream(music);
|
||||||
|
ma_uint32 frameCursorPos = audioBuffer->frameCursorPos;
|
||||||
|
PlayAudioStream(music.stream); // WARNING: This resets the cursor position.
|
||||||
|
audioBuffer->frameCursorPos = frameCursorPos;
|
||||||
}
|
}
|
||||||
|
else TraceLog(LOG_ERROR, "PlayMusicStream() : No audio buffer");
|
||||||
|
|
||||||
// For music streams, we need to make sure we maintain the frame cursor position. This is hack for this section of code in UpdateMusicStream()
|
|
||||||
// // NOTE: In case window is minimized, music stream is stopped,
|
|
||||||
// // just make sure to play again on window restore
|
|
||||||
// if (IsMusicPlaying(music)) PlayMusicStream(music);
|
|
||||||
ma_uint32 frameCursorPos = audioBuffer->frameCursorPos;
|
|
||||||
|
|
||||||
PlayAudioStream(music.stream); // <-- This resets the cursor position.
|
|
||||||
|
|
||||||
audioBuffer->frameCursorPos = frameCursorPos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pause music playing
|
// Pause music playing
|
||||||
|
|
@ -1389,7 +1373,7 @@ void StopMusicStream(Music music)
|
||||||
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: drflac_seek_to_pcm_frame((drflac *)music.ctxData, 0); 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;
|
||||||
|
|
@ -1402,8 +1386,6 @@ void StopMusicStream(Music music)
|
||||||
#endif
|
#endif
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
music.sampleLeft = music.sampleCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update (re-fill) music buffers if data already processed
|
// Update (re-fill) music buffers if data already processed
|
||||||
|
|
@ -1416,12 +1398,16 @@ void UpdateMusicStream(Music music)
|
||||||
// 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 streamed in L+R samples for xm floats, individual L or R for ogg shorts
|
||||||
|
|
||||||
while (IsAudioBufferProcessed(music.stream))
|
// TODO: Get the sampleLeft using totalFramesProcessed... but first, get total frames processed correctly...
|
||||||
|
//ma_uint32 frameSizeInBytes = ma_get_bytes_per_sample(music.stream.buffer->dsp.formatConverterIn.config.formatIn)*music.stream.buffer->dsp.formatConverterIn.config.channels;
|
||||||
|
int sampleLeft = music.sampleCount - (music.stream.buffer->totalFramesProcessed*music.stream.channels);
|
||||||
|
|
||||||
|
while (IsAudioStreamProcessed(music.stream))
|
||||||
{
|
{
|
||||||
if ((music.sampleLeft/music.stream.channels) >= subBufferSizeInFrames) samplesCount = subBufferSizeInFrames*music.stream.channels;
|
if ((sampleLeft/music.stream.channels) >= subBufferSizeInFrames) samplesCount = subBufferSizeInFrames*music.stream.channels;
|
||||||
else samplesCount = music.sampleLeft;
|
else samplesCount = sampleLeft;
|
||||||
|
|
||||||
switch (music.ctxType)
|
switch (music.ctxType)
|
||||||
{
|
{
|
||||||
|
|
@ -1437,7 +1423,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_pcm_frames_s16((drflac *)music.ctxData, samplesCount, (short *)pcm);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1467,15 +1453,15 @@ void UpdateMusicStream(Music music)
|
||||||
}
|
}
|
||||||
|
|
||||||
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) sampleLeft -= samplesCount/2;
|
||||||
else music.sampleLeft -= samplesCount;
|
else sampleLeft -= samplesCount;
|
||||||
}
|
}
|
||||||
else music.sampleLeft -= samplesCount;
|
else sampleLeft -= samplesCount;
|
||||||
|
|
||||||
if (music.sampleLeft <= 0)
|
if (sampleLeft <= 0)
|
||||||
{
|
{
|
||||||
streamEnding = true;
|
streamEnding = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -1493,13 +1479,10 @@ void UpdateMusicStream(Music music)
|
||||||
// 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
|
||||||
{
|
{
|
||||||
|
|
@ -1528,7 +1511,7 @@ void SetMusicPitch(Music music, float 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 0, means infinite loop
|
||||||
void SetMusicLoopCount(Music music, int count)
|
void SetMusicLoopCount(Music music, int count)
|
||||||
{
|
{
|
||||||
music.loopCount = count;
|
music.loopCount = count;
|
||||||
|
|
@ -1549,7 +1532,8 @@ float GetMusicTimePlayed(Music music)
|
||||||
{
|
{
|
||||||
float secondsPlayed = 0.0f;
|
float secondsPlayed = 0.0f;
|
||||||
|
|
||||||
unsigned int samplesPlayed = music.sampleCount - music.sampleLeft;
|
//ma_uint32 frameSizeInBytes = ma_get_bytes_per_sample(music.stream.buffer->dsp.formatConverterIn.config.formatIn)*music.stream.buffer->dsp.formatConverterIn.config.channels;
|
||||||
|
unsigned int samplesPlayed = music.stream.buffer->totalFramesProcessed*music.stream.channels;
|
||||||
secondsPlayed = (float)samplesPlayed/(music.stream.sampleRate*music.stream.channels);
|
secondsPlayed = (float)samplesPlayed/(music.stream.sampleRate*music.stream.channels);
|
||||||
|
|
||||||
return secondsPlayed;
|
return secondsPlayed;
|
||||||
|
|
@ -1562,35 +1546,24 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
|
||||||
|
|
||||||
stream.sampleRate = sampleRate;
|
stream.sampleRate = sampleRate;
|
||||||
stream.sampleSize = sampleSize;
|
stream.sampleSize = sampleSize;
|
||||||
|
stream.channels = channels;
|
||||||
// Only mono and stereo channels are supported
|
|
||||||
if ((channels > 0) && (channels < 3)) stream.channels = channels;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TraceLog(LOG_WARNING, "Init audio stream: Number of channels not supported: %i", channels);
|
|
||||||
stream.channels = 1; // Fallback to mono channel
|
|
||||||
}
|
|
||||||
|
|
||||||
ma_format formatIn = ((stream.sampleSize == 8)? ma_format_u8 : ((stream.sampleSize == 16)? ma_format_s16 : ma_format_f32));
|
ma_format formatIn = ((stream.sampleSize == 8)? ma_format_u8 : ((stream.sampleSize == 16)? ma_format_s16 : ma_format_f32));
|
||||||
|
|
||||||
// The size of a streaming buffer must be at least double the size of a period
|
// The size of a streaming buffer must be at least double the size of a period
|
||||||
unsigned int periodSize = device.playback.internalBufferSizeInFrames/device.playback.internalPeriods;
|
unsigned int periodSize = device.playback.internalBufferSizeInFrames/device.playback.internalPeriods;
|
||||||
unsigned int subBufferSize = AUDIO_BUFFER_SIZE;
|
unsigned int subBufferSize = AUDIO_BUFFER_SIZE;
|
||||||
|
|
||||||
if (subBufferSize < periodSize) subBufferSize = periodSize;
|
if (subBufferSize < periodSize) subBufferSize = periodSize;
|
||||||
|
|
||||||
AudioBuffer *audioBuffer = InitAudioBuffer(formatIn, stream.channels, stream.sampleRate, subBufferSize*2, AUDIO_BUFFER_USAGE_STREAM);
|
stream.buffer = InitAudioBuffer(formatIn, stream.channels, stream.sampleRate, subBufferSize*2, AUDIO_BUFFER_USAGE_STREAM);
|
||||||
|
|
||||||
if (audioBuffer == NULL)
|
if (stream.buffer != NULL)
|
||||||
{
|
{
|
||||||
TraceLog(LOG_ERROR, "InitAudioStream() : Failed to create audio buffer");
|
stream.buffer->looping = true; // Always loop for streaming buffers
|
||||||
return stream;
|
TraceLog(LOG_INFO, "Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.sampleRate, stream.sampleSize, (stream.channels == 1)? "Mono" : "Stereo");
|
||||||
}
|
}
|
||||||
|
else TraceLog(LOG_ERROR, "InitAudioStream() : Failed to create audio buffer");
|
||||||
audioBuffer->looping = true; // Always loop for streaming buffers
|
|
||||||
stream.buffer = audioBuffer;
|
|
||||||
|
|
||||||
TraceLog(LOG_INFO, "Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.sampleRate, stream.sampleSize, (stream.channels == 1)? "Mono" : "Stereo");
|
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
@ -1605,67 +1578,67 @@ void CloseAudioStream(AudioStream stream)
|
||||||
|
|
||||||
// Update audio stream buffers with data
|
// Update audio stream buffers with data
|
||||||
// NOTE 1: Only updates one buffer of the stream source: unqueue -> update -> queue
|
// NOTE 1: Only updates one buffer of the stream source: unqueue -> update -> queue
|
||||||
// NOTE 2: To unqueue a buffer it needs to be processed: IsAudioBufferProcessed()
|
// NOTE 2: To unqueue a buffer it needs to be processed: IsAudioStreamProcessed()
|
||||||
void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
|
void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
|
||||||
{
|
{
|
||||||
AudioBuffer *audioBuffer = stream.buffer;
|
AudioBuffer *audioBuffer = stream.buffer;
|
||||||
|
|
||||||
if (audioBuffer == NULL)
|
if (audioBuffer != NULL)
|
||||||
{
|
{
|
||||||
TraceLog(LOG_ERROR, "UpdateAudioStream() : No audio buffer");
|
if (audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1])
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1])
|
|
||||||
{
|
|
||||||
ma_uint32 subBufferToUpdate = 0;
|
|
||||||
|
|
||||||
if (audioBuffer->isSubBufferProcessed[0] && audioBuffer->isSubBufferProcessed[1])
|
|
||||||
{
|
{
|
||||||
// Both buffers are available for updating. Update the first one and make sure the cursor is moved back to the front.
|
ma_uint32 subBufferToUpdate = 0;
|
||||||
subBufferToUpdate = 0;
|
|
||||||
audioBuffer->frameCursorPos = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Just update whichever sub-buffer is processed.
|
|
||||||
subBufferToUpdate = (audioBuffer->isSubBufferProcessed[0])? 0 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ma_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2;
|
if (audioBuffer->isSubBufferProcessed[0] && audioBuffer->isSubBufferProcessed[1])
|
||||||
unsigned char *subBuffer = audioBuffer->buffer + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate);
|
|
||||||
|
|
||||||
// Does this API expect a whole buffer to be updated in one go? Assuming so, but if not will need to change this logic.
|
|
||||||
if (subBufferSizeInFrames >= (ma_uint32)samplesCount/stream.channels)
|
|
||||||
{
|
|
||||||
ma_uint32 framesToWrite = subBufferSizeInFrames;
|
|
||||||
|
|
||||||
if (framesToWrite > ((ma_uint32)samplesCount/stream.channels)) framesToWrite = (ma_uint32)samplesCount/stream.channels;
|
|
||||||
|
|
||||||
ma_uint32 bytesToWrite = framesToWrite*stream.channels*(stream.sampleSize/8);
|
|
||||||
memcpy(subBuffer, data, bytesToWrite);
|
|
||||||
|
|
||||||
// Any leftover frames should be filled with zeros.
|
|
||||||
ma_uint32 leftoverFrameCount = subBufferSizeInFrames - framesToWrite;
|
|
||||||
|
|
||||||
if (leftoverFrameCount > 0)
|
|
||||||
{
|
{
|
||||||
memset(subBuffer + bytesToWrite, 0, leftoverFrameCount*stream.channels*(stream.sampleSize/8));
|
// Both buffers are available for updating.
|
||||||
|
// Update the first one and make sure the cursor is moved back to the front.
|
||||||
|
subBufferToUpdate = 0;
|
||||||
|
audioBuffer->frameCursorPos = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Just update whichever sub-buffer is processed.
|
||||||
|
subBufferToUpdate = (audioBuffer->isSubBufferProcessed[0])? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
audioBuffer->isSubBufferProcessed[subBufferToUpdate] = false;
|
ma_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2;
|
||||||
|
unsigned char *subBuffer = audioBuffer->buffer + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate);
|
||||||
|
|
||||||
|
// TODO: Get total frames processed on this buffer... DOES NOT WORK.
|
||||||
|
audioBuffer->totalFramesProcessed += subBufferSizeInFrames;
|
||||||
|
|
||||||
|
// Does this API expect a whole buffer to be updated in one go?
|
||||||
|
// Assuming so, but if not will need to change this logic.
|
||||||
|
if (subBufferSizeInFrames >= (ma_uint32)samplesCount/stream.channels)
|
||||||
|
{
|
||||||
|
ma_uint32 framesToWrite = subBufferSizeInFrames;
|
||||||
|
|
||||||
|
if (framesToWrite > ((ma_uint32)samplesCount/stream.channels)) framesToWrite = (ma_uint32)samplesCount/stream.channels;
|
||||||
|
|
||||||
|
ma_uint32 bytesToWrite = framesToWrite*stream.channels*(stream.sampleSize/8);
|
||||||
|
memcpy(subBuffer, data, bytesToWrite);
|
||||||
|
|
||||||
|
// Any leftover frames should be filled with zeros.
|
||||||
|
ma_uint32 leftoverFrameCount = subBufferSizeInFrames - framesToWrite;
|
||||||
|
|
||||||
|
if (leftoverFrameCount > 0) memset(subBuffer + bytesToWrite, 0, leftoverFrameCount*stream.channels*(stream.sampleSize/8));
|
||||||
|
|
||||||
|
audioBuffer->isSubBufferProcessed[subBufferToUpdate] = false;
|
||||||
|
}
|
||||||
|
else TraceLog(LOG_ERROR, "UpdateAudioStream() : Attempting to write too many frames to buffer");
|
||||||
}
|
}
|
||||||
else TraceLog(LOG_ERROR, "UpdateAudioStream() : Attempting to write too many frames to buffer");
|
else TraceLog(LOG_ERROR, "UpdateAudioStream() : Audio buffer not available for updating");
|
||||||
}
|
}
|
||||||
else TraceLog(LOG_ERROR, "Audio buffer not available for updating");
|
else TraceLog(LOG_ERROR, "UpdateAudioStream() : No audio buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if any audio stream buffers requires refill
|
// Check if any audio stream buffers requires refill
|
||||||
bool IsAudioBufferProcessed(AudioStream stream)
|
bool IsAudioStreamProcessed(AudioStream stream)
|
||||||
{
|
{
|
||||||
if (stream.buffer == NULL)
|
if (stream.buffer == NULL)
|
||||||
{
|
{
|
||||||
TraceLog(LOG_ERROR, "IsAudioBufferProcessed() : No audio buffer");
|
TraceLog(LOG_ERROR, "IsAudioStreamProcessed() : No audio buffer");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1901,9 +1874,9 @@ static int SaveWAV(Wave wave, const char *fileName)
|
||||||
waveData.subChunkID[3] = 'a';
|
waveData.subChunkID[3] = 'a';
|
||||||
waveData.subChunkSize = dataSize;
|
waveData.subChunkSize = dataSize;
|
||||||
|
|
||||||
success = fwrite(&riffHeader, sizeof(RiffHeader), 1, wavFile);
|
fwrite(&riffHeader, sizeof(RiffHeader), 1, wavFile);
|
||||||
success = fwrite(&waveFormat, sizeof(WaveFormat), 1, wavFile);
|
fwrite(&waveFormat, sizeof(WaveFormat), 1, wavFile);
|
||||||
success = fwrite(&waveData, sizeof(WaveData), 1, wavFile);
|
fwrite(&waveData, sizeof(WaveData), 1, wavFile);
|
||||||
|
|
||||||
success = fwrite(wave.data, dataSize, 1, wavFile);
|
success = fwrite(wave.data, dataSize, 1, wavFile);
|
||||||
|
|
||||||
|
|
@ -1962,7 +1935,7 @@ static Wave LoadFLAC(const char *fileName)
|
||||||
|
|
||||||
// Decode an entire FLAC file in one go
|
// Decode an entire FLAC file in one go
|
||||||
uint64_t totalSampleCount;
|
uint64_t totalSampleCount;
|
||||||
wave.data = drflac_open_and_decode_file_s16(fileName, &wave.channels, &wave.sampleRate, &totalSampleCount);
|
wave.data = drflac_open_file_and_read_pcm_frames_s16(fileName, &wave.channels, &wave.sampleRate, &totalSampleCount);
|
||||||
|
|
||||||
wave.sampleCount = (unsigned int)totalSampleCount;
|
wave.sampleCount = (unsigned int)totalSampleCount;
|
||||||
wave.sampleSize = 16;
|
wave.sampleSize = 16;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/**********************************************************************************************
|
/**********************************************************************************************
|
||||||
*
|
*
|
||||||
* raudio - A simple and easy-to-use audio library based on mini_al
|
* raudio - A simple and easy-to-use audio library based on miniaudio
|
||||||
*
|
*
|
||||||
* FEATURES:
|
* FEATURES:
|
||||||
* - Manage audio device (init/close)
|
* - Manage audio device (init/close)
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
*
|
*
|
||||||
* CONTRIBUTORS:
|
* CONTRIBUTORS:
|
||||||
* David Reid (github: @mackron) (Nov. 2017):
|
* David Reid (github: @mackron) (Nov. 2017):
|
||||||
* - Complete port to mini_al library
|
* - Complete port to miniaudio library
|
||||||
*
|
*
|
||||||
* Joshua Reisenauer (github: @kd7tck) (2015)
|
* Joshua Reisenauer (github: @kd7tck) (2015)
|
||||||
* - XM audio module support (jar_xm)
|
* - XM audio module support (jar_xm)
|
||||||
|
|
@ -110,9 +110,8 @@ typedef struct Sound {
|
||||||
typedef struct Music {
|
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
|
||||||
|
|
||||||
unsigned int sampleCount; // Total number of samples
|
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
|
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
|
||||||
|
|
||||||
AudioStream stream; // Audio stream
|
AudioStream stream; // Audio stream
|
||||||
|
|
@ -182,7 +181,7 @@ float GetMusicTimePlayed(Music music); // Get current m
|
||||||
AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream raw audio pcm data)
|
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 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 IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill
|
||||||
void PlayAudioStream(AudioStream stream); // Play audio stream
|
void PlayAudioStream(AudioStream stream); // Play audio stream
|
||||||
void PauseAudioStream(AudioStream stream); // Pause audio stream
|
void PauseAudioStream(AudioStream stream); // Pause audio stream
|
||||||
void ResumeAudioStream(AudioStream stream); // Resume audio stream
|
void ResumeAudioStream(AudioStream stream); // Resume audio stream
|
||||||
|
|
|
||||||
80
src/raylib.h
|
|
@ -33,7 +33,7 @@
|
||||||
* [core] rgif (Charlie Tangora, Ramon Santamaria) for GIF recording
|
* [core] rgif (Charlie Tangora, Ramon Santamaria) for GIF recording
|
||||||
* [textures] stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...)
|
* [textures] stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...)
|
||||||
* [textures] stb_image_write (Sean Barret) for image writting (BMP, TGA, PNG, JPG)
|
* [textures] stb_image_write (Sean Barret) for image writting (BMP, TGA, PNG, JPG)
|
||||||
* [textures] stb_image_resize (Sean Barret) for image resizing algorythms
|
* [textures] stb_image_resize (Sean Barret) for image resizing algorithms
|
||||||
* [textures] stb_perlin (Sean Barret) for Perlin noise image generation
|
* [textures] stb_perlin (Sean Barret) for Perlin noise image generation
|
||||||
* [text] stb_truetype (Sean Barret) for ttf fonts loading
|
* [text] stb_truetype (Sean Barret) for ttf fonts loading
|
||||||
* [text] stb_rect_pack (Sean Barret) for rectangles packing
|
* [text] stb_rect_pack (Sean Barret) for rectangles packing
|
||||||
|
|
@ -96,10 +96,6 @@
|
||||||
|
|
||||||
#define MAX_TOUCH_POINTS 10 // Maximum number of touch points supported
|
#define MAX_TOUCH_POINTS 10 // Maximum number of touch points supported
|
||||||
|
|
||||||
// Shader and material limits
|
|
||||||
#define MAX_SHADER_LOCATIONS 32 // Maximum number of predefined locations stored in shader struct
|
|
||||||
#define MAX_MATERIAL_MAPS 12 // Maximum number of texture maps stored in shader struct
|
|
||||||
|
|
||||||
// Allow custom memory allocators
|
// Allow custom memory allocators
|
||||||
#ifndef RL_MALLOC
|
#ifndef RL_MALLOC
|
||||||
#define RL_MALLOC(sz) malloc(sz)
|
#define RL_MALLOC(sz) malloc(sz)
|
||||||
|
|
@ -110,7 +106,7 @@
|
||||||
#ifndef RL_FREE
|
#ifndef RL_FREE
|
||||||
#define RL_FREE(p) free(p)
|
#define RL_FREE(p) free(p)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// 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)
|
||||||
|
|
@ -322,13 +318,13 @@ typedef struct Mesh {
|
||||||
|
|
||||||
// OpenGL identifiers
|
// OpenGL identifiers
|
||||||
unsigned int vaoId; // OpenGL Vertex Array Object id
|
unsigned int vaoId; // OpenGL Vertex Array Object id
|
||||||
unsigned int vboId[7]; // OpenGL Vertex Buffer Objects id (default vertex data)
|
unsigned int *vboId; // OpenGL Vertex Buffer Objects id (default vertex data)
|
||||||
} Mesh;
|
} Mesh;
|
||||||
|
|
||||||
// Shader type (generic)
|
// Shader type (generic)
|
||||||
typedef struct Shader {
|
typedef struct Shader {
|
||||||
unsigned int id; // Shader program id
|
unsigned int id; // Shader program id
|
||||||
int locs[MAX_SHADER_LOCATIONS]; // Shader locations array
|
int *locs; // Shader locations array (MAX_SHADER_LOCATIONS)
|
||||||
} Shader;
|
} Shader;
|
||||||
|
|
||||||
// Material texture map
|
// Material texture map
|
||||||
|
|
@ -341,7 +337,7 @@ typedef struct MaterialMap {
|
||||||
// Material type (generic)
|
// Material type (generic)
|
||||||
typedef struct Material {
|
typedef struct Material {
|
||||||
Shader shader; // Material shader
|
Shader shader; // Material shader
|
||||||
MaterialMap maps[MAX_MATERIAL_MAPS]; // Material maps
|
MaterialMap *maps; // Material maps array (MAX_MATERIAL_MAPS)
|
||||||
float *params; // Material generic parameters (if required)
|
float *params; // Material generic parameters (if required)
|
||||||
} Material;
|
} Material;
|
||||||
|
|
||||||
|
|
@ -436,9 +432,8 @@ typedef struct Sound {
|
||||||
typedef struct Music {
|
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
|
||||||
|
|
||||||
unsigned int sampleCount; // Total number of samples
|
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
|
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
|
||||||
|
|
||||||
AudioStream stream; // Audio stream
|
AudioStream stream; // Audio stream
|
||||||
|
|
@ -464,7 +459,7 @@ typedef struct VrDeviceInfo {
|
||||||
// System config flags
|
// System config flags
|
||||||
// NOTE: Used for bit masks
|
// NOTE: Used for bit masks
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FLAG_SHOW_LOGO = 1, // Set to show raylib logo at startup
|
FLAG_RESERVED = 1, // Reserved
|
||||||
FLAG_FULLSCREEN_MODE = 2, // Set to run program in fullscreen
|
FLAG_FULLSCREEN_MODE = 2, // Set to run program in fullscreen
|
||||||
FLAG_WINDOW_RESIZABLE = 4, // Set to allow resizable window
|
FLAG_WINDOW_RESIZABLE = 4, // Set to allow resizable window
|
||||||
FLAG_WINDOW_UNDECORATED = 8, // Set to disable window decoration (frame and buttons)
|
FLAG_WINDOW_UNDECORATED = 8, // Set to disable window decoration (frame and buttons)
|
||||||
|
|
@ -887,6 +882,7 @@ RLAPI int GetMonitorWidth(int monitor); // Get primary
|
||||||
RLAPI int GetMonitorHeight(int monitor); // Get primary monitor height
|
RLAPI int GetMonitorHeight(int monitor); // Get primary monitor height
|
||||||
RLAPI int GetMonitorPhysicalWidth(int monitor); // Get primary monitor physical width in millimetres
|
RLAPI int GetMonitorPhysicalWidth(int monitor); // Get primary monitor physical width in millimetres
|
||||||
RLAPI int GetMonitorPhysicalHeight(int monitor); // Get primary monitor physical height in millimetres
|
RLAPI int GetMonitorPhysicalHeight(int monitor); // Get primary monitor physical height in millimetres
|
||||||
|
RLAPI Vector2 GetWindowPosition(void); // Get window position XY on monitor
|
||||||
RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the primary monitor
|
RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the primary monitor
|
||||||
RLAPI const char *GetClipboardText(void); // Get clipboard text content
|
RLAPI const char *GetClipboardText(void); // Get clipboard text content
|
||||||
RLAPI void SetClipboardText(const char *text); // Set clipboard text content
|
RLAPI void SetClipboardText(const char *text); // Set clipboard text content
|
||||||
|
|
@ -908,11 +904,16 @@ RLAPI void BeginMode3D(Camera3D camera); // Initializes
|
||||||
RLAPI void EndMode3D(void); // Ends 3D mode and returns to default 2D orthographic mode
|
RLAPI void EndMode3D(void); // Ends 3D mode and returns to default 2D orthographic mode
|
||||||
RLAPI void BeginTextureMode(RenderTexture2D target); // Initializes render texture for drawing
|
RLAPI void BeginTextureMode(RenderTexture2D target); // Initializes render texture for drawing
|
||||||
RLAPI void EndTextureMode(void); // Ends drawing to render texture
|
RLAPI void EndTextureMode(void); // Ends drawing to render texture
|
||||||
|
RLAPI void BeginScissorMode(int x, int y, int width, int height); // Begin scissor mode (define screen area for following drawing)
|
||||||
|
RLAPI void EndScissorMode(void); // End scissor mode
|
||||||
|
|
||||||
// Screen-space-related functions
|
// Screen-space-related functions
|
||||||
RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position
|
RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position
|
||||||
RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position for a 3d world space position
|
|
||||||
RLAPI Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix)
|
RLAPI Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix)
|
||||||
|
RLAPI Matrix GetCameraMatrix2D(Camera2D camera); // Returns camera 2d transform matrix
|
||||||
|
RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position for a 3d world space position
|
||||||
|
RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Returns the screen space position for a 2d camera world space position
|
||||||
|
RLAPI Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera); // Returns the world space position for a 2d camera screen space position
|
||||||
|
|
||||||
// Timing-related functions
|
// Timing-related functions
|
||||||
RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum)
|
RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum)
|
||||||
|
|
@ -940,10 +941,12 @@ RLAPI int GetRandomValue(int min, int max); // Returns a r
|
||||||
// Files management functions
|
// Files management functions
|
||||||
RLAPI bool FileExists(const char *fileName); // Check if file exists
|
RLAPI bool FileExists(const char *fileName); // Check if file exists
|
||||||
RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension
|
RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension
|
||||||
|
RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists
|
||||||
RLAPI const char *GetExtension(const char *fileName); // Get pointer to extension for a filename string
|
RLAPI const char *GetExtension(const char *fileName); // Get pointer to extension for a filename string
|
||||||
RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string
|
RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string
|
||||||
RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (memory should be freed)
|
RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string)
|
||||||
RLAPI const char *GetDirectoryPath(const char *fileName); // Get full path for a given fileName (uses static string)
|
RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string)
|
||||||
|
RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string)
|
||||||
RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string)
|
RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string)
|
||||||
RLAPI char **GetDirectoryFiles(const char *dirPath, int *count); // Get filenames in a directory path (memory should be freed)
|
RLAPI char **GetDirectoryFiles(const char *dirPath, int *count); // Get filenames in a directory path (memory should be freed)
|
||||||
RLAPI void ClearDirectoryFiles(void); // Clear directory files paths buffers (free memory)
|
RLAPI void ClearDirectoryFiles(void); // Clear directory files paths buffers (free memory)
|
||||||
|
|
@ -953,6 +956,9 @@ RLAPI char **GetDroppedFiles(int *count); // Get dropped
|
||||||
RLAPI void ClearDroppedFiles(void); // Clear dropped files paths buffer (free memory)
|
RLAPI void ClearDroppedFiles(void); // Clear dropped files paths buffer (free memory)
|
||||||
RLAPI long GetFileModTime(const char *fileName); // Get file modification time (last write time)
|
RLAPI long GetFileModTime(const char *fileName); // Get file modification time (last write time)
|
||||||
|
|
||||||
|
RLAPI unsigned char *CompressData(unsigned char *data, int dataLength, int *compDataLength); // Compress data (DEFLATE algorythm)
|
||||||
|
RLAPI unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *dataLength); // Decompress data (DEFLATE algorythm)
|
||||||
|
|
||||||
// Persistent storage management
|
// Persistent storage management
|
||||||
RLAPI void StorageSaveValue(int position, int value); // Save integer value to storage file (to defined position)
|
RLAPI void StorageSaveValue(int position, int value); // Save integer value to storage file (to defined position)
|
||||||
RLAPI int StorageLoadValue(int position); // Load integer value from storage file (from defined position)
|
RLAPI int StorageLoadValue(int position); // Load integer value from storage file (from defined position)
|
||||||
|
|
@ -1056,9 +1062,9 @@ RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color c
|
||||||
RLAPI void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color); // Draw rectangle outline with extended parameters
|
RLAPI void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color); // Draw rectangle outline with extended parameters
|
||||||
RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges
|
RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges
|
||||||
RLAPI void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, int lineThick, Color color); // Draw rectangle with rounded edges outline
|
RLAPI void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, int lineThick, Color color); // Draw rectangle with rounded edges outline
|
||||||
RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle
|
RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!)
|
||||||
RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline
|
RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline (vertex in counter-clockwise order!)
|
||||||
RLAPI void DrawTriangleFan(Vector2 *points, int numPoints, Color color); // Draw a triangle fan defined by points
|
RLAPI void DrawTriangleFan(Vector2 *points, int numPoints, Color color); // Draw a triangle fan defined by points (first vertex is the center)
|
||||||
RLAPI void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color); // Draw a triangle strip defined by points
|
RLAPI void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color); // Draw a triangle strip defined by points
|
||||||
RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version)
|
RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version)
|
||||||
|
|
||||||
|
|
@ -1093,6 +1099,7 @@ RLAPI void UnloadTexture(Texture2D texture);
|
||||||
RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM)
|
RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM)
|
||||||
RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array
|
RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array
|
||||||
RLAPI Vector4 *GetImageDataNormalized(Image image); // Get pixel data from image as Vector4 array (float normalized)
|
RLAPI Vector4 *GetImageDataNormalized(Image image); // Get pixel data from image as Vector4 array (float normalized)
|
||||||
|
RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold); // Get image alpha border rectangle
|
||||||
RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture)
|
RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture)
|
||||||
RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image
|
RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image
|
||||||
RLAPI Image GetScreenData(void); // Get pixel data from screen buffer and return an Image (screenshot)
|
RLAPI Image GetScreenData(void); // Get pixel data from screen buffer and return an Image (screenshot)
|
||||||
|
|
@ -1181,18 +1188,15 @@ RLAPI void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontS
|
||||||
RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font
|
RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font
|
||||||
RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font
|
RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font
|
||||||
RLAPI int GetGlyphIndex(Font font, int character); // Get index position for a unicode character on font
|
RLAPI int GetGlyphIndex(Font font, int character); // Get index position for a unicode character on font
|
||||||
RLAPI int GetNextCodepoint(const char *text, int *bytesProcessed); // Returns next codepoint in a UTF8 encoded string
|
|
||||||
// NOTE: 0x3f('?') is returned on failure
|
|
||||||
|
|
||||||
// Text strings management functions
|
// Text strings management functions (no utf8 strings, only byte chars)
|
||||||
// NOTE: Some strings allocate memory internally for returned strings, just be careful!
|
// NOTE: Some strings allocate memory internally for returned strings, just be careful!
|
||||||
RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal
|
RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal
|
||||||
RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending
|
RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending
|
||||||
RLAPI unsigned int TextCountCodepoints(const char *text); // Get total number of characters (codepoints) in a UTF8 encoded string
|
|
||||||
RLAPI const char *TextFormat(const char *text, ...); // Text formatting with variables (sprintf style)
|
RLAPI const char *TextFormat(const char *text, ...); // Text formatting with variables (sprintf style)
|
||||||
RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string
|
RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string
|
||||||
RLAPI char *TextReplace(char *text, const char *replace, const char *by); // Replace text string (memory should be freed!)
|
RLAPI char *TextReplace(char *text, const char *replace, const char *by); // Replace text string (memory must be freed!)
|
||||||
RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (memory should be freed!)
|
RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (memory must be freed!)
|
||||||
RLAPI const char *TextJoin(const char **textList, int count, const char *delimiter); // Join text strings with delimiter
|
RLAPI const char *TextJoin(const char **textList, int count, const char *delimiter); // Join text strings with delimiter
|
||||||
RLAPI const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings
|
RLAPI const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings
|
||||||
RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor!
|
RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor!
|
||||||
|
|
@ -1201,6 +1205,13 @@ RLAPI const char *TextToUpper(const char *text); // Get upp
|
||||||
RLAPI const char *TextToLower(const char *text); // Get lower case version of provided string
|
RLAPI const char *TextToLower(const char *text); // Get lower case version of provided string
|
||||||
RLAPI const char *TextToPascal(const char *text); // Get Pascal case notation version of provided string
|
RLAPI const char *TextToPascal(const char *text); // Get Pascal case notation version of provided string
|
||||||
RLAPI int TextToInteger(const char *text); // Get integer value from text (negative values not supported)
|
RLAPI int TextToInteger(const char *text); // Get integer value from text (negative values not supported)
|
||||||
|
RLAPI char *TextToUtf8(int *codepoints, int length); // Encode text codepoint into utf8 text (memory must be freed!)
|
||||||
|
|
||||||
|
// UTF8 text strings management functions
|
||||||
|
RLAPI int *GetCodepoints(const char *text, int *count); // Get all codepoints in a string, codepoints count returned by parameters
|
||||||
|
RLAPI int GetCodepointsCount(const char *text); // Get total number of characters (codepoints) in a UTF8 encoded string
|
||||||
|
RLAPI int GetNextCodepoint(const char *text, int *bytesProcessed); // Returns next codepoint in a UTF8 encoded string; 0x3f('?') is returned on failure
|
||||||
|
RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength); // Encode codepoint into utf8 text (char array length returned as parameter)
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Basic 3d Shapes Drawing Functions (Module: models)
|
// Basic 3d Shapes Drawing Functions (Module: models)
|
||||||
|
|
@ -1237,7 +1248,7 @@ RLAPI void UnloadModel(Model model);
|
||||||
// Mesh loading/unloading functions
|
// Mesh loading/unloading functions
|
||||||
RLAPI Mesh *LoadMeshes(const char *fileName, int *meshCount); // Load meshes from model file
|
RLAPI Mesh *LoadMeshes(const char *fileName, int *meshCount); // Load meshes from model file
|
||||||
RLAPI void ExportMesh(Mesh mesh, const char *fileName); // Export mesh data to file
|
RLAPI void ExportMesh(Mesh mesh, const char *fileName); // Export mesh data to file
|
||||||
RLAPI void UnloadMesh(Mesh *mesh); // Unload mesh from memory (RAM and/or VRAM)
|
RLAPI void UnloadMesh(Mesh mesh); // Unload mesh from memory (RAM and/or VRAM)
|
||||||
|
|
||||||
// Material loading/unloading functions
|
// Material loading/unloading functions
|
||||||
RLAPI Material *LoadMaterials(const char *fileName, int *materialCount); // Load materials from model file
|
RLAPI Material *LoadMaterials(const char *fileName, int *materialCount); // Load materials from model file
|
||||||
|
|
@ -1281,11 +1292,11 @@ RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRe
|
||||||
// Collision detection functions
|
// Collision detection functions
|
||||||
RLAPI bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres
|
RLAPI bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres
|
||||||
RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes
|
RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes
|
||||||
RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere
|
RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius); // Detect collision between box and sphere
|
||||||
RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius); // Detect collision between ray and sphere
|
RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 center, float radius); // Detect collision between ray and sphere
|
||||||
RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, Vector3 *collisionPoint); // Detect collision between ray and sphere, returns collision point
|
RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 center, float radius, Vector3 *collisionPoint); // Detect collision between ray and sphere, returns collision point
|
||||||
RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box
|
RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box
|
||||||
RLAPI RayHitInfo GetCollisionRayModel(Ray ray, Model *model); // Get collision info between ray and model
|
RLAPI RayHitInfo GetCollisionRayModel(Ray ray, Model model); // Get collision info between ray and model
|
||||||
RLAPI RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle
|
RLAPI RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle
|
||||||
RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight); // Get collision info between ray and ground plane (Y-normal plane)
|
RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight); // Get collision info between ray and ground plane (Y-normal plane)
|
||||||
|
|
||||||
|
|
@ -1297,7 +1308,7 @@ RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight);
|
||||||
// Shader loading/unloading functions
|
// Shader loading/unloading functions
|
||||||
RLAPI char *LoadText(const char *fileName); // Load chars array from text file
|
RLAPI char *LoadText(const char *fileName); // Load chars array from text file
|
||||||
RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations
|
RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations
|
||||||
RLAPI Shader LoadShaderCode(char *vsCode, char *fsCode); // Load shader from code strings and bind default locations
|
RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations
|
||||||
RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM)
|
RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM)
|
||||||
|
|
||||||
RLAPI Shader GetShaderDefault(void); // Get default shader
|
RLAPI Shader GetShaderDefault(void); // Get default shader
|
||||||
|
|
@ -1312,6 +1323,7 @@ RLAPI void SetShaderValueTexture(Shader shader, int uniformLoc, Texture2D textur
|
||||||
RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix)
|
RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix)
|
||||||
RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix)
|
RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix)
|
||||||
RLAPI Matrix GetMatrixModelview(void); // Get internal modelview matrix
|
RLAPI Matrix GetMatrixModelview(void); // Get internal modelview matrix
|
||||||
|
RLAPI Matrix GetMatrixProjection(void); // Get internal projection matrix
|
||||||
|
|
||||||
// Texture maps generation (PBR)
|
// Texture maps generation (PBR)
|
||||||
// NOTE: Required shaders should be provided
|
// NOTE: Required shaders should be provided
|
||||||
|
|
@ -1325,8 +1337,6 @@ RLAPI void BeginShaderMode(Shader shader); // Beg
|
||||||
RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader)
|
RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader)
|
||||||
RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied)
|
RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied)
|
||||||
RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending)
|
RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending)
|
||||||
RLAPI void BeginScissorMode(int x, int y, int width, int height); // Begin scissor mode (define screen area for following drawing)
|
|
||||||
RLAPI void EndScissorMode(void); // End scissor mode
|
|
||||||
|
|
||||||
// VR control functions
|
// VR control functions
|
||||||
RLAPI void InitVrSimulator(void); // Init VR simulator for selected device parameters
|
RLAPI void InitVrSimulator(void); // Init VR simulator for selected device parameters
|
||||||
|
|
@ -1393,7 +1403,7 @@ RLAPI float GetMusicTimePlayed(Music music); // Get cur
|
||||||
RLAPI AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream raw audio pcm data)
|
RLAPI AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream raw audio pcm data)
|
||||||
RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data
|
RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data
|
||||||
RLAPI void CloseAudioStream(AudioStream stream); // Close audio stream and free memory
|
RLAPI void CloseAudioStream(AudioStream stream); // Close audio stream and free memory
|
||||||
RLAPI bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill
|
RLAPI bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill
|
||||||
RLAPI void PlayAudioStream(AudioStream stream); // Play audio stream
|
RLAPI void PlayAudioStream(AudioStream stream); // Play audio stream
|
||||||
RLAPI void PauseAudioStream(AudioStream stream); // Pause audio stream
|
RLAPI void PauseAudioStream(AudioStream stream); // Pause audio stream
|
||||||
RLAPI void ResumeAudioStream(AudioStream stream); // Resume audio stream
|
RLAPI void ResumeAudioStream(AudioStream stream); // Resume audio stream
|
||||||
|
|
@ -1401,7 +1411,7 @@ RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check i
|
||||||
RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream
|
RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream
|
||||||
RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
|
RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
|
||||||
RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
|
RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Network (Module: network)
|
// Network (Module: network)
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
103
src/raymath.h
|
|
@ -20,7 +20,7 @@
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2017 Ramon Santamaria (@raysan5)
|
* Copyright (c) 2015-2019 Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||||
* will the authors be held liable for any damages arising from the use of this software.
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
#if defined(RAYMATH_IMPLEMENTATION)
|
#if defined(RAYMATH_IMPLEMENTATION)
|
||||||
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
|
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
|
||||||
#define RMDEF __declspec(dllexport) extern inline // We are building raylib as a Win32 shared library (.dll).
|
#define RMDEF __declspec(dllexport) extern inline // We are building raylib as a Win32 shared library (.dll).
|
||||||
#elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED)
|
#elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED)
|
||||||
#define RMDEF __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll)
|
#define RMDEF __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll)
|
||||||
#else
|
#else
|
||||||
#define RMDEF extern inline // Provide external definition
|
#define RMDEF extern inline // Provide external definition
|
||||||
|
|
@ -113,7 +113,7 @@
|
||||||
float y;
|
float y;
|
||||||
float z;
|
float z;
|
||||||
} Vector3;
|
} Vector3;
|
||||||
|
|
||||||
// Quaternion type
|
// Quaternion type
|
||||||
typedef struct Quaternion {
|
typedef struct Quaternion {
|
||||||
float x;
|
float x;
|
||||||
|
|
@ -148,7 +148,7 @@ RMDEF float Clamp(float value, float min, float max)
|
||||||
return res > max ? max : res;
|
return res > max ? max : res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate linear interpolation between two vectors
|
// Calculate linear interpolation between two floats
|
||||||
RMDEF float Lerp(float start, float end, float amount)
|
RMDEF float Lerp(float start, float end, float amount)
|
||||||
{
|
{
|
||||||
return start + amount*(end - start);
|
return start + amount*(end - start);
|
||||||
|
|
@ -225,8 +225,8 @@ RMDEF Vector2 Vector2Scale(Vector2 v, float scale)
|
||||||
// Multiply vector by vector
|
// Multiply vector by vector
|
||||||
RMDEF Vector2 Vector2MultiplyV(Vector2 v1, Vector2 v2)
|
RMDEF Vector2 Vector2MultiplyV(Vector2 v1, Vector2 v2)
|
||||||
{
|
{
|
||||||
Vector2 result = { v1.x*v2.x, v1.y*v2.y };
|
Vector2 result = { v1.x*v2.x, v1.y*v2.y };
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Negate vector
|
// Negate vector
|
||||||
|
|
@ -246,8 +246,8 @@ RMDEF Vector2 Vector2Divide(Vector2 v, float div)
|
||||||
// Divide vector by vector
|
// Divide vector by vector
|
||||||
RMDEF Vector2 Vector2DivideV(Vector2 v1, Vector2 v2)
|
RMDEF Vector2 Vector2DivideV(Vector2 v1, Vector2 v2)
|
||||||
{
|
{
|
||||||
Vector2 result = { v1.x/v2.x, v1.y/v2.y };
|
Vector2 result = { v1.x/v2.x, v1.y/v2.y };
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize provided vector
|
// Normalize provided vector
|
||||||
|
|
@ -388,15 +388,15 @@ RMDEF Vector3 Vector3Negate(Vector3 v)
|
||||||
// Divide vector by a float value
|
// Divide vector by a float value
|
||||||
RMDEF Vector3 Vector3Divide(Vector3 v, float div)
|
RMDEF Vector3 Vector3Divide(Vector3 v, float div)
|
||||||
{
|
{
|
||||||
Vector3 result = { v.x / div, v.y / div, v.z / div };
|
Vector3 result = { v.x / div, v.y / div, v.z / div };
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Divide vector by vector
|
// Divide vector by vector
|
||||||
RMDEF Vector3 Vector3DivideV(Vector3 v1, Vector3 v2)
|
RMDEF Vector3 Vector3DivideV(Vector3 v1, Vector3 v2)
|
||||||
{
|
{
|
||||||
Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z };
|
Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z };
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize provided vector
|
// Normalize provided vector
|
||||||
|
|
@ -794,6 +794,33 @@ RMDEF Matrix MatrixRotate(Vector3 axis, float angle)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns xyz-rotation matrix (angles in radians)
|
||||||
|
RMDEF Matrix MatrixRotateXYZ(Vector3 ang)
|
||||||
|
{
|
||||||
|
Matrix result = MatrixIdentity();
|
||||||
|
|
||||||
|
float cosz = cosf(-ang.z);
|
||||||
|
float sinz = sinf(-ang.z);
|
||||||
|
float cosy = cosf(-ang.y);
|
||||||
|
float siny = sinf(-ang.y);
|
||||||
|
float cosx = cosf(-ang.x);
|
||||||
|
float sinx = sinf(-ang.x);
|
||||||
|
|
||||||
|
result.m0 = cosz * cosy;
|
||||||
|
result.m4 = (cosz * siny * sinx) - (sinz * cosx);
|
||||||
|
result.m8 = (cosz * siny * cosx) + (sinz * sinx);
|
||||||
|
|
||||||
|
result.m1 = sinz * cosy;
|
||||||
|
result.m5 = (sinz * siny * sinx) + (cosz * cosx);
|
||||||
|
result.m9 = (sinz * siny * cosx) - (cosz * sinx);
|
||||||
|
|
||||||
|
result.m2 = -siny;
|
||||||
|
result.m6 = cosy * sinx;
|
||||||
|
result.m10= cosy * cosx;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns x-rotation matrix (angle in radians)
|
// Returns x-rotation matrix (angle in radians)
|
||||||
RMDEF Matrix MatrixRotateX(float angle)
|
RMDEF Matrix MatrixRotateX(float angle)
|
||||||
{
|
{
|
||||||
|
|
@ -1159,7 +1186,7 @@ RMDEF Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)
|
||||||
// Above lines are equivalent to:
|
// Above lines are equivalent to:
|
||||||
//Quaternion result = QuaternionNlerp(q, QuaternionIdentity(), 0.5f);
|
//Quaternion result = QuaternionNlerp(q, QuaternionIdentity(), 0.5f);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a quaternion for a given rotation matrix
|
// Returns a quaternion for a given rotation matrix
|
||||||
|
|
@ -1320,21 +1347,21 @@ RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle
|
||||||
// Returns he quaternion equivalent to Euler angles
|
// Returns he quaternion equivalent to Euler angles
|
||||||
RMDEF Quaternion QuaternionFromEuler(float roll, float pitch, float yaw)
|
RMDEF Quaternion QuaternionFromEuler(float roll, float pitch, float yaw)
|
||||||
{
|
{
|
||||||
Quaternion q = { 0 };
|
Quaternion q = { 0 };
|
||||||
|
|
||||||
float x0 = cosf(roll*0.5f);
|
float x0 = cosf(roll*0.5f);
|
||||||
float x1 = sinf(roll*0.5f);
|
float x1 = sinf(roll*0.5f);
|
||||||
float y0 = cosf(pitch*0.5f);
|
float y0 = cosf(pitch*0.5f);
|
||||||
float y1 = sinf(pitch*0.5f);
|
float y1 = sinf(pitch*0.5f);
|
||||||
float z0 = cosf(yaw*0.5f);
|
float z0 = cosf(yaw*0.5f);
|
||||||
float z1 = sinf(yaw*0.5f);
|
float z1 = sinf(yaw*0.5f);
|
||||||
|
|
||||||
q.x = x1*y0*z0 - x0*y1*z1;
|
q.x = x1*y0*z0 - x0*y1*z1;
|
||||||
q.y = x0*y1*z0 + x1*y0*z1;
|
q.y = x0*y1*z0 + x1*y0*z1;
|
||||||
q.z = x0*y0*z1 - x1*y1*z0;
|
q.z = x0*y0*z1 - x1*y1*z0;
|
||||||
q.w = x0*y0*z0 + x1*y1*z1;
|
q.w = x0*y0*z0 + x1*y1*z1;
|
||||||
|
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the Euler angles equivalent to quaternion (roll, pitch, yaw)
|
// Return the Euler angles equivalent to quaternion (roll, pitch, yaw)
|
||||||
|
|
@ -1343,21 +1370,21 @@ RMDEF Vector3 QuaternionToEuler(Quaternion q)
|
||||||
{
|
{
|
||||||
Vector3 result = { 0 };
|
Vector3 result = { 0 };
|
||||||
|
|
||||||
// roll (x-axis rotation)
|
// roll (x-axis rotation)
|
||||||
float x0 = 2.0f*(q.w*q.x + q.y*q.z);
|
float x0 = 2.0f*(q.w*q.x + q.y*q.z);
|
||||||
float x1 = 1.0f - 2.0f*(q.x*q.x + q.y*q.y);
|
float x1 = 1.0f - 2.0f*(q.x*q.x + q.y*q.y);
|
||||||
result.x = atan2f(x0, x1)*RAD2DEG;
|
result.x = atan2f(x0, x1)*RAD2DEG;
|
||||||
|
|
||||||
// pitch (y-axis rotation)
|
// pitch (y-axis rotation)
|
||||||
float y0 = 2.0f*(q.w*q.y - q.z*q.x);
|
float y0 = 2.0f*(q.w*q.y - q.z*q.x);
|
||||||
y0 = y0 > 1.0f ? 1.0f : y0;
|
y0 = y0 > 1.0f ? 1.0f : y0;
|
||||||
y0 = y0 < -1.0f ? -1.0f : y0;
|
y0 = y0 < -1.0f ? -1.0f : y0;
|
||||||
result.y = asinf(y0)*RAD2DEG;
|
result.y = asinf(y0)*RAD2DEG;
|
||||||
|
|
||||||
// yaw (z-axis rotation)
|
// yaw (z-axis rotation)
|
||||||
float z0 = 2.0f*(q.w*q.z + q.x*q.y);
|
float z0 = 2.0f*(q.w*q.z + q.x*q.y);
|
||||||
float z1 = 1.0f - 2.0f*(q.y*q.y + q.z*q.z);
|
float z1 = 1.0f - 2.0f*(q.y*q.y + q.z*q.z);
|
||||||
result.z = atan2f(z0, z1)*RAD2DEG;
|
result.z = atan2f(z0, z1)*RAD2DEG;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* rglfw - raylib GLFW single file compilation
|
* rglfw - raylib GLFW single file compilation
|
||||||
*
|
*
|
||||||
* This file includes latest GLFW sources (https://github.com/glfw/glfw) to be compiled together
|
* This file includes latest GLFW sources (https://github.com/glfw/glfw) to be compiled together
|
||||||
* with raylib for all supported platforms, this way, no external dependencies are required.
|
* with raylib for all supported platforms, this way, no external dependencies are required.
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
#define _GLFW_USE_RETINA // To have windows use the full resolution of Retina displays
|
#define _GLFW_USE_RETINA // To have windows use the full resolution of Retina displays
|
||||||
#endif
|
#endif
|
||||||
#if defined(__TINYC__)
|
#if defined(__TINYC__)
|
||||||
#define _WIN32_WINNT_WINXP 0x0501
|
#define _WIN32_WINNT_WINXP 0x0501
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// NOTE: _GLFW_MIR experimental platform not supported at this moment
|
// NOTE: _GLFW_MIR experimental platform not supported at this moment
|
||||||
|
|
|
||||||
181
src/rlgl.h
|
|
@ -131,6 +131,10 @@
|
||||||
#define MAX_MATRIX_STACK_SIZE 32 // Max size of Matrix stack
|
#define MAX_MATRIX_STACK_SIZE 32 // Max size of Matrix stack
|
||||||
#define MAX_DRAWCALL_REGISTERED 256 // Max draws by state changes (mode, texture)
|
#define MAX_DRAWCALL_REGISTERED 256 // Max draws by state changes (mode, texture)
|
||||||
|
|
||||||
|
// Shader and material limits
|
||||||
|
#define MAX_SHADER_LOCATIONS 32 // Maximum number of predefined locations stored in shader struct
|
||||||
|
#define MAX_MATERIAL_MAPS 12 // Maximum number of texture maps stored in shader struct
|
||||||
|
|
||||||
// Texture parameters (equivalent to OpenGL defines)
|
// Texture parameters (equivalent to OpenGL defines)
|
||||||
#define RL_TEXTURE_WRAP_S 0x2802 // GL_TEXTURE_WRAP_S
|
#define RL_TEXTURE_WRAP_S 0x2802 // GL_TEXTURE_WRAP_S
|
||||||
#define RL_TEXTURE_WRAP_T 0x2803 // GL_TEXTURE_WRAP_T
|
#define RL_TEXTURE_WRAP_T 0x2803 // GL_TEXTURE_WRAP_T
|
||||||
|
|
@ -228,7 +232,7 @@ typedef unsigned char byte;
|
||||||
|
|
||||||
// OpenGL identifiers
|
// OpenGL identifiers
|
||||||
unsigned int vaoId; // OpenGL Vertex Array Object id
|
unsigned int vaoId; // OpenGL Vertex Array Object id
|
||||||
unsigned int vboId[7]; // OpenGL Vertex Buffer Objects id (7 types of vertex data)
|
unsigned int *vboId; // OpenGL Vertex Buffer Objects id (7 types of vertex data)
|
||||||
} Mesh;
|
} Mesh;
|
||||||
|
|
||||||
// Shader and material limits
|
// Shader and material limits
|
||||||
|
|
@ -237,8 +241,8 @@ typedef unsigned char byte;
|
||||||
|
|
||||||
// Shader type (generic)
|
// Shader type (generic)
|
||||||
typedef struct Shader {
|
typedef struct Shader {
|
||||||
unsigned int id; // Shader program id
|
unsigned int id; // Shader program id
|
||||||
int locs[MAX_SHADER_LOCATIONS]; // Shader locations array
|
int *locs; // Shader locations array (MAX_SHADER_LOCATIONS)
|
||||||
} Shader;
|
} Shader;
|
||||||
|
|
||||||
// Material texture map
|
// Material texture map
|
||||||
|
|
@ -251,7 +255,7 @@ typedef unsigned char byte;
|
||||||
// Material type (generic)
|
// Material type (generic)
|
||||||
typedef struct Material {
|
typedef struct Material {
|
||||||
Shader shader; // Material shader
|
Shader shader; // Material shader
|
||||||
MaterialMap maps[MAX_MATERIAL_MAPS]; // Material maps
|
MaterialMap *maps; // Material maps (MAX_MATERIAL_MAPS)
|
||||||
float *params; // Material generic parameters (if required)
|
float *params; // Material generic parameters (if required)
|
||||||
} Material;
|
} Material;
|
||||||
|
|
||||||
|
|
@ -453,6 +457,9 @@ RLAPI void rlEnableDepthTest(void); // Enable depth te
|
||||||
RLAPI void rlDisableDepthTest(void); // Disable depth test
|
RLAPI void rlDisableDepthTest(void); // Disable depth test
|
||||||
RLAPI void rlEnableBackfaceCulling(void); // Enable backface culling
|
RLAPI void rlEnableBackfaceCulling(void); // Enable backface culling
|
||||||
RLAPI void rlDisableBackfaceCulling(void); // Disable backface culling
|
RLAPI void rlDisableBackfaceCulling(void); // Disable backface culling
|
||||||
|
RLAPI void rlEnableScissorTest(void); // Enable scissor test
|
||||||
|
RLAPI void rlDisableScissorTest(void); // Disable scissor test
|
||||||
|
RLAPI void rlScissor(int x, int y, int width, int height); // Scissor test
|
||||||
RLAPI void rlEnableWireMode(void); // Enable wire mode
|
RLAPI void rlEnableWireMode(void); // Enable wire mode
|
||||||
RLAPI void rlDisableWireMode(void); // Disable wire mode
|
RLAPI void rlDisableWireMode(void); // Disable wire mode
|
||||||
RLAPI void rlDeleteTextures(unsigned int id); // Delete OpenGL texture from GPU
|
RLAPI void rlDeleteTextures(unsigned int id); // Delete OpenGL texture from GPU
|
||||||
|
|
@ -499,7 +506,7 @@ RLAPI bool rlRenderTextureComplete(RenderTexture target); // Ver
|
||||||
RLAPI void rlLoadMesh(Mesh *mesh, bool dynamic); // Upload vertex data into GPU and provided VAO/VBO ids
|
RLAPI void rlLoadMesh(Mesh *mesh, bool dynamic); // Upload vertex data into GPU and provided VAO/VBO ids
|
||||||
RLAPI void rlUpdateMesh(Mesh mesh, int buffer, int numVertex); // Update vertex data on GPU (upload new data to one buffer)
|
RLAPI void rlUpdateMesh(Mesh mesh, int buffer, int numVertex); // Update vertex data on GPU (upload new data to one buffer)
|
||||||
RLAPI void rlDrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform
|
RLAPI void rlDrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform
|
||||||
RLAPI void rlUnloadMesh(Mesh *mesh); // Unload mesh data from CPU and GPU
|
RLAPI void rlUnloadMesh(Mesh mesh); // Unload mesh data from CPU and GPU
|
||||||
|
|
||||||
// NOTE: There is a set of shader related functions that are available to end user,
|
// NOTE: There is a set of shader related functions that are available to end user,
|
||||||
// to avoid creating function wrappers through core module, they have been directly declared in raylib.h
|
// to avoid creating function wrappers through core module, they have been directly declared in raylib.h
|
||||||
|
|
@ -512,7 +519,7 @@ RLAPI void rlUnloadMesh(Mesh *mesh); // Unl
|
||||||
// Shader loading/unloading functions
|
// Shader loading/unloading functions
|
||||||
RLAPI char *LoadText(const char *fileName); // Load chars array from text file
|
RLAPI char *LoadText(const char *fileName); // Load chars array from text file
|
||||||
RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations
|
RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations
|
||||||
RLAPI Shader LoadShaderCode(char *vsCode, char *fsCode); // Load shader from code strings and bind default locations
|
RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations
|
||||||
RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM)
|
RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM)
|
||||||
|
|
||||||
RLAPI Shader GetShaderDefault(void); // Get default shader
|
RLAPI Shader GetShaderDefault(void); // Get default shader
|
||||||
|
|
@ -1340,28 +1347,25 @@ void rlDisableRenderTexture(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable depth test
|
// Enable depth test
|
||||||
void rlEnableDepthTest(void)
|
void rlEnableDepthTest(void) { glEnable(GL_DEPTH_TEST); }
|
||||||
{
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable depth test
|
// Disable depth test
|
||||||
void rlDisableDepthTest(void)
|
void rlDisableDepthTest(void) { glDisable(GL_DEPTH_TEST); }
|
||||||
{
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable backface culling
|
// Enable backface culling
|
||||||
void rlEnableBackfaceCulling(void)
|
void rlEnableBackfaceCulling(void) { glEnable(GL_CULL_FACE); }
|
||||||
{
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable backface culling
|
// Disable backface culling
|
||||||
void rlDisableBackfaceCulling(void)
|
void rlDisableBackfaceCulling(void) { glDisable(GL_CULL_FACE); }
|
||||||
{
|
|
||||||
glDisable(GL_CULL_FACE);
|
// Enable scissor test
|
||||||
}
|
RLAPI void rlEnableScissorTest(void) { glEnable(GL_SCISSOR_TEST); }
|
||||||
|
|
||||||
|
// Disable scissor test
|
||||||
|
RLAPI void rlDisableScissorTest(void) { glDisable(GL_SCISSOR_TEST); }
|
||||||
|
|
||||||
|
// Scissor test
|
||||||
|
RLAPI void rlScissor(int x, int y, int width, int height) { glScissor(x, y, width, height); }
|
||||||
|
|
||||||
// Enable wire mode
|
// Enable wire mode
|
||||||
void rlEnableWireMode(void)
|
void rlEnableWireMode(void)
|
||||||
|
|
@ -1523,26 +1527,35 @@ void rlglInit(int width, int height)
|
||||||
|
|
||||||
// Allocate numExt strings pointers
|
// Allocate numExt strings pointers
|
||||||
const char **extList = RL_MALLOC(sizeof(const char *)*numExt);
|
const char **extList = RL_MALLOC(sizeof(const char *)*numExt);
|
||||||
|
|
||||||
// Get extensions strings
|
// Get extensions strings
|
||||||
for (int i = 0; i < numExt; i++) extList[i] = (char *)glGetStringi(GL_EXTENSIONS, i);
|
for (int i = 0; i < numExt; i++) extList[i] = (const char *)glGetStringi(GL_EXTENSIONS, i);
|
||||||
|
|
||||||
#elif defined(GRAPHICS_API_OPENGL_ES2)
|
#elif defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
// Allocate 512 strings pointers (2 KB)
|
// Allocate 512 strings pointers (2 KB)
|
||||||
const char **extList = RL_MALLOC(sizeof(const char *)*512);
|
const char **extList = RL_MALLOC(sizeof(const char *)*512);
|
||||||
|
|
||||||
// Get extensions strings
|
const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string
|
||||||
char *extensions = (char *)glGetString(GL_EXTENSIONS); // One big static const string returned
|
|
||||||
int len = strlen(extensions);
|
// NOTE: We have to duplicate string because glGetString() returns a const string
|
||||||
|
int len = strlen(extensions) + 1;
|
||||||
|
char *extensionsDup = (char *)RL_CALLOC(len, sizeof(char));
|
||||||
|
strcpy(extensionsDup, extensions);
|
||||||
|
|
||||||
|
extList[numExt] = extensionsDup;
|
||||||
|
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
if (i == ' ')
|
if (extensionsDup[i] == ' ')
|
||||||
{
|
{
|
||||||
extList[numExt] = &extensions[i + 1];
|
extensionsDup[i] = '\0';
|
||||||
|
|
||||||
numExt++;
|
numExt++;
|
||||||
|
extList[numExt] = &extensionsDup[i + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: Duplicated string (extensionsDup) must be deallocated
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TraceLog(LOG_INFO, "Number of supported extensions: %i", numExt);
|
TraceLog(LOG_INFO, "Number of supported extensions: %i", numExt);
|
||||||
|
|
@ -1618,6 +1631,8 @@ void rlglInit(int width, int height)
|
||||||
RL_FREE(extList);
|
RL_FREE(extList);
|
||||||
|
|
||||||
#if defined(GRAPHICS_API_OPENGL_ES2)
|
#if defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
|
RL_FREE(extensionsDup); // Duplicated string must be deallocated
|
||||||
|
|
||||||
if (vaoSupported) TraceLog(LOG_INFO, "[EXTENSION] VAO extension detected, VAO functions initialized successfully");
|
if (vaoSupported) TraceLog(LOG_INFO, "[EXTENSION] VAO extension detected, VAO functions initialized successfully");
|
||||||
else TraceLog(LOG_WARNING, "[EXTENSION] VAO extension not found, VAO usage not supported");
|
else TraceLog(LOG_WARNING, "[EXTENSION] VAO extension not found, VAO usage not supported");
|
||||||
|
|
||||||
|
|
@ -1683,7 +1698,6 @@ void rlglInit(int width, int height)
|
||||||
|
|
||||||
// Initialize OpenGL default states
|
// Initialize OpenGL default states
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
|
|
||||||
// Init state: Depth test
|
// Init state: Depth test
|
||||||
glDepthFunc(GL_LEQUAL); // Type of depth testing to apply
|
glDepthFunc(GL_LEQUAL); // Type of depth testing to apply
|
||||||
glDisable(GL_DEPTH_TEST); // Disable depth testing for 2D (only used for 3D)
|
glDisable(GL_DEPTH_TEST); // Disable depth testing for 2D (only used for 3D)
|
||||||
|
|
@ -2622,11 +2636,11 @@ void rlDrawMesh(Mesh mesh, Material material, Matrix transform)
|
||||||
// That's because BeginMode3D() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix()
|
// That's because BeginMode3D() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix()
|
||||||
Matrix matView = modelview; // View matrix (camera)
|
Matrix matView = modelview; // View matrix (camera)
|
||||||
Matrix matProjection = projection; // Projection matrix (perspective)
|
Matrix matProjection = projection; // Projection matrix (perspective)
|
||||||
|
|
||||||
// TODO: Matrix nightmare! Trying to combine stack matrices with view matrix and local model transform matrix..
|
// 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...
|
// There is some problem in the order matrices are multiplied... it requires some time to figure out...
|
||||||
Matrix matStackTransform = MatrixIdentity();
|
Matrix matStackTransform = MatrixIdentity();
|
||||||
|
|
||||||
// TODO: Consider possible transform matrices in the stack
|
// 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?
|
// 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);
|
//for (int i = stackCounter; i > 0; i--) matStackTransform = MatrixMultiply(stack[i], matStackTransform);
|
||||||
|
|
@ -2757,30 +2771,30 @@ void rlDrawMesh(Mesh mesh, Material material, Matrix transform)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unload mesh data from CPU and GPU
|
// Unload mesh data from CPU and GPU
|
||||||
void rlUnloadMesh(Mesh *mesh)
|
void rlUnloadMesh(Mesh mesh)
|
||||||
{
|
{
|
||||||
RL_FREE(mesh->vertices);
|
RL_FREE(mesh.vertices);
|
||||||
RL_FREE(mesh->texcoords);
|
RL_FREE(mesh.texcoords);
|
||||||
RL_FREE(mesh->normals);
|
RL_FREE(mesh.normals);
|
||||||
RL_FREE(mesh->colors);
|
RL_FREE(mesh.colors);
|
||||||
RL_FREE(mesh->tangents);
|
RL_FREE(mesh.tangents);
|
||||||
RL_FREE(mesh->texcoords2);
|
RL_FREE(mesh.texcoords2);
|
||||||
RL_FREE(mesh->indices);
|
RL_FREE(mesh.indices);
|
||||||
|
|
||||||
RL_FREE(mesh->animVertices);
|
RL_FREE(mesh.animVertices);
|
||||||
RL_FREE(mesh->animNormals);
|
RL_FREE(mesh.animNormals);
|
||||||
RL_FREE(mesh->boneWeights);
|
RL_FREE(mesh.boneWeights);
|
||||||
RL_FREE(mesh->boneIds);
|
RL_FREE(mesh.boneIds);
|
||||||
|
|
||||||
rlDeleteBuffers(mesh->vboId[0]); // vertex
|
rlDeleteBuffers(mesh.vboId[0]); // vertex
|
||||||
rlDeleteBuffers(mesh->vboId[1]); // texcoords
|
rlDeleteBuffers(mesh.vboId[1]); // texcoords
|
||||||
rlDeleteBuffers(mesh->vboId[2]); // normals
|
rlDeleteBuffers(mesh.vboId[2]); // normals
|
||||||
rlDeleteBuffers(mesh->vboId[3]); // colors
|
rlDeleteBuffers(mesh.vboId[3]); // colors
|
||||||
rlDeleteBuffers(mesh->vboId[4]); // tangents
|
rlDeleteBuffers(mesh.vboId[4]); // tangents
|
||||||
rlDeleteBuffers(mesh->vboId[5]); // texcoords2
|
rlDeleteBuffers(mesh.vboId[5]); // texcoords2
|
||||||
rlDeleteBuffers(mesh->vboId[6]); // indices
|
rlDeleteBuffers(mesh.vboId[6]); // indices
|
||||||
|
|
||||||
rlDeleteVertexArrays(mesh->vaoId);
|
rlDeleteVertexArrays(mesh.vaoId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read screen pixel data (color buffer)
|
// Read screen pixel data (color buffer)
|
||||||
|
|
@ -2954,6 +2968,8 @@ Shader LoadShader(const char *vsFileName, const char *fsFileName)
|
||||||
{
|
{
|
||||||
Shader shader = { 0 };
|
Shader shader = { 0 };
|
||||||
|
|
||||||
|
// NOTE: Shader.locs is allocated by LoadShaderCode()
|
||||||
|
|
||||||
char *vShaderStr = NULL;
|
char *vShaderStr = NULL;
|
||||||
char *fShaderStr = NULL;
|
char *fShaderStr = NULL;
|
||||||
|
|
||||||
|
|
@ -2970,9 +2986,10 @@ Shader LoadShader(const char *vsFileName, const char *fsFileName)
|
||||||
|
|
||||||
// Load shader from code strings
|
// Load shader from code strings
|
||||||
// NOTE: If shader string is NULL, using default vertex/fragment shaders
|
// NOTE: If shader string is NULL, using default vertex/fragment shaders
|
||||||
Shader LoadShaderCode(char *vsCode, char *fsCode)
|
Shader LoadShaderCode(const char *vsCode, const char *fsCode)
|
||||||
{
|
{
|
||||||
Shader shader = { 0 };
|
Shader shader = { 0 };
|
||||||
|
shader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS, sizeof(int));
|
||||||
|
|
||||||
// NOTE: All locations must be reseted to -1 (no location)
|
// NOTE: All locations must be reseted to -1 (no location)
|
||||||
for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
|
for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
|
||||||
|
|
@ -3008,7 +3025,7 @@ Shader LoadShaderCode(char *vsCode, char *fsCode)
|
||||||
|
|
||||||
glGetProgramiv(shader.id, GL_ACTIVE_UNIFORMS, &uniformCount);
|
glGetProgramiv(shader.id, GL_ACTIVE_UNIFORMS, &uniformCount);
|
||||||
|
|
||||||
for(int i = 0; i < uniformCount; i++)
|
for (int i = 0; i < uniformCount; i++)
|
||||||
{
|
{
|
||||||
int namelen = -1;
|
int namelen = -1;
|
||||||
int num = -1;
|
int num = -1;
|
||||||
|
|
@ -3038,6 +3055,8 @@ void UnloadShader(Shader shader)
|
||||||
rlDeleteShader(shader.id);
|
rlDeleteShader(shader.id);
|
||||||
TraceLog(LOG_INFO, "[SHDR ID %i] Unloaded shader program data", shader.id);
|
TraceLog(LOG_INFO, "[SHDR ID %i] Unloaded shader program data", shader.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RL_FREE(shader.locs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin custom shader mode
|
// Begin custom shader mode
|
||||||
|
|
@ -3136,6 +3155,23 @@ void SetMatrixProjection(Matrix proj)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return internal projection matrix
|
||||||
|
Matrix GetMatrixProjection(void) {
|
||||||
|
#if defined(GRAPHICS_API_OPENGL_11)
|
||||||
|
float mat[16];
|
||||||
|
glGetFloatv(GL_PROJECTION_MATRIX,mat);
|
||||||
|
Matrix m;
|
||||||
|
m.m0 = mat[0]; m.m1 = mat[1]; m.m2 = mat[2]; m.m3 = mat[3];
|
||||||
|
m.m4 = mat[4]; m.m5 = mat[5]; m.m6 = mat[6]; m.m7 = mat[7];
|
||||||
|
m.m8 = mat[8]; m.m9 = mat[9]; m.m10 = mat[10]; m.m11 = mat[11];
|
||||||
|
m.m12 = mat[12]; m.m13 = mat[13]; m.m14 = mat[14]; m.m15 = mat[15];
|
||||||
|
return m;
|
||||||
|
#else
|
||||||
|
return projection;
|
||||||
|
#endif
|
||||||
|
#
|
||||||
|
}
|
||||||
|
|
||||||
// Set a custom modelview matrix (replaces internal modelview matrix)
|
// Set a custom modelview matrix (replaces internal modelview matrix)
|
||||||
void SetMatrixModelview(Matrix view)
|
void SetMatrixModelview(Matrix view)
|
||||||
{
|
{
|
||||||
|
|
@ -3151,6 +3187,10 @@ Matrix GetMatrixModelview(void)
|
||||||
#if defined(GRAPHICS_API_OPENGL_11)
|
#if defined(GRAPHICS_API_OPENGL_11)
|
||||||
float mat[16];
|
float mat[16];
|
||||||
glGetFloatv(GL_MODELVIEW_MATRIX, mat);
|
glGetFloatv(GL_MODELVIEW_MATRIX, mat);
|
||||||
|
matrix.m0 = mat[0]; matrix.m1 = mat[1]; matrix.m2 = mat[2]; matrix.m3 = mat[3];
|
||||||
|
matrix.m4 = mat[4]; matrix.m5 = mat[5]; matrix.m6 = mat[6]; matrix.m7 = mat[7];
|
||||||
|
matrix.m8 = mat[8]; matrix.m9 = mat[9]; matrix.m10 = mat[10]; matrix.m11 = mat[11];
|
||||||
|
matrix.m12 = mat[12]; matrix.m13 = mat[13]; matrix.m14 = mat[14]; matrix.m15 = mat[15];
|
||||||
#else
|
#else
|
||||||
matrix = modelview;
|
matrix = modelview;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -3505,24 +3545,6 @@ void EndBlendMode(void)
|
||||||
BeginBlendMode(BLEND_ALPHA);
|
BeginBlendMode(BLEND_ALPHA);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin scissor mode (define screen area for following drawing)
|
|
||||||
// NOTE: Scissor rec refers to bottom-left corner, we change it to upper-left
|
|
||||||
void BeginScissorMode(int x, int y, int width, int height)
|
|
||||||
{
|
|
||||||
rlglDraw(); // Force drawing elements
|
|
||||||
|
|
||||||
glEnable(GL_SCISSOR_TEST);
|
|
||||||
glScissor(x, framebufferHeight - (y + height), width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
// End scissor mode
|
|
||||||
void EndScissorMode(void)
|
|
||||||
{
|
|
||||||
rlglDraw(); // Force drawing elements
|
|
||||||
|
|
||||||
glDisable(GL_SCISSOR_TEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(SUPPORT_VR_SIMULATOR)
|
#if defined(SUPPORT_VR_SIMULATOR)
|
||||||
// Init VR simulator for selected device parameters
|
// Init VR simulator for selected device parameters
|
||||||
// NOTE: It modifies the global variable: stereoFbo
|
// NOTE: It modifies the global variable: stereoFbo
|
||||||
|
|
@ -3861,12 +3883,13 @@ static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShad
|
||||||
static Shader LoadShaderDefault(void)
|
static Shader LoadShaderDefault(void)
|
||||||
{
|
{
|
||||||
Shader shader = { 0 };
|
Shader shader = { 0 };
|
||||||
|
shader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS, sizeof(int));
|
||||||
|
|
||||||
// NOTE: All locations must be reseted to -1 (no location)
|
// NOTE: All locations must be reseted to -1 (no location)
|
||||||
for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
|
for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
|
||||||
|
|
||||||
// Vertex shader directly defined, no external file required
|
// Vertex shader directly defined, no external file required
|
||||||
char defaultVShaderStr[] =
|
const char *defaultVShaderStr =
|
||||||
#if defined(GRAPHICS_API_OPENGL_21)
|
#if defined(GRAPHICS_API_OPENGL_21)
|
||||||
"#version 120 \n"
|
"#version 120 \n"
|
||||||
#elif defined(GRAPHICS_API_OPENGL_ES2)
|
#elif defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
|
|
@ -3895,7 +3918,7 @@ static Shader LoadShaderDefault(void)
|
||||||
"} \n";
|
"} \n";
|
||||||
|
|
||||||
// Fragment shader directly defined, no external file required
|
// Fragment shader directly defined, no external file required
|
||||||
char defaultFShaderStr[] =
|
const char *defaultFShaderStr =
|
||||||
#if defined(GRAPHICS_API_OPENGL_21)
|
#if defined(GRAPHICS_API_OPENGL_21)
|
||||||
"#version 120 \n"
|
"#version 120 \n"
|
||||||
#elif defined(GRAPHICS_API_OPENGL_ES2)
|
#elif defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
|
|
@ -4615,6 +4638,14 @@ int GetPixelDataSize(int width, int height, int format)
|
||||||
|
|
||||||
dataSize = width*height*bpp/8; // Total data size in bytes
|
dataSize = width*height*bpp/8; // Total data size in bytes
|
||||||
|
|
||||||
|
// Most compressed formats works on 4x4 blocks,
|
||||||
|
// if texture is smaller, minimum dataSize is 8 or 16
|
||||||
|
if ((width < 4) && (height < 4))
|
||||||
|
{
|
||||||
|
if ((format >= COMPRESSED_DXT1_RGB) && (format < COMPRESSED_DXT3_RGBA)) dataSize = 8;
|
||||||
|
else if ((format >= COMPRESSED_DXT3_RGBA) && (format < COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16;
|
||||||
|
}
|
||||||
|
|
||||||
return dataSize;
|
return dataSize;
|
||||||
}
|
}
|
||||||
#endif // RLGL_STANDALONE
|
#endif // RLGL_STANDALONE
|
||||||
|
|
|
||||||
170
src/rmem.h
|
|
@ -5,7 +5,7 @@
|
||||||
* A quick, efficient, and minimal free list and stack-based allocator
|
* A quick, efficient, and minimal free list and stack-based allocator
|
||||||
*
|
*
|
||||||
* PURPOSE:
|
* PURPOSE:
|
||||||
* - Aquicker, efficient memory allocator alternative to 'malloc' and friends.
|
* - A quicker, efficient memory allocator alternative to 'malloc' and friends.
|
||||||
* - Reduce the possibilities of memory leaks for beginner developers using Raylib.
|
* - Reduce the possibilities of memory leaks for beginner developers using Raylib.
|
||||||
* - Being able to flexibly range check memory if necessary.
|
* - Being able to flexibly range check memory if necessary.
|
||||||
*
|
*
|
||||||
|
|
@ -54,7 +54,7 @@
|
||||||
#else
|
#else
|
||||||
#define RMEMAPI // We are building or using library as a static library (or Linux shared library)
|
#define RMEMAPI // We are building or using library as a static library (or Linux shared library)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Types and Structures Definition
|
// Types and Structures Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -139,9 +139,9 @@ RMEMAPI void ObjPoolCleanUp(ObjPool *objpool, void **ptrref);
|
||||||
|
|
||||||
#if defined(RMEM_IMPLEMENTATION)
|
#if defined(RMEM_IMPLEMENTATION)
|
||||||
|
|
||||||
#include <stdio.h> // Required for:
|
#include <stdio.h> // Required for:
|
||||||
#include <stdlib.h> // Required for:
|
#include <stdlib.h> // Required for:
|
||||||
#include <string.h> // Required for:
|
#include <string.h> // Required for:
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Defines and Macros
|
// Defines and Macros
|
||||||
|
|
@ -163,24 +163,9 @@ RMEMAPI void ObjPoolCleanUp(ObjPool *objpool, void **ptrref);
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module specific Functions Declaration
|
// Module specific Functions Declaration
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
static inline size_t __AlignSize(const size_t size, const size_t align)
|
static inline size_t __AlignSize(const size_t size, const size_t align)
|
||||||
{
|
|
||||||
return (size + (align - 1)) & -align;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __RemoveNode(MemPool *const mempool, MemNode **const node)
|
|
||||||
{
|
{
|
||||||
if ((*node)->next != NULL) (*node)->next->prev = (*node)->prev;
|
return (size + (align - 1)) & -align;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -190,9 +175,9 @@ static void __RemoveNode(MemPool *const mempool, MemNode **const node)
|
||||||
MemPool CreateMemPool(const size_t size)
|
MemPool CreateMemPool(const size_t size)
|
||||||
{
|
{
|
||||||
MemPool mempool = { 0 };
|
MemPool mempool = { 0 };
|
||||||
|
|
||||||
if (size == 0UL) return mempool;
|
if (size == 0UL) return mempool;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 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;
|
||||||
|
|
@ -203,7 +188,7 @@ MemPool CreateMemPool(const size_t size)
|
||||||
mempool.stack.size = 0UL;
|
mempool.stack.size = 0UL;
|
||||||
return mempool;
|
return mempool;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mempool.stack.base = mempool.stack.mem + mempool.stack.size;
|
mempool.stack.base = mempool.stack.mem + mempool.stack.size;
|
||||||
return mempool;
|
return mempool;
|
||||||
|
|
@ -214,9 +199,9 @@ MemPool CreateMemPool(const size_t size)
|
||||||
MemPool CreateMemPoolFromBuffer(void *buf, const size_t size)
|
MemPool CreateMemPoolFromBuffer(void *buf, const size_t size)
|
||||||
{
|
{
|
||||||
MemPool mempool = { 0 };
|
MemPool mempool = { 0 };
|
||||||
|
|
||||||
if ((size == 0UL) || (buf == NULL) || (size <= sizeof(MemNode))) return mempool;
|
if ((size == 0UL) || (buf == NULL) || (size <= sizeof(MemNode))) return mempool;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mempool.stack.size = size;
|
mempool.stack.size = size;
|
||||||
mempool.stack.mem = buf;
|
mempool.stack.mem = buf;
|
||||||
|
|
@ -228,7 +213,7 @@ MemPool CreateMemPoolFromBuffer(void *buf, const size_t size)
|
||||||
void DestroyMemPool(MemPool *const mempool)
|
void DestroyMemPool(MemPool *const mempool)
|
||||||
{
|
{
|
||||||
if ((mempool == NULL) || (mempool->stack.mem == NULL)) return;
|
if ((mempool == NULL) || (mempool->stack.mem == NULL)) return;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
free(mempool->stack.mem);
|
free(mempool->stack.mem);
|
||||||
*mempool = (MemPool){ 0 };
|
*mempool = (MemPool){ 0 };
|
||||||
|
|
@ -243,7 +228,8 @@ 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;
|
const size_t BUCKET_INDEX = (ALLOC_SIZE >> MEMPOOL_BUCKET_BITS) - 1;
|
||||||
|
|
||||||
|
// If the size is small enough, let's check if our buckets has a fitting memory block.
|
||||||
if (BUCKET_INDEX < MEMPOOL_BUCKET_SIZE && mempool->buckets[BUCKET_INDEX] != NULL && mempool->buckets[BUCKET_INDEX]->size >= ALLOC_SIZE)
|
if (BUCKET_INDEX < MEMPOOL_BUCKET_SIZE && mempool->buckets[BUCKET_INDEX] != NULL && mempool->buckets[BUCKET_INDEX]->size >= ALLOC_SIZE)
|
||||||
{
|
{
|
||||||
new_mem = mempool->buckets[BUCKET_INDEX];
|
new_mem = mempool->buckets[BUCKET_INDEX];
|
||||||
|
|
@ -254,30 +240,36 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
|
||||||
else if (mempool->freeList.head != NULL)
|
else if (mempool->freeList.head != NULL)
|
||||||
{
|
{
|
||||||
const size_t MEM_SPLIT_THRESHOLD = 16;
|
const size_t MEM_SPLIT_THRESHOLD = 16;
|
||||||
|
|
||||||
// If the freelist is valid, let's allocate FROM the freelist then!
|
// If the freelist is valid, let's allocate FROM the freelist then!
|
||||||
for (MemNode **inode = &mempool->freeList.head; *inode != NULL; inode = &(*inode)->next)
|
for (MemNode *inode = mempool->freeList.head; inode != NULL; inode = inode->next)
|
||||||
{
|
{
|
||||||
if ((*inode)->size < ALLOC_SIZE) continue;
|
if (inode->size < ALLOC_SIZE) continue;
|
||||||
else if ((*inode)->size <= (ALLOC_SIZE + MEM_SPLIT_THRESHOLD))
|
else if (inode->size <= (ALLOC_SIZE + MEM_SPLIT_THRESHOLD))
|
||||||
{
|
{
|
||||||
// Close in size - reduce fragmentation by not splitting.
|
// Close in size - reduce fragmentation by not splitting.
|
||||||
new_mem = *inode;
|
new_mem = inode;
|
||||||
__RemoveNode(mempool, inode);
|
(inode->prev != NULL)? (inode->prev->next = inode->next) : (mempool->freeList.head = inode->next);
|
||||||
|
(inode->next != NULL)? (inode->next->prev = inode->prev) : (mempool->freeList.tail = inode->prev);
|
||||||
|
|
||||||
|
if (mempool->freeList.head != NULL) mempool->freeList.head->prev = NULL;
|
||||||
|
else mempool->freeList.tail = NULL;
|
||||||
|
|
||||||
|
if (mempool->freeList.tail != NULL) mempool->freeList.tail->next = NULL;
|
||||||
mempool->freeList.len--;
|
mempool->freeList.len--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Split the memory chunk.
|
// Split the memory chunk.
|
||||||
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;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_mem == NULL)
|
if (new_mem == NULL)
|
||||||
{
|
{
|
||||||
// not enough memory to support the size!
|
// not enough memory to support the size!
|
||||||
|
|
@ -287,13 +279,13 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
|
||||||
// Couldn't allocate from a freelist, allocate from available mempool.
|
// Couldn't allocate from a freelist, allocate from available mempool.
|
||||||
// Subtract allocation size from the mempool.
|
// Subtract allocation size from the mempool.
|
||||||
mempool->stack.base -= ALLOC_SIZE;
|
mempool->stack.base -= ALLOC_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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visual of the allocation block.
|
// Visual of the allocation block.
|
||||||
// --------------
|
// --------------
|
||||||
// | mem size | lowest addr of block
|
// | mem size | lowest addr of block
|
||||||
|
|
@ -322,7 +314,7 @@ void *MemPoolRealloc(MemPool *const restrict mempool, void *ptr, const size_t si
|
||||||
MemNode *const 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 *const 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
|
||||||
{
|
{
|
||||||
|
|
@ -337,16 +329,16 @@ 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 - sizeof(MemNode) < (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 *const 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;
|
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) ||
|
||||||
(((uintptr_t)mem_node - (uintptr_t)mempool->stack.mem) > mempool->stack.size) ||
|
(((uintptr_t)mem_node - (uintptr_t)mempool->stack.mem) > mempool->stack.size) ||
|
||||||
(mem_node->size == 0UL) ||
|
(mem_node->size == 0UL) ||
|
||||||
(mem_node->size > mempool->stack.size)) return;
|
(mem_node->size > mempool->stack.size)) return;
|
||||||
// If the mem_node is right at the stack base ptr, then add it to the stack.
|
// If the mem_node is right at the stack base ptr, then add it to the stack.
|
||||||
else if ((uintptr_t)mem_node == (uintptr_t)mempool->stack.base)
|
else if ((uintptr_t)mem_node == (uintptr_t)mempool->stack.base)
|
||||||
|
|
@ -356,13 +348,13 @@ void MemPoolFree(MemPool *const restrict mempool, void *ptr)
|
||||||
// attempted stack merge failed, try to place it into the memnode buckets
|
// attempted stack merge failed, try to place it into the memnode buckets
|
||||||
else if (BUCKET_INDEX < MEMPOOL_BUCKET_SIZE)
|
else if (BUCKET_INDEX < MEMPOOL_BUCKET_SIZE)
|
||||||
{
|
{
|
||||||
if (mempool->buckets[index] == NULL) mempool->buckets[index] = node;
|
if (mempool->buckets[BUCKET_INDEX] == NULL) mempool->buckets[BUCKET_INDEX] = mem_node;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (MemNode *n = mempool->buckets[index]; n != NULL; n = n->next) if( n==node ) return;
|
for (MemNode *n = mempool->buckets[BUCKET_INDEX]; n != NULL; n = n->next) if( n==mem_node ) return;
|
||||||
mempool->buckets[index]->prev = node;
|
mempool->buckets[BUCKET_INDEX]->prev = mem_node;
|
||||||
node->next = mempool->buckets[index];
|
mem_node->next = mempool->buckets[BUCKET_INDEX];
|
||||||
mempool->buckets[index] = node;
|
mempool->buckets[BUCKET_INDEX] = mem_node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Otherwise, we add it to the free list.
|
// Otherwise, we add it to the free list.
|
||||||
|
|
@ -370,13 +362,13 @@ void MemPoolFree(MemPool *const restrict mempool, void *ptr)
|
||||||
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 insertion sorts where largest size is last.
|
// This code insertion sorts where largest size is last.
|
||||||
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;
|
||||||
|
|
@ -391,7 +383,7 @@ void MemPoolFree(MemPool *const restrict mempool, void *ptr)
|
||||||
mempool->freeList.tail = mem_node;
|
mempool->freeList.tail = mem_node;
|
||||||
mempool->freeList.len++;
|
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,7 +392,7 @@ void MemPoolFree(MemPool *const restrict mempool, void *ptr)
|
||||||
void MemPoolCleanUp(MemPool *const restrict mempool, void **ptrref)
|
void MemPoolCleanUp(MemPool *const restrict mempool, void **ptrref)
|
||||||
{
|
{
|
||||||
if ((mempool == NULL) || (ptrref == NULL) || (*ptrref == NULL)) return;
|
if ((mempool == NULL) || (ptrref == NULL) || (*ptrref == NULL)) return;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MemPoolFree(mempool, *ptrref);
|
MemPoolFree(mempool, *ptrref);
|
||||||
*ptrref = NULL;
|
*ptrref = NULL;
|
||||||
|
|
@ -410,11 +402,11 @@ void MemPoolCleanUp(MemPool *const restrict mempool, void **ptrref)
|
||||||
size_t GetMemPoolFreeMemory(const MemPool mempool)
|
size_t GetMemPoolFreeMemory(const MemPool mempool)
|
||||||
{
|
{
|
||||||
size_t total_remaining = (uintptr_t)mempool.stack.base - (uintptr_t)mempool.stack.mem;
|
size_t total_remaining = (uintptr_t)mempool.stack.base - (uintptr_t)mempool.stack.mem;
|
||||||
|
|
||||||
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;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -431,12 +423,12 @@ bool MemPoolDefrag(MemPool *const mempool)
|
||||||
for (size_t i = 0; i < MEMPOOL_BUCKET_SIZE; i++) mempool->buckets[i] = NULL;
|
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++)
|
for (size_t i=0; i<MEMPOOL_BUCKET_SIZE; i++)
|
||||||
{
|
{
|
||||||
while (mempool->buckets[i] != NULL)
|
while (mempool->buckets[i] != NULL)
|
||||||
{
|
{
|
||||||
if ((uintptr_t)mempool->buckets[i] == (uintptr_t)mempool->stack.base)
|
if ((uintptr_t)mempool->buckets[i] == (uintptr_t)mempool->stack.base)
|
||||||
{
|
{
|
||||||
|
|
@ -448,36 +440,42 @@ bool MemPoolDefrag(MemPool *const mempool)
|
||||||
else break;
|
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;
|
||||||
|
|
||||||
while (*node != NULL)
|
while (*node != NULL)
|
||||||
{
|
{
|
||||||
if ((uintptr_t)*node == (uintptr_t)mempool->stack.base)
|
if ((uintptr_t)*node == (uintptr_t)mempool->stack.base)
|
||||||
{
|
{
|
||||||
// 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(mempool, node);
|
((*node)->prev != NULL)? ((*node)->prev->next = (*node)->next) : (mempool->freeList.head = (*node)->next);
|
||||||
|
((*node)->next != NULL)? ((*node)->next->prev = (*node)->prev) : (mempool->freeList.tail = (*node)->prev);
|
||||||
|
|
||||||
|
if (mempool->freeList.head != NULL) mempool->freeList.head->prev = NULL;
|
||||||
|
else mempool->freeList.tail = NULL;
|
||||||
|
|
||||||
|
if (mempool->freeList.tail != NULL) mempool->freeList.tail->next = NULL;
|
||||||
mempool->freeList.len--;
|
mempool->freeList.len--;
|
||||||
node = &mempool->freeList.head;
|
node = &mempool->freeList.head;
|
||||||
}
|
}
|
||||||
else if (((uintptr_t)*node + (*node)->size) == (uintptr_t)(*node)->next)
|
else if (((uintptr_t)*node + (*node)->size) == (uintptr_t)(*node)->next)
|
||||||
{
|
{
|
||||||
// Next node is at a higher address.
|
// Next node is at a higher address.
|
||||||
(*node)->size += (*node)->next->size;
|
(*node)->size += (*node)->next->size;
|
||||||
(*node)->next->size = 0UL;
|
(*node)->next->size = 0UL;
|
||||||
|
|
||||||
// <-[P Curr N]-> <-[P Next N]-> <-[P NextNext N]->
|
// <-[P Curr N]-> <-[P Next N]-> <-[P NextNext N]->
|
||||||
//
|
//
|
||||||
// |--------------------|
|
// |--------------------|
|
||||||
// <-[P Curr N]-> <-[P Next N]-> [P NextNext N]->
|
// <-[P Curr N]-> <-[P Next N]-> [P NextNext N]->
|
||||||
if ((*node)->next->next != NULL) (*node)->next->next->prev = *node;
|
if ((*node)->next->next != NULL) (*node)->next->next->prev = *node;
|
||||||
|
|
||||||
// <-[P Curr N]-> <-[P NextNext N]->
|
// <-[P Curr N]-> <-[P NextNext N]->
|
||||||
(*node)->next = (*node)->next->next;
|
(*node)->next = (*node)->next->next;
|
||||||
|
|
||||||
mempool->freeList.len--;
|
mempool->freeList.len--;
|
||||||
node = &mempool->freeList.head;
|
node = &mempool->freeList.head;
|
||||||
}
|
}
|
||||||
|
|
@ -486,16 +484,16 @@ bool MemPoolDefrag(MemPool *const mempool)
|
||||||
// Prev node is at a higher address.
|
// Prev node is at a higher address.
|
||||||
(*node)->size += (*node)->prev->size;
|
(*node)->size += (*node)->prev->size;
|
||||||
(*node)->prev->size = 0UL;
|
(*node)->prev->size = 0UL;
|
||||||
|
|
||||||
// <-[P PrevPrev N]-> <-[P Prev N]-> <-[P Curr N]->
|
// <-[P PrevPrev N]-> <-[P Prev N]-> <-[P Curr N]->
|
||||||
//
|
//
|
||||||
// |--------------------|
|
// |--------------------|
|
||||||
// <-[P PrevPrev N] <-[P Prev N]-> <-[P Curr N]->
|
// <-[P PrevPrev N] <-[P Prev N]-> <-[P Curr N]->
|
||||||
(*node)->prev->prev->next = *node;
|
(*node)->prev->prev->next = *node;
|
||||||
|
|
||||||
// <-[P PrevPrev N]-> <-[P Curr N]->
|
// <-[P PrevPrev N]-> <-[P Curr N]->
|
||||||
(*node)->prev = (*node)->prev->prev;
|
(*node)->prev = (*node)->prev->prev;
|
||||||
|
|
||||||
mempool->freeList.len--;
|
mempool->freeList.len--;
|
||||||
node = &mempool->freeList.head;
|
node = &mempool->freeList.head;
|
||||||
}
|
}
|
||||||
|
|
@ -503,12 +501,12 @@ bool MemPoolDefrag(MemPool *const mempool)
|
||||||
{
|
{
|
||||||
// Next node is at a lower address.
|
// Next node is at a lower address.
|
||||||
(*node)->next->size += (*node)->size;
|
(*node)->next->size += (*node)->size;
|
||||||
|
|
||||||
(*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;
|
*node = (*node)->next;
|
||||||
|
|
||||||
mempool->freeList.len--;
|
mempool->freeList.len--;
|
||||||
node = &mempool->freeList.head;
|
node = &mempool->freeList.head;
|
||||||
}
|
}
|
||||||
|
|
@ -516,21 +514,21 @@ bool MemPoolDefrag(MemPool *const mempool)
|
||||||
{
|
{
|
||||||
// Prev node is at a lower address.
|
// Prev node is at a lower address.
|
||||||
(*node)->prev->size += (*node)->size;
|
(*node)->prev->size += (*node)->size;
|
||||||
|
|
||||||
(*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;
|
*node = (*node)->prev;
|
||||||
|
|
||||||
mempool->freeList.len--;
|
mempool->freeList.len--;
|
||||||
node = &mempool->freeList.head;
|
node = &mempool->freeList.head;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
node = &(*node)->next;
|
node = &(*node)->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return PRE_DEFRAG_LEN > mempool->freeList.len;
|
return PRE_DEFRAG_LEN > mempool->freeList.len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -553,19 +551,19 @@ union ObjInfo {
|
||||||
ObjPool CreateObjPool(const size_t objsize, const size_t len)
|
ObjPool CreateObjPool(const size_t objsize, const size_t len)
|
||||||
{
|
{
|
||||||
ObjPool objpool = { 0 };
|
ObjPool objpool = { 0 };
|
||||||
|
|
||||||
if ((len == 0UL) || (objsize == 0UL)) return objpool;
|
if ((len == 0UL) || (objsize == 0UL)) return objpool;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
objpool.objSize = __AlignSize(objsize, sizeof(size_t));
|
objpool.objSize = __AlignSize(objsize, sizeof(size_t));
|
||||||
objpool.stack.size = objpool.freeBlocks = len;
|
objpool.stack.size = objpool.freeBlocks = len;
|
||||||
objpool.stack.mem = calloc(objpool.stack.size, objpool.objSize);
|
objpool.stack.mem = calloc(objpool.stack.size, objpool.objSize);
|
||||||
|
|
||||||
if (objpool.stack.mem == NULL)
|
if (objpool.stack.mem == NULL)
|
||||||
{
|
{
|
||||||
objpool.stack.size = 0UL;
|
objpool.stack.size = 0UL;
|
||||||
return objpool;
|
return objpool;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (size_t i=0; i<objpool.freeBlocks; i++)
|
for (size_t i=0; i<objpool.freeBlocks; i++)
|
||||||
|
|
@ -573,7 +571,7 @@ ObjPool CreateObjPool(const size_t objsize, const size_t len)
|
||||||
union ObjInfo block = { .byte = &objpool.stack.mem[i*objpool.objSize] };
|
union ObjInfo block = { .byte = &objpool.stack.mem[i*objpool.objSize] };
|
||||||
*block.index = i + 1;
|
*block.index = i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
objpool.stack.base = objpool.stack.mem;
|
objpool.stack.base = objpool.stack.mem;
|
||||||
return objpool;
|
return objpool;
|
||||||
}
|
}
|
||||||
|
|
@ -583,7 +581,7 @@ ObjPool CreateObjPool(const size_t objsize, const size_t len)
|
||||||
ObjPool CreateObjPoolFromBuffer(void *const buf, const size_t objsize, const size_t len)
|
ObjPool CreateObjPoolFromBuffer(void *const buf, const size_t objsize, const size_t len)
|
||||||
{
|
{
|
||||||
ObjPool objpool = { 0 };
|
ObjPool objpool = { 0 };
|
||||||
|
|
||||||
// If the object size isn't large enough to align to a size_t, then we can't use it.
|
// If the object size isn't large enough to align to a size_t, then we can't use it.
|
||||||
if ((buf == NULL) || (len == 0UL) || (objsize < sizeof(size_t)) || (objsize*len != __AlignSize(objsize, sizeof(size_t))*len)) return objpool;
|
if ((buf == NULL) || (len == 0UL) || (objsize < sizeof(size_t)) || (objsize*len != __AlignSize(objsize, sizeof(size_t))*len)) return objpool;
|
||||||
else
|
else
|
||||||
|
|
@ -591,13 +589,13 @@ ObjPool CreateObjPoolFromBuffer(void *const buf, const size_t objsize, const siz
|
||||||
objpool.objSize = __AlignSize(objsize, sizeof(size_t));
|
objpool.objSize = __AlignSize(objsize, sizeof(size_t));
|
||||||
objpool.stack.size = objpool.freeBlocks = len;
|
objpool.stack.size = objpool.freeBlocks = len;
|
||||||
objpool.stack.mem = buf;
|
objpool.stack.mem = buf;
|
||||||
|
|
||||||
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.index = i + 1;
|
*block.index = i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
objpool.stack.base = objpool.stack.mem;
|
objpool.stack.base = objpool.stack.mem;
|
||||||
return objpool;
|
return objpool;
|
||||||
}
|
}
|
||||||
|
|
@ -625,7 +623,7 @@ void *ObjPoolAlloc(ObjPool *const objpool)
|
||||||
// ret = Head == ret = &pool[0];
|
// ret = Head == ret = &pool[0];
|
||||||
union ObjInfo ret = { .byte = objpool->stack.base };
|
union ObjInfo ret = { .byte = objpool->stack.base };
|
||||||
objpool->freeBlocks--;
|
objpool->freeBlocks--;
|
||||||
|
|
||||||
// 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.index*objpool->objSize) : NULL;
|
objpool->stack.base = (objpool->freeBlocks != 0UL)? objpool->stack.mem + (*ret.index*objpool->objSize) : NULL;
|
||||||
|
|
|
||||||
|
|
@ -95,10 +95,10 @@
|
||||||
// Platform type definitions
|
// Platform type definitions
|
||||||
// From: https://github.com/DFHack/clsocket/blob/master/src/Host.h
|
// From: https://github.com/DFHack/clsocket/blob/master/src/Host.h
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
typedef int socklen_t;
|
typedef int socklen_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef RESULT_SUCCESS
|
#ifndef RESULT_SUCCESS
|
||||||
# define RESULT_SUCCESS 0
|
# define RESULT_SUCCESS 0
|
||||||
|
|
@ -171,7 +171,7 @@ typedef int socklen_t;
|
||||||
#define SOCKET_MAX_QUEUE_SIZE (16) // Maximum socket queue size
|
#define SOCKET_MAX_QUEUE_SIZE (16) // Maximum socket queue size
|
||||||
#define SOCKET_MAX_SOCK_OPTS (4) // Maximum socket options
|
#define SOCKET_MAX_SOCK_OPTS (4) // Maximum socket options
|
||||||
#define SOCKET_MAX_UDPCHANNELS (32) // Maximum UDP channels
|
#define SOCKET_MAX_UDPCHANNELS (32) // Maximum UDP channels
|
||||||
#define SOCKET_MAX_UDPADDRESSES (4) // Maximum bound UDP addresses
|
#define SOCKET_MAX_UDPADDRESSES (4) // Maximum bound UDP addresses
|
||||||
|
|
||||||
|
|
||||||
// Network address related defines
|
// Network address related defines
|
||||||
|
|
@ -386,7 +386,7 @@ int AddSocket(SocketSet *set, Socket *sock);
|
||||||
int RemoveSocket(SocketSet *set, Socket *sock);
|
int RemoveSocket(SocketSet *set, Socket *sock);
|
||||||
int CheckSockets(SocketSet *set, unsigned int timeout);
|
int CheckSockets(SocketSet *set, unsigned int timeout);
|
||||||
|
|
||||||
// Packet API
|
// Packet API
|
||||||
void PacketSend(Packet *packet);
|
void PacketSend(Packet *packet);
|
||||||
void PacketReceive(Packet *packet);
|
void PacketReceive(Packet *packet);
|
||||||
void PacketWrite8(Packet *packet, uint16_t value);
|
void PacketWrite8(Packet *packet, uint16_t value);
|
||||||
|
|
|
||||||
36
src/shapes.c
|
|
@ -1179,10 +1179,11 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw a triangle
|
// Draw a triangle
|
||||||
|
// NOTE: Vertex must be provided in counter-clockwise order
|
||||||
void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
|
void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
|
||||||
{
|
{
|
||||||
if (rlCheckBufferLimit(4)) rlglDraw();
|
if (rlCheckBufferLimit(4)) rlglDraw();
|
||||||
|
|
||||||
#if defined(SUPPORT_QUADS_DRAW_MODE)
|
#if defined(SUPPORT_QUADS_DRAW_MODE)
|
||||||
rlEnableTexture(GetShapesTexture().id);
|
rlEnableTexture(GetShapesTexture().id);
|
||||||
|
|
||||||
|
|
@ -1214,10 +1215,11 @@ void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw a triangle using lines
|
// Draw a triangle using lines
|
||||||
|
// NOTE: Vertex must be provided in counter-clockwise order
|
||||||
void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
|
void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
|
||||||
{
|
{
|
||||||
if (rlCheckBufferLimit(6)) rlglDraw();
|
if (rlCheckBufferLimit(6)) rlglDraw();
|
||||||
|
|
||||||
rlBegin(RL_LINES);
|
rlBegin(RL_LINES);
|
||||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||||
rlVertex2f(v1.x, v1.y);
|
rlVertex2f(v1.x, v1.y);
|
||||||
|
|
@ -1232,7 +1234,7 @@ void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw a triangle fan defined by points
|
// Draw a triangle fan defined by points
|
||||||
// NOTE: First point provided is shared by all triangles
|
// NOTE: First vertex provided is the center, shared by all triangles
|
||||||
void DrawTriangleFan(Vector2 *points, int pointsCount, Color color)
|
void DrawTriangleFan(Vector2 *points, int pointsCount, Color color)
|
||||||
{
|
{
|
||||||
if (pointsCount >= 3)
|
if (pointsCount >= 3)
|
||||||
|
|
@ -1263,7 +1265,7 @@ void DrawTriangleFan(Vector2 *points, int pointsCount, Color color)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw a triangle strip defined by points
|
// Draw a triangle strip defined by points
|
||||||
// NOTE: Every new point connects with previous two
|
// NOTE: Every new vertex connects with previous two
|
||||||
void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color)
|
void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color)
|
||||||
{
|
{
|
||||||
if (pointsCount >= 3)
|
if (pointsCount >= 3)
|
||||||
|
|
@ -1296,6 +1298,7 @@ void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color)
|
||||||
void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color)
|
void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color)
|
||||||
{
|
{
|
||||||
if (sides < 3) sides = 3;
|
if (sides < 3) sides = 3;
|
||||||
|
float centralAngle = 0.0f;
|
||||||
|
|
||||||
if (rlCheckBufferLimit(4*(360/sides))) rlglDraw();
|
if (rlCheckBufferLimit(4*(360/sides))) rlglDraw();
|
||||||
|
|
||||||
|
|
@ -1307,7 +1310,7 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col
|
||||||
rlEnableTexture(GetShapesTexture().id);
|
rlEnableTexture(GetShapesTexture().id);
|
||||||
|
|
||||||
rlBegin(RL_QUADS);
|
rlBegin(RL_QUADS);
|
||||||
for (int i = 0; i < 360; i += 360/sides)
|
for (int i = 0; i < sides; i++)
|
||||||
{
|
{
|
||||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||||
|
|
||||||
|
|
@ -1315,25 +1318,28 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col
|
||||||
rlVertex2f(0, 0);
|
rlVertex2f(0, 0);
|
||||||
|
|
||||||
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
|
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
|
||||||
rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius);
|
rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
|
||||||
|
|
||||||
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
|
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
|
||||||
rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius);
|
rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
|
||||||
|
|
||||||
|
centralAngle += 360.0f/(float)sides;
|
||||||
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
|
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
|
||||||
rlVertex2f(sinf(DEG2RAD*(i + 360/sides))*radius, cosf(DEG2RAD*(i + 360/sides))*radius);
|
rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
|
||||||
}
|
}
|
||||||
rlEnd();
|
rlEnd();
|
||||||
rlDisableTexture();
|
rlDisableTexture();
|
||||||
#else
|
#else
|
||||||
rlBegin(RL_TRIANGLES);
|
rlBegin(RL_TRIANGLES);
|
||||||
for (int i = 0; i < 360; i += 360/sides)
|
for (int i = 0; i < sides; i++)
|
||||||
{
|
{
|
||||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||||
|
|
||||||
rlVertex2f(0, 0);
|
rlVertex2f(0, 0);
|
||||||
rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius);
|
rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
|
||||||
rlVertex2f(sinf(DEG2RAD*(i + 360/sides))*radius, cosf(DEG2RAD*(i + 360/sides))*radius);
|
|
||||||
|
centralAngle += 360.0f/(float)sides;
|
||||||
|
rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
|
||||||
}
|
}
|
||||||
rlEnd();
|
rlEnd();
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1390,8 +1396,8 @@ bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2)
|
||||||
{
|
{
|
||||||
bool collision = false;
|
bool collision = false;
|
||||||
|
|
||||||
if ((rec1.x <= (rec2.x + rec2.width) && (rec1.x + rec1.width) >= rec2.x) &&
|
if ((rec1.x < (rec2.x + rec2.width) && (rec1.x + rec1.width) > rec2.x) &&
|
||||||
(rec1.y <= (rec2.y + rec2.height) && (rec1.y + rec1.height) >= rec2.y)) collision = true;
|
(rec1.y < (rec2.y + rec2.height) && (rec1.y + rec1.height) > rec2.y)) collision = true;
|
||||||
|
|
||||||
return collision;
|
return collision;
|
||||||
}
|
}
|
||||||
|
|
@ -1509,9 +1515,9 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
|
||||||
static float EaseCubicInOut(float t, float b, float c, float d)
|
static float EaseCubicInOut(float t, float b, float c, float d)
|
||||||
{
|
{
|
||||||
if ((t /= 0.5f*d) < 1) return 0.5f*c*t*t*t + b;
|
if ((t /= 0.5f*d) < 1) return 0.5f*c*t*t*t + b;
|
||||||
|
|
||||||
t -= 2;
|
t -= 2;
|
||||||
|
|
||||||
return 0.5f*c*(t*t*t + 2.0f) + b;
|
return 0.5f*c*(t*t*t + 2.0f) + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
483
src/text.c
|
|
@ -10,9 +10,19 @@
|
||||||
* supported by default, to remove support, just comment unrequired #define in this module
|
* supported by default, to remove support, just comment unrequired #define in this module
|
||||||
*
|
*
|
||||||
* #define SUPPORT_DEFAULT_FONT
|
* #define SUPPORT_DEFAULT_FONT
|
||||||
|
* Load default raylib font on initialization to be used by DrawText() and MeasureText().
|
||||||
|
* If no default font loaded, DrawTextEx() and MeasureTextEx() are required.
|
||||||
|
*
|
||||||
|
* #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
|
||||||
|
* TextSplit() function static buffer max size
|
||||||
|
*
|
||||||
|
* #define TEXTSPLIT_MAX_SUBSTRINGS_COUNT
|
||||||
|
* TextSplit() function static substrings pointers array (pointing to static buffer)
|
||||||
|
*
|
||||||
*
|
*
|
||||||
* DEPENDENCIES:
|
* DEPENDENCIES:
|
||||||
* stb_truetype - Load TTF file and rasterize characters data
|
* stb_truetype - Load TTF file and rasterize characters data
|
||||||
|
* stb_rect_pack - Rectangles packing algorythms, required for font atlas generation
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
|
|
@ -40,7 +50,7 @@
|
||||||
|
|
||||||
// Check if config flags have been externally provided on compilation line
|
// Check if config flags have been externally provided on compilation line
|
||||||
#if !defined(EXTERNAL_CONFIG_FLAGS)
|
#if !defined(EXTERNAL_CONFIG_FLAGS)
|
||||||
#include "config.h" // Defines module configuration flags
|
#include "config.h" // Defines module configuration flags
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h> // Required for: malloc(), free()
|
#include <stdlib.h> // Required for: malloc(), free()
|
||||||
|
|
@ -63,7 +73,18 @@
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Defines and Macros
|
// Defines and Macros
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers of some Text*() functions
|
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
|
||||||
|
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal()
|
||||||
|
|
||||||
|
#define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints
|
||||||
|
|
||||||
|
#if !defined(TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH)
|
||||||
|
#define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH 1024 // Size of static buffer: TextSplit()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(TEXTSPLIT_MAX_SUBSTRINGS_COUNT)
|
||||||
|
#define TEXTSPLIT_MAX_SUBSTRINGS_COUNT 128 // Size of static pointers array: TextSplit()
|
||||||
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Types and Structures Definition
|
// Types and Structures Definition
|
||||||
|
|
@ -282,7 +303,7 @@ Font LoadFont(const char *fileName)
|
||||||
Font font = { 0 };
|
Font font = { 0 };
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_TTF)
|
#if defined(SUPPORT_FILEFORMAT_TTF)
|
||||||
if (IsFileExtension(fileName, ".ttf") || IsFileExtension(fileName, ".otf")) font = LoadFontEx(fileName, DEFAULT_TTF_FONTSIZE, NULL, DEFAULT_TTF_NUMCHARS);
|
if (IsFileExtension(fileName, ".ttf;.otf")) font = LoadFontEx(fileName, DEFAULT_TTF_FONTSIZE, NULL, DEFAULT_TTF_NUMCHARS);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_FNT)
|
#if defined(SUPPORT_FILEFORMAT_FNT)
|
||||||
|
|
@ -321,7 +342,7 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
|
||||||
{
|
{
|
||||||
Image atlas = GenImageFontAtlas(font.chars, &font.recs, font.charsCount, font.baseSize, 2, 0);
|
Image atlas = GenImageFontAtlas(font.chars, &font.recs, font.charsCount, font.baseSize, 2, 0);
|
||||||
font.texture = LoadTextureFromImage(atlas);
|
font.texture = LoadTextureFromImage(atlas);
|
||||||
|
|
||||||
// Update chars[i].image to use alpha, required to be used on ImageDrawText()
|
// Update chars[i].image to use alpha, required to be used on ImageDrawText()
|
||||||
for (int i = 0; i < font.charsCount; i++)
|
for (int i = 0; i < font.charsCount; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -439,7 +460,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
|
||||||
for (int i = 0; i < spriteFont.charsCount; i++)
|
for (int i = 0; i < spriteFont.charsCount; i++)
|
||||||
{
|
{
|
||||||
spriteFont.chars[i].value = tempCharValues[i];
|
spriteFont.chars[i].value = tempCharValues[i];
|
||||||
|
|
||||||
// Get character rectangle in the font atlas texture
|
// Get character rectangle in the font atlas texture
|
||||||
spriteFont.recs[i] = tempCharRecs[i];
|
spriteFont.recs[i] = tempCharRecs[i];
|
||||||
|
|
||||||
|
|
@ -447,7 +468,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
|
||||||
spriteFont.chars[i].offsetX = 0;
|
spriteFont.chars[i].offsetX = 0;
|
||||||
spriteFont.chars[i].offsetY = 0;
|
spriteFont.chars[i].offsetY = 0;
|
||||||
spriteFont.chars[i].advanceX = 0;
|
spriteFont.chars[i].advanceX = 0;
|
||||||
|
|
||||||
// Fill character image data from fontClear data
|
// Fill character image data from fontClear data
|
||||||
spriteFont.chars[i].image = ImageFromImage(fontClear, tempCharRecs[i]);
|
spriteFont.chars[i].image = ImageFromImage(fontClear, tempCharRecs[i]);
|
||||||
}
|
}
|
||||||
|
|
@ -586,8 +607,8 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
|
||||||
*charRecs = NULL;
|
*charRecs = NULL;
|
||||||
|
|
||||||
// In case no chars count provided we suppose default of 95
|
// In case no chars count provided we suppose default of 95
|
||||||
charsCount = (charsCount > 0) ? charsCount : 95;
|
charsCount = (charsCount > 0)? charsCount : 95;
|
||||||
|
|
||||||
// NOTE: Rectangles memory is loaded here!
|
// NOTE: Rectangles memory is loaded here!
|
||||||
Rectangle *recs = (Rectangle *)RL_MALLOC(charsCount*sizeof(Rectangle));
|
Rectangle *recs = (Rectangle *)RL_MALLOC(charsCount*sizeof(Rectangle));
|
||||||
|
|
||||||
|
|
@ -597,7 +618,7 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
|
||||||
// so image size would result bigger than default font type
|
// so image size would result bigger than default font type
|
||||||
float requiredArea = 0;
|
float requiredArea = 0;
|
||||||
for (int i = 0; i < charsCount; i++) requiredArea += ((chars[i].image.width + 2*padding)*(chars[i].image.height + 2*padding));
|
for (int i = 0; i < charsCount; i++) requiredArea += ((chars[i].image.width + 2*padding)*(chars[i].image.height + 2*padding));
|
||||||
float guessSize = sqrtf(requiredArea)*1.25f;
|
float guessSize = sqrtf(requiredArea)*1.3f;
|
||||||
int imageSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT
|
int imageSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT
|
||||||
|
|
||||||
atlas.width = imageSize; // Atlas bitmap width
|
atlas.width = imageSize; // Atlas bitmap width
|
||||||
|
|
@ -711,7 +732,7 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
|
||||||
RL_FREE(atlas.data);
|
RL_FREE(atlas.data);
|
||||||
atlas.data = dataGrayAlpha;
|
atlas.data = dataGrayAlpha;
|
||||||
atlas.format = UNCOMPRESSED_GRAY_ALPHA;
|
atlas.format = UNCOMPRESSED_GRAY_ALPHA;
|
||||||
|
|
||||||
*charRecs = recs;
|
*charRecs = recs;
|
||||||
|
|
||||||
return atlas;
|
return atlas;
|
||||||
|
|
@ -756,120 +777,6 @@ void DrawFPS(int posX, int posY)
|
||||||
DrawText(TextFormat("%2i FPS", fps), posX, posY, 20, LIME);
|
DrawText(TextFormat("%2i FPS", fps), posX, posY, 20, LIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns next codepoint in a UTF8 encoded text, scanning until '\0' is found
|
|
||||||
// When a invalid UTF8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
|
|
||||||
// Total number of bytes processed are returned as a parameter
|
|
||||||
// NOTE: the standard says U+FFFD should be returned in case of errors
|
|
||||||
// but that character is not supported by the default font in raylib
|
|
||||||
// TODO: optimize this code for speed!!
|
|
||||||
int GetNextCodepoint(const char *text, int *bytesProcessed)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
UTF8 specs from https://www.ietf.org/rfc/rfc3629.txt
|
|
||||||
|
|
||||||
Char. number range | UTF-8 octet sequence
|
|
||||||
(hexadecimal) | (binary)
|
|
||||||
--------------------+---------------------------------------------
|
|
||||||
0000 0000-0000 007F | 0xxxxxxx
|
|
||||||
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
|
|
||||||
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
|
|
||||||
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
|
||||||
*/
|
|
||||||
|
|
||||||
// NOTE: on decode errors we return as soon as possible
|
|
||||||
|
|
||||||
int code = 0x3f; // Codepoint (defaults to '?')
|
|
||||||
int octet = (unsigned char)(text[0]); // The first UTF8 octet
|
|
||||||
*bytesProcessed = 1;
|
|
||||||
|
|
||||||
if (octet <= 0x7f)
|
|
||||||
{
|
|
||||||
// Only one octet (ASCII range x00-7F)
|
|
||||||
code = text[0];
|
|
||||||
}
|
|
||||||
else if ((octet & 0xe0) == 0xc0)
|
|
||||||
{
|
|
||||||
// Two octets
|
|
||||||
// [0]xC2-DF [1]UTF8-tail(x80-BF)
|
|
||||||
unsigned char octet1 = text[1];
|
|
||||||
|
|
||||||
if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
|
||||||
|
|
||||||
if ((octet >= 0xc2) && (octet <= 0xdf))
|
|
||||||
{
|
|
||||||
code = ((octet & 0x1f) << 6) | (octet1 & 0x3f);
|
|
||||||
*bytesProcessed = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((octet & 0xf0) == 0xe0)
|
|
||||||
{
|
|
||||||
// Three octets
|
|
||||||
unsigned char octet1 = text[1];
|
|
||||||
unsigned char octet2 = '\0';
|
|
||||||
|
|
||||||
if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
|
||||||
|
|
||||||
octet2 = text[2];
|
|
||||||
|
|
||||||
if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; } // Unexpected sequence
|
|
||||||
|
|
||||||
/*
|
|
||||||
[0]xE0 [1]xA0-BF [2]UTF8-tail(x80-BF)
|
|
||||||
[0]xE1-EC [1]UTF8-tail [2]UTF8-tail(x80-BF)
|
|
||||||
[0]xED [1]x80-9F [2]UTF8-tail(x80-BF)
|
|
||||||
[0]xEE-EF [1]UTF8-tail [2]UTF8-tail(x80-BF)
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (((octet == 0xe0) && !((octet1 >= 0xa0) && (octet1 <= 0xbf))) ||
|
|
||||||
((octet == 0xed) && !((octet1 >= 0x80) && (octet1 <= 0x9f)))) { *bytesProcessed = 2; return code; }
|
|
||||||
|
|
||||||
if ((octet >= 0xe0) && (0 <= 0xef))
|
|
||||||
{
|
|
||||||
code = ((octet & 0xf) << 12) | ((octet1 & 0x3f) << 6) | (octet2 & 0x3f);
|
|
||||||
*bytesProcessed = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((octet & 0xf8) == 0xf0)
|
|
||||||
{
|
|
||||||
// Four octets
|
|
||||||
if (octet > 0xf4) return code;
|
|
||||||
|
|
||||||
unsigned char octet1 = text[1];
|
|
||||||
unsigned char octet2 = '\0';
|
|
||||||
unsigned char octet3 = '\0';
|
|
||||||
|
|
||||||
if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
|
||||||
|
|
||||||
octet2 = text[2];
|
|
||||||
|
|
||||||
if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; } // Unexpected sequence
|
|
||||||
|
|
||||||
octet3 = text[3];
|
|
||||||
|
|
||||||
if ((octet3 == '\0') || ((octet3 >> 6) != 2)) { *bytesProcessed = 4; return code; } // Unexpected sequence
|
|
||||||
|
|
||||||
/*
|
|
||||||
[0]xF0 [1]x90-BF [2]UTF8-tail [3]UTF8-tail
|
|
||||||
[0]xF1-F3 [1]UTF8-tail [2]UTF8-tail [3]UTF8-tail
|
|
||||||
[0]xF4 [1]x80-8F [2]UTF8-tail [3]UTF8-tail
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (((octet == 0xf0) && !((octet1 >= 0x90) && (octet1 <= 0xbf))) ||
|
|
||||||
((octet == 0xf4) && !((octet1 >= 0x80) && (octet1 <= 0x8f)))) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
|
||||||
|
|
||||||
if (octet >= 0xf0)
|
|
||||||
{
|
|
||||||
code = ((octet & 0x7) << 18) | ((octet1 & 0x3f) << 12) | ((octet2 & 0x3f) << 6) | (octet3 & 0x3f);
|
|
||||||
*bytesProcessed = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (code > 0x10ffff) code = 0x3f; // Codepoints after U+10ffff are invalid
|
|
||||||
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Draw text (using default font)
|
// Draw text (using default font)
|
||||||
// NOTE: fontSize work like in any drawing program but if fontSize is lower than font-base-size, then font-base-size is used
|
// NOTE: fontSize work like in any drawing program but if fontSize is lower than font-base-size, then font-base-size is used
|
||||||
// NOTE: chars spacing is proportional to fontSize
|
// NOTE: chars spacing is proportional to fontSize
|
||||||
|
|
@ -907,12 +814,12 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
|
||||||
int next = 0;
|
int next = 0;
|
||||||
letter = GetNextCodepoint(&text[i], &next);
|
letter = GetNextCodepoint(&text[i], &next);
|
||||||
index = GetGlyphIndex(font, letter);
|
index = GetGlyphIndex(font, letter);
|
||||||
|
|
||||||
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
|
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
|
||||||
// but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set 'next = 1'
|
// but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set 'next = 1'
|
||||||
if (letter == 0x3f) next = 1;
|
if (letter == 0x3f) next = 1;
|
||||||
i += (next - 1);
|
i += (next - 1);
|
||||||
|
|
||||||
if (letter == '\n')
|
if (letter == '\n')
|
||||||
{
|
{
|
||||||
// NOTE: Fixed line spacing of 1.5 lines
|
// NOTE: Fixed line spacing of 1.5 lines
|
||||||
|
|
@ -960,17 +867,17 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
|
||||||
int startLine = -1; // Index where to begin drawing (where a line begins)
|
int startLine = -1; // Index where to begin drawing (where a line begins)
|
||||||
int endLine = -1; // Index where to stop drawing (where a line ends)
|
int endLine = -1; // Index where to stop drawing (where a line ends)
|
||||||
int lastk = -1; // Holds last value of the character position
|
int lastk = -1; // Holds last value of the character position
|
||||||
|
|
||||||
for (int i = 0, k = 0; i < length; i++, k++)
|
for (int i = 0, k = 0; i < length; i++, k++)
|
||||||
{
|
{
|
||||||
int glyphWidth = 0;
|
int glyphWidth = 0;
|
||||||
int next = 0;
|
int next = 0;
|
||||||
letter = GetNextCodepoint(&text[i], &next);
|
letter = GetNextCodepoint(&text[i], &next);
|
||||||
index = GetGlyphIndex(font, letter);
|
index = GetGlyphIndex(font, letter);
|
||||||
|
|
||||||
// NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
|
// NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
|
||||||
// but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1
|
// but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1
|
||||||
if (letter == 0x3f) next = 1;
|
if (letter == 0x3f) next = 1;
|
||||||
i += next - 1;
|
i += next - 1;
|
||||||
|
|
||||||
if (letter != '\n')
|
if (letter != '\n')
|
||||||
|
|
@ -988,7 +895,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
|
||||||
if (state == MEASURE_STATE)
|
if (state == MEASURE_STATE)
|
||||||
{
|
{
|
||||||
// TODO: there are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more
|
// TODO: there are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more
|
||||||
// See: http://jkorpela.fi/chars/spaces.html
|
// See: http://jkorpela.fi/chars/spaces.html
|
||||||
if ((letter == ' ') || (letter == '\t') || (letter == '\n')) endLine = i;
|
if ((letter == ' ') || (letter == '\t') || (letter == '\n')) endLine = i;
|
||||||
|
|
||||||
if ((textOffsetX + glyphWidth + 1) >= rec.width)
|
if ((textOffsetX + glyphWidth + 1) >= rec.width)
|
||||||
|
|
@ -1013,7 +920,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
|
||||||
textOffsetX = 0;
|
textOffsetX = 0;
|
||||||
i = startLine;
|
i = startLine;
|
||||||
glyphWidth = 0;
|
glyphWidth = 0;
|
||||||
|
|
||||||
// Save character position when we switch states
|
// Save character position when we switch states
|
||||||
int tmp = lastk;
|
int tmp = lastk;
|
||||||
lastk = k - 1;
|
lastk = k - 1;
|
||||||
|
|
@ -1114,16 +1021,16 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
lenCounter++;
|
lenCounter++;
|
||||||
|
|
||||||
int next = 0;
|
int next = 0;
|
||||||
letter = GetNextCodepoint(&text[i], &next);
|
letter = GetNextCodepoint(&text[i], &next);
|
||||||
index = GetGlyphIndex(font, letter);
|
index = GetGlyphIndex(font, letter);
|
||||||
|
|
||||||
// NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
|
// NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
|
||||||
// but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1
|
// but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1
|
||||||
if (letter == 0x3f) next = 1;
|
if (letter == 0x3f) next = 1;
|
||||||
i += next - 1;
|
i += next - 1;
|
||||||
|
|
||||||
if (letter != '\n')
|
if (letter != '\n')
|
||||||
{
|
{
|
||||||
if (font.chars[index].advanceX != 0) textWidth += font.chars[index].advanceX;
|
if (font.chars[index].advanceX != 0) textWidth += font.chars[index].advanceX;
|
||||||
|
|
@ -1194,27 +1101,6 @@ unsigned int TextLength(const char *text)
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns total number of characters(codepoints) in a UTF8 encoded text, until '\0' is found
|
|
||||||
// NOTE: If an invalid UTF8 sequence is encountered a '?'(0x3f) codepoint is counted instead
|
|
||||||
unsigned int TextCountCodepoints(const char *text)
|
|
||||||
{
|
|
||||||
unsigned int len = 0;
|
|
||||||
char *ptr = (char *)&text[0];
|
|
||||||
|
|
||||||
while (*ptr != '\0')
|
|
||||||
{
|
|
||||||
int next = 0;
|
|
||||||
int letter = GetNextCodepoint(ptr, &next);
|
|
||||||
|
|
||||||
if (letter == 0x3f) ptr += 1;
|
|
||||||
else ptr += next;
|
|
||||||
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Formatting of text with variables to 'embed'
|
// Formatting of text with variables to 'embed'
|
||||||
const char *TextFormat(const char *text, ...)
|
const char *TextFormat(const char *text, ...)
|
||||||
{
|
{
|
||||||
|
|
@ -1338,14 +1224,14 @@ const char *TextJoin(const char **textList, int count, const char *delimiter)
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
int textListLength = strlen(textList[i]);
|
int textListLength = strlen(textList[i]);
|
||||||
|
|
||||||
// Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH
|
// Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH
|
||||||
if ((totalLength + textListLength) < MAX_TEXT_BUFFER_LENGTH)
|
if ((totalLength + textListLength) < MAX_TEXT_BUFFER_LENGTH)
|
||||||
{
|
{
|
||||||
strcat(text, textList[i]);
|
strcat(text, textList[i]);
|
||||||
totalLength += textListLength;
|
totalLength += textListLength;
|
||||||
|
|
||||||
if ((delimiterLen > 0) && (i < (count - 1)))
|
if ((delimiterLen > 0) && (i < (count - 1)))
|
||||||
{
|
{
|
||||||
strcat(text, delimiter);
|
strcat(text, delimiter);
|
||||||
totalLength += delimiterLen;
|
totalLength += delimiterLen;
|
||||||
|
|
@ -1362,30 +1248,33 @@ const char **TextSplit(const char *text, char delimiter, int *count)
|
||||||
// NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
|
// NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
|
||||||
// inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
|
// inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
|
||||||
// all used memory is static... it has some limitations:
|
// all used memory is static... it has some limitations:
|
||||||
// 1. Maximum number of possible split strings is set by MAX_SUBSTRINGS_COUNT
|
// 1. Maximum number of possible split strings is set by TEXTSPLIT_MAX_SUBSTRINGS_COUNT
|
||||||
// 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH
|
// 2. Maximum size of text to split is TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
|
||||||
|
|
||||||
#define MAX_SUBSTRINGS_COUNT 64
|
static const char *result[TEXTSPLIT_MAX_SUBSTRINGS_COUNT] = { NULL };
|
||||||
|
static char buffer[TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||||
static const char *result[MAX_SUBSTRINGS_COUNT] = { NULL };
|
memset(buffer, 0, TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH);
|
||||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
|
||||||
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
|
|
||||||
|
|
||||||
result[0] = buffer;
|
result[0] = buffer;
|
||||||
int counter = 1;
|
int counter = 0;
|
||||||
|
|
||||||
// Count how many substrings we have on text and point to every one
|
if (text != NULL)
|
||||||
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
|
|
||||||
{
|
{
|
||||||
buffer[i] = text[i];
|
counter = 1;
|
||||||
if (buffer[i] == '\0') break;
|
|
||||||
else if (buffer[i] == delimiter)
|
|
||||||
{
|
|
||||||
buffer[i] = '\0'; // Set an end of string at this point
|
|
||||||
result[counter] = buffer + i + 1;
|
|
||||||
counter++;
|
|
||||||
|
|
||||||
if (counter == MAX_SUBSTRINGS_COUNT) break;
|
// Count how many substrings we have on text and point to every one
|
||||||
|
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
|
||||||
|
{
|
||||||
|
buffer[i] = text[i];
|
||||||
|
if (buffer[i] == '\0') break;
|
||||||
|
else if (buffer[i] == delimiter)
|
||||||
|
{
|
||||||
|
buffer[i] = '\0'; // Set an end of string at this point
|
||||||
|
result[counter] = buffer + i + 1;
|
||||||
|
counter++;
|
||||||
|
|
||||||
|
if (counter == TEXTSPLIT_MAX_SUBSTRINGS_COUNT) break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1487,6 +1376,221 @@ int TextToInteger(const char *text)
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Encode text codepoint into utf8 text (memory must be freed!)
|
||||||
|
char *TextToUtf8(int *codepoints, int length)
|
||||||
|
{
|
||||||
|
// We allocate enough memory fo fit all possible codepoints
|
||||||
|
// NOTE: 5 bytes for every codepoint should be enough
|
||||||
|
char *text = (char *)calloc(length*5, 1);
|
||||||
|
const char *utf8 = NULL;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
for (int i = 0, bytes = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
utf8 = CodepointToUtf8(codepoints[i], &bytes);
|
||||||
|
strncpy(text + size, utf8, bytes);
|
||||||
|
size += bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize memory to text length + string NULL terminator
|
||||||
|
realloc(text, size + 1);
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all codepoints in a string, codepoints count returned by parameters
|
||||||
|
int *GetCodepoints(const char *text, int *count)
|
||||||
|
{
|
||||||
|
static int codepoints[MAX_TEXT_UNICODE_CHARS] = { 0 };
|
||||||
|
memset(codepoints, 0, MAX_TEXT_UNICODE_CHARS*sizeof(int));
|
||||||
|
|
||||||
|
int bytesProcessed = 0;
|
||||||
|
int textLength = strlen(text);
|
||||||
|
int codepointsCount = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < textLength; codepointsCount++)
|
||||||
|
{
|
||||||
|
codepoints[codepointsCount] = GetNextCodepoint(text + i, &bytesProcessed);
|
||||||
|
i += bytesProcessed;
|
||||||
|
}
|
||||||
|
|
||||||
|
*count = codepointsCount;
|
||||||
|
|
||||||
|
return codepoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns total number of characters(codepoints) in a UTF8 encoded text, until '\0' is found
|
||||||
|
// NOTE: If an invalid UTF8 sequence is encountered a '?'(0x3f) codepoint is counted instead
|
||||||
|
int GetCodepointsCount(const char *text)
|
||||||
|
{
|
||||||
|
unsigned int len = 0;
|
||||||
|
char *ptr = (char *)&text[0];
|
||||||
|
|
||||||
|
while (*ptr != '\0')
|
||||||
|
{
|
||||||
|
int next = 0;
|
||||||
|
int letter = GetNextCodepoint(ptr, &next);
|
||||||
|
|
||||||
|
if (letter == 0x3f) ptr += 1;
|
||||||
|
else ptr += next;
|
||||||
|
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns next codepoint in a UTF8 encoded text, scanning until '\0' is found
|
||||||
|
// When a invalid UTF8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
|
||||||
|
// Total number of bytes processed are returned as a parameter
|
||||||
|
// NOTE: the standard says U+FFFD should be returned in case of errors
|
||||||
|
// but that character is not supported by the default font in raylib
|
||||||
|
// TODO: optimize this code for speed!!
|
||||||
|
int GetNextCodepoint(const char *text, int *bytesProcessed)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
UTF8 specs from https://www.ietf.org/rfc/rfc3629.txt
|
||||||
|
|
||||||
|
Char. number range | UTF-8 octet sequence
|
||||||
|
(hexadecimal) | (binary)
|
||||||
|
--------------------+---------------------------------------------
|
||||||
|
0000 0000-0000 007F | 0xxxxxxx
|
||||||
|
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
|
||||||
|
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
|
||||||
|
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
*/
|
||||||
|
// NOTE: on decode errors we return as soon as possible
|
||||||
|
|
||||||
|
int code = 0x3f; // Codepoint (defaults to '?')
|
||||||
|
int octet = (unsigned char)(text[0]); // The first UTF8 octet
|
||||||
|
*bytesProcessed = 1;
|
||||||
|
|
||||||
|
if (octet <= 0x7f)
|
||||||
|
{
|
||||||
|
// Only one octet (ASCII range x00-7F)
|
||||||
|
code = text[0];
|
||||||
|
}
|
||||||
|
else if ((octet & 0xe0) == 0xc0)
|
||||||
|
{
|
||||||
|
// Two octets
|
||||||
|
// [0]xC2-DF [1]UTF8-tail(x80-BF)
|
||||||
|
unsigned char octet1 = text[1];
|
||||||
|
|
||||||
|
if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
||||||
|
|
||||||
|
if ((octet >= 0xc2) && (octet <= 0xdf))
|
||||||
|
{
|
||||||
|
code = ((octet & 0x1f) << 6) | (octet1 & 0x3f);
|
||||||
|
*bytesProcessed = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((octet & 0xf0) == 0xe0)
|
||||||
|
{
|
||||||
|
// Three octets
|
||||||
|
unsigned char octet1 = text[1];
|
||||||
|
unsigned char octet2 = '\0';
|
||||||
|
|
||||||
|
if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
||||||
|
|
||||||
|
octet2 = text[2];
|
||||||
|
|
||||||
|
if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; } // Unexpected sequence
|
||||||
|
|
||||||
|
/*
|
||||||
|
[0]xE0 [1]xA0-BF [2]UTF8-tail(x80-BF)
|
||||||
|
[0]xE1-EC [1]UTF8-tail [2]UTF8-tail(x80-BF)
|
||||||
|
[0]xED [1]x80-9F [2]UTF8-tail(x80-BF)
|
||||||
|
[0]xEE-EF [1]UTF8-tail [2]UTF8-tail(x80-BF)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (((octet == 0xe0) && !((octet1 >= 0xa0) && (octet1 <= 0xbf))) ||
|
||||||
|
((octet == 0xed) && !((octet1 >= 0x80) && (octet1 <= 0x9f)))) { *bytesProcessed = 2; return code; }
|
||||||
|
|
||||||
|
if ((octet >= 0xe0) && (0 <= 0xef))
|
||||||
|
{
|
||||||
|
code = ((octet & 0xf) << 12) | ((octet1 & 0x3f) << 6) | (octet2 & 0x3f);
|
||||||
|
*bytesProcessed = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((octet & 0xf8) == 0xf0)
|
||||||
|
{
|
||||||
|
// Four octets
|
||||||
|
if (octet > 0xf4) return code;
|
||||||
|
|
||||||
|
unsigned char octet1 = text[1];
|
||||||
|
unsigned char octet2 = '\0';
|
||||||
|
unsigned char octet3 = '\0';
|
||||||
|
|
||||||
|
if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
||||||
|
|
||||||
|
octet2 = text[2];
|
||||||
|
|
||||||
|
if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; } // Unexpected sequence
|
||||||
|
|
||||||
|
octet3 = text[3];
|
||||||
|
|
||||||
|
if ((octet3 == '\0') || ((octet3 >> 6) != 2)) { *bytesProcessed = 4; return code; } // Unexpected sequence
|
||||||
|
|
||||||
|
/*
|
||||||
|
[0]xF0 [1]x90-BF [2]UTF8-tail [3]UTF8-tail
|
||||||
|
[0]xF1-F3 [1]UTF8-tail [2]UTF8-tail [3]UTF8-tail
|
||||||
|
[0]xF4 [1]x80-8F [2]UTF8-tail [3]UTF8-tail
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (((octet == 0xf0) && !((octet1 >= 0x90) && (octet1 <= 0xbf))) ||
|
||||||
|
((octet == 0xf4) && !((octet1 >= 0x80) && (octet1 <= 0x8f)))) { *bytesProcessed = 2; return code; } // Unexpected sequence
|
||||||
|
|
||||||
|
if (octet >= 0xf0)
|
||||||
|
{
|
||||||
|
code = ((octet & 0x7) << 18) | ((octet1 & 0x3f) << 12) | ((octet2 & 0x3f) << 6) | (octet3 & 0x3f);
|
||||||
|
*bytesProcessed = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code > 0x10ffff) code = 0x3f; // Codepoints after U+10ffff are invalid
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode codepoint into utf8 text (char array length returned as parameter)
|
||||||
|
RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength)
|
||||||
|
{
|
||||||
|
static char utf8[6] = { 0 };
|
||||||
|
int length = 0;
|
||||||
|
|
||||||
|
if (codepoint <= 0x7f)
|
||||||
|
{
|
||||||
|
utf8[0] = (char)codepoint;
|
||||||
|
length = 1;
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0x7ff)
|
||||||
|
{
|
||||||
|
utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
|
||||||
|
utf8[1] = (char)((codepoint & 0x3f) | 0x80);
|
||||||
|
length = 2;
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0xffff)
|
||||||
|
{
|
||||||
|
utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
|
||||||
|
utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
|
||||||
|
utf8[2] = (char)((codepoint & 0x3f) | 0x80);
|
||||||
|
length = 3;
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0x10ffff)
|
||||||
|
{
|
||||||
|
utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0);
|
||||||
|
utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
|
||||||
|
utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
|
||||||
|
utf8[3] = (char)((codepoint & 0x3f) | 0x80);
|
||||||
|
length = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
*byteLength = length;
|
||||||
|
|
||||||
|
return utf8;
|
||||||
|
}
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -1567,18 +1671,15 @@ static Font LoadBMFont(const char *fileName)
|
||||||
TraceLog(LOG_DEBUG, "[%s] Font texture loading path: %s", fileName, texPath);
|
TraceLog(LOG_DEBUG, "[%s] Font texture loading path: %s", fileName, texPath);
|
||||||
|
|
||||||
Image imFont = LoadImage(texPath);
|
Image imFont = LoadImage(texPath);
|
||||||
Image imFontAlpha = ImageCopy(imFont);
|
|
||||||
|
|
||||||
if (imFont.format == UNCOMPRESSED_GRAYSCALE)
|
if (imFont.format == UNCOMPRESSED_GRAYSCALE)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < imFontAlpha.width*imFontAlpha.height; i++) ((unsigned char *)imFontAlpha.data)[i] = 0xff;
|
// Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
|
||||||
|
ImageAlphaMask(&imFont, imFont);
|
||||||
ImageAlphaMask(&imFontAlpha, imFont);
|
for (int p = 0; p < (imFont.width*imFont.height*2); p += 2) ((unsigned char *)(imFont.data))[p] = 0xff;
|
||||||
font.texture = LoadTextureFromImage(imFontAlpha);
|
|
||||||
}
|
}
|
||||||
else font.texture = LoadTextureFromImage(imFont);
|
|
||||||
|
font.texture = LoadTextureFromImage(imFont);
|
||||||
UnloadImage(imFont);
|
|
||||||
|
|
||||||
RL_FREE(texPath);
|
RL_FREE(texPath);
|
||||||
|
|
||||||
|
|
@ -1595,7 +1696,7 @@ static Font LoadBMFont(const char *fileName)
|
||||||
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
|
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
|
||||||
sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i",
|
sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i",
|
||||||
&charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
|
&charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
|
||||||
|
|
||||||
// Get character rectangle in the font atlas texture
|
// Get character rectangle in the font atlas texture
|
||||||
font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight };
|
font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight };
|
||||||
|
|
||||||
|
|
@ -1604,12 +1705,12 @@ static Font LoadBMFont(const char *fileName)
|
||||||
font.chars[i].offsetX = charOffsetX;
|
font.chars[i].offsetX = charOffsetX;
|
||||||
font.chars[i].offsetY = charOffsetY;
|
font.chars[i].offsetY = charOffsetY;
|
||||||
font.chars[i].advanceX = charAdvanceX;
|
font.chars[i].advanceX = charAdvanceX;
|
||||||
|
|
||||||
// Fill character image data from imFont data
|
// Fill character image data from imFont data
|
||||||
font.chars[i].image = ImageFromImage(imFontAlpha, font.recs[i]);
|
font.chars[i].image = ImageFromImage(imFont, font.recs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
UnloadImage(imFontAlpha);
|
UnloadImage(imFont);
|
||||||
|
|
||||||
fclose(fntFile);
|
fclose(fntFile);
|
||||||
|
|
||||||
|
|
|
||||||