Merge branch 'master' of https://github.com/raysan5/raylib into raysan
This commit is contained in:
commit
2469f46950
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -438,7 +438,7 @@ EXAMPLES = \
|
||||||
shaders/shaders_eratosthenes \
|
shaders/shaders_eratosthenes \
|
||||||
shaders/shaders_basic_lighting \
|
shaders/shaders_basic_lighting \
|
||||||
shaders/shaders_fog \
|
shaders/shaders_fog \
|
||||||
shaders/shaders_simple \
|
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 \
|
||||||
|
|
|
||||||
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
74
src/camera.h
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)
|
||||||
|
|
|
||||||
75
src/core.c
75
src/core.c
|
|
@ -579,7 +579,7 @@ static void InitTerminal(void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE);
|
ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -590,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);
|
||||||
|
|
||||||
|
|
@ -774,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
|
||||||
|
|
||||||
|
|
@ -1207,7 +1207,7 @@ void EndDrawing(void)
|
||||||
// we draw a small rectangle for user reference
|
// we draw a small rectangle for user reference
|
||||||
DrawRectangle(mousePosition.x, mousePosition.y, 3, 3, MAROON);
|
DrawRectangle(mousePosition.x, mousePosition.y, 3, 3, MAROON);
|
||||||
#endif
|
#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)
|
||||||
|
|
@ -1270,10 +1270,10 @@ 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)
|
||||||
|
|
||||||
// Apply screen scaling if required
|
// Apply screen scaling if required
|
||||||
rlMultMatrixf(MatrixToFloat(screenScaling));
|
rlMultMatrixf(MatrixToFloat(screenScaling));
|
||||||
|
|
||||||
// Apply 2d camera transformation to modelview
|
// Apply 2d camera transformation to modelview
|
||||||
rlMultMatrixf(MatrixToFloat(GetCameraMatrix2D(camera)));
|
rlMultMatrixf(MatrixToFloat(GetCameraMatrix2D(camera)));
|
||||||
}
|
}
|
||||||
|
|
@ -1465,7 +1465,7 @@ Matrix GetCameraMatrix(Camera camera)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns camera 2d transform matrix
|
// Returns camera 2d transform matrix
|
||||||
Matrix GetCameraMatrix2D(Camera2D camera)
|
Matrix GetCameraMatrix2D(Camera2D camera)
|
||||||
{
|
{
|
||||||
Matrix matTransform = { 0 };
|
Matrix matTransform = { 0 };
|
||||||
// The camera in world-space is set by
|
// The camera in world-space is set by
|
||||||
|
|
@ -1486,9 +1486,9 @@ Matrix GetCameraMatrix2D(Camera2D camera)
|
||||||
Matrix matRotation = MatrixRotate((Vector3){ 0.0f, 0.0f, 1.0f }, camera.rotation*DEG2RAD);
|
Matrix matRotation = MatrixRotate((Vector3){ 0.0f, 0.0f, 1.0f }, camera.rotation*DEG2RAD);
|
||||||
Matrix matScale = MatrixScale(camera.zoom, camera.zoom, 1.0f);
|
Matrix matScale = MatrixScale(camera.zoom, camera.zoom, 1.0f);
|
||||||
Matrix matTranslation = MatrixTranslate(camera.offset.x, camera.offset.y, 0.0f);
|
Matrix matTranslation = MatrixTranslate(camera.offset.x, camera.offset.y, 0.0f);
|
||||||
|
|
||||||
matTransform = MatrixMultiply(MatrixMultiply(matOrigin, MatrixMultiply(matScale, matRotation)), matTranslation);
|
matTransform = MatrixMultiply(MatrixMultiply(matOrigin, MatrixMultiply(matScale, matRotation)), matTranslation);
|
||||||
|
|
||||||
return matTransform;
|
return matTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1535,20 +1535,20 @@ Vector2 GetWorldToScreen(Vector3 position, Camera camera)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the screen space position for a 2d camera world space position
|
// Returns the screen space position for a 2d camera world space position
|
||||||
Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera)
|
Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera)
|
||||||
{
|
{
|
||||||
Matrix matCamera = GetCameraMatrix2D(camera);
|
Matrix matCamera = GetCameraMatrix2D(camera);
|
||||||
Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, matCamera);
|
Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, matCamera);
|
||||||
|
|
||||||
return (Vector2){ transform.x, transform.y };
|
return (Vector2){ transform.x, transform.y };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the world space position for a 2d camera screen space position
|
// Returns the world space position for a 2d camera screen space position
|
||||||
Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera)
|
Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera)
|
||||||
{
|
{
|
||||||
Matrix invMatCamera = MatrixInvert(GetCameraMatrix2D(camera));
|
Matrix invMatCamera = MatrixInvert(GetCameraMatrix2D(camera));
|
||||||
Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, invMatCamera);
|
Vector3 transform = Vector3Transform((Vector3){ position.x, position.y, 0 }, invMatCamera);
|
||||||
|
|
||||||
return (Vector2){ transform.x, transform.y };
|
return (Vector2){ transform.x, transform.y };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1796,29 +1796,21 @@ 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;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -1916,9 +1908,9 @@ const char *GetPrevDirectoryPath(const char *dirPath)
|
||||||
static char prevDirPath[MAX_FILEPATH_LENGTH];
|
static char prevDirPath[MAX_FILEPATH_LENGTH];
|
||||||
memset(prevDirPath, 0, MAX_FILEPATH_LENGTH);
|
memset(prevDirPath, 0, MAX_FILEPATH_LENGTH);
|
||||||
int pathLen = strlen(dirPath);
|
int pathLen = strlen(dirPath);
|
||||||
|
|
||||||
if (pathLen <= 3) strcpy(prevDirPath, dirPath);
|
if (pathLen <= 3) strcpy(prevDirPath, dirPath);
|
||||||
|
|
||||||
for (int i = (pathLen - 1); (i > 0) && (pathLen > 3); i--)
|
for (int i = (pathLen - 1); (i > 0) && (pathLen > 3); i--)
|
||||||
{
|
{
|
||||||
if ((dirPath[i] == '\\') || (dirPath[i] == '/'))
|
if ((dirPath[i] == '\\') || (dirPath[i] == '/'))
|
||||||
|
|
@ -1928,7 +1920,7 @@ const char *GetPrevDirectoryPath(const char *dirPath)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return prevDirPath;
|
return prevDirPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1986,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
|
||||||
|
|
@ -2045,9 +2038,9 @@ long GetFileModTime(const char *fileName)
|
||||||
unsigned char *CompressData(unsigned char *data, int dataLength, int *compDataLength)
|
unsigned char *CompressData(unsigned char *data, int dataLength, int *compDataLength)
|
||||||
{
|
{
|
||||||
#define COMPRESSION_QUALITY_DEFLATE 8
|
#define COMPRESSION_QUALITY_DEFLATE 8
|
||||||
|
|
||||||
unsigned char *compData = NULL;
|
unsigned char *compData = NULL;
|
||||||
|
|
||||||
#if defined(SUPPORT_COMPRESSION_API)
|
#if defined(SUPPORT_COMPRESSION_API)
|
||||||
compData = stbi_zlib_compress(data, dataLength, compDataLength, COMPRESSION_QUALITY_DEFLATE);
|
compData = stbi_zlib_compress(data, dataLength, compDataLength, COMPRESSION_QUALITY_DEFLATE);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -2059,7 +2052,7 @@ unsigned char *CompressData(unsigned char *data, int dataLength, int *compDataLe
|
||||||
unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *dataLength)
|
unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *dataLength)
|
||||||
{
|
{
|
||||||
char *data = NULL;
|
char *data = NULL;
|
||||||
|
|
||||||
#if defined(SUPPORT_COMPRESSION_API)
|
#if defined(SUPPORT_COMPRESSION_API)
|
||||||
data = stbi_zlib_decode_malloc((char *)compData, compDataLength, dataLength);
|
data = stbi_zlib_decode_malloc((char *)compData, compDataLength, dataLength);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -2664,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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4931,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
|
||||||
|
|
||||||
|
|
@ -4945,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
src/external/stb_image.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
|
||||||
|
|
|
||||||
6
src/external/stb_image_write.h
vendored
6
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
|
||||||
|
|
||||||
|
|
@ -868,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;
|
||||||
|
|
@ -1530,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
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
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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
227
src/models.c
227
src/models.c
|
|
@ -2385,8 +2385,18 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
|
||||||
|
|
||||||
for (int i = 0; i < model.meshCount; i++)
|
for (int i = 0; i < model.meshCount; i++)
|
||||||
{
|
{
|
||||||
model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = tint;
|
// TODO: Review color + tint premultiplication mechanism
|
||||||
|
Color color = model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color;
|
||||||
|
|
||||||
|
Color colorTint = WHITE;
|
||||||
|
colorTint.r = (((float)color.r/255.0)*((float)tint.r/255.0))*255;
|
||||||
|
colorTint.g = (((float)color.g/255.0)*((float)tint.g/255.0))*255;
|
||||||
|
colorTint.b = (((float)color.b/255.0)*((float)tint.b/255.0))*255;
|
||||||
|
colorTint.a = (((float)color.a/255.0)*((float)tint.a/255.0))*255;
|
||||||
|
|
||||||
|
model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = colorTint;
|
||||||
rlDrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform);
|
rlDrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform);
|
||||||
|
model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3344,6 +3354,88 @@ static unsigned char *DecodeBase64(char *input, int *size)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load texture from cgltf_image
|
||||||
|
static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath, Color tint)
|
||||||
|
{
|
||||||
|
Texture texture = { 0 };
|
||||||
|
|
||||||
|
if (image->uri)
|
||||||
|
{
|
||||||
|
if ((strlen(image->uri) > 5) &&
|
||||||
|
(image->uri[0] == 'd') &&
|
||||||
|
(image->uri[1] == 'a') &&
|
||||||
|
(image->uri[2] == 't') &&
|
||||||
|
(image->uri[3] == 'a') &&
|
||||||
|
(image->uri[4] == ':'))
|
||||||
|
{
|
||||||
|
// Data URI
|
||||||
|
// Format: data:<mediatype>;base64,<data>
|
||||||
|
|
||||||
|
// Find the comma
|
||||||
|
int i = 0;
|
||||||
|
while ((image->uri[i] != ',') && (image->uri[i] != 0)) i++;
|
||||||
|
|
||||||
|
if (image->uri[i] == 0) TraceLog(LOG_WARNING, "CGLTF Image: Invalid data URI");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
unsigned char *data = DecodeBase64(image->uri + i + 1, &size);
|
||||||
|
|
||||||
|
int w, h;
|
||||||
|
unsigned char *raw = stbi_load_from_memory(data, size, &w, &h, NULL, 4);
|
||||||
|
|
||||||
|
Image rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
|
||||||
|
|
||||||
|
// TODO: Tint shouldn't be applied here!
|
||||||
|
ImageColorTint(&rimage, tint);
|
||||||
|
texture = LoadTextureFromImage(rimage);
|
||||||
|
UnloadImage(rimage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Image rimage = LoadImage(TextFormat("%s/%s", texPath, image->uri));
|
||||||
|
|
||||||
|
// TODO: Tint shouldn't be applied here!
|
||||||
|
ImageColorTint(&rimage, tint);
|
||||||
|
texture = LoadTextureFromImage(rimage);
|
||||||
|
UnloadImage(rimage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (image->buffer_view)
|
||||||
|
{
|
||||||
|
unsigned char *data = RL_MALLOC(image->buffer_view->size);
|
||||||
|
int n = image->buffer_view->offset;
|
||||||
|
int stride = image->buffer_view->stride ? image->buffer_view->stride : 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < image->buffer_view->size; i++)
|
||||||
|
{
|
||||||
|
data[i] = ((unsigned char *)image->buffer_view->buffer->data)[n];
|
||||||
|
n += stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
int w, h;
|
||||||
|
unsigned char *raw = stbi_load_from_memory(data, image->buffer_view->size, &w, &h, NULL, 4);
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
Image rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
|
||||||
|
free(raw);
|
||||||
|
|
||||||
|
// TODO: Tint shouldn't be applied here!
|
||||||
|
ImageColorTint(&rimage, tint);
|
||||||
|
texture = LoadTextureFromImage(rimage);
|
||||||
|
UnloadImage(rimage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Image rimage = LoadImageEx(&tint, 1, 1);
|
||||||
|
texture = LoadTextureFromImage(rimage);
|
||||||
|
UnloadImage(rimage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
// Load glTF mesh data
|
// Load glTF mesh data
|
||||||
static Model LoadGLTF(const char *fileName)
|
static Model LoadGLTF(const char *fileName)
|
||||||
{
|
{
|
||||||
|
|
@ -3409,9 +3501,7 @@ static Model LoadGLTF(const char *fileName)
|
||||||
|
|
||||||
// Read data buffers
|
// Read data buffers
|
||||||
result = cgltf_load_buffers(&options, data, fileName);
|
result = cgltf_load_buffers(&options, data, fileName);
|
||||||
if (result != cgltf_result_success) {
|
if (result != cgltf_result_success) TraceLog(LOG_INFO, "[%s][%s] Error loading mesh/material buffers", fileName, (data->file_type == 2)? "glb" : "gltf");
|
||||||
TraceLog(LOG_INFO, "[%s][%s] Error loading mesh/material buffers", fileName, (data->file_type == 2)? "glb" : "gltf");
|
|
||||||
}
|
|
||||||
|
|
||||||
int primitivesCount = 0;
|
int primitivesCount = 0;
|
||||||
|
|
||||||
|
|
@ -3426,106 +3516,55 @@ static Model LoadGLTF(const char *fileName)
|
||||||
|
|
||||||
for (int i = 0; i < model.meshCount; i++) model.meshes[i].vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int));
|
for (int i = 0; i < model.meshCount; i++) model.meshes[i].vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int));
|
||||||
|
|
||||||
|
//For each material
|
||||||
for (int i = 0; i < model.materialCount - 1; i++)
|
for (int i = 0; i < model.materialCount - 1; i++)
|
||||||
{
|
{
|
||||||
Color tint = WHITE;
|
model.materials[i] = LoadMaterialDefault();
|
||||||
Texture2D texture = { 0 };
|
Color tint = (Color){ 255, 255, 255, 255 };
|
||||||
const char *texPath = GetDirectoryPath(fileName);
|
const char *texPath = GetDirectoryPath(fileName);
|
||||||
|
|
||||||
if (data->materials[i].has_pbr_metallic_roughness)
|
//Ensure material follows raylib support for PBR (metallic/roughness flow)
|
||||||
|
if (data->materials[i].has_pbr_metallic_roughness)
|
||||||
{
|
{
|
||||||
tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255.99f);
|
float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
|
||||||
tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255.99f);
|
float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
|
||||||
tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255.99f);
|
|
||||||
tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255.99f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tint.r = 1.0f;
|
|
||||||
tint.g = 1.0f;
|
|
||||||
tint.b = 1.0f;
|
|
||||||
tint.a = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data->materials[i].has_pbr_metallic_roughness)
|
// NOTE: Material name not used for the moment
|
||||||
{
|
//if (model.materials[i].name && data->materials[i].name) strcpy(model.materials[i].name, data->materials[i].name);
|
||||||
cgltf_image *img = data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image;
|
|
||||||
|
|
||||||
if (img->uri)
|
// TODO: REview: shouldn't these be *255 ???
|
||||||
|
tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
|
||||||
|
tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
|
||||||
|
tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
|
||||||
|
tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
|
||||||
|
|
||||||
|
model.materials[i].maps[MAP_ROUGHNESS].color = tint;
|
||||||
|
|
||||||
|
if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture)
|
||||||
{
|
{
|
||||||
if ((strlen(img->uri) > 5) &&
|
model.materials[i].maps[MAP_ALBEDO].texture = LoadTextureFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath, tint);
|
||||||
(img->uri[0] == 'd') &&
|
|
||||||
(img->uri[1] == 'a') &&
|
|
||||||
(img->uri[2] == 't') &&
|
|
||||||
(img->uri[3] == 'a') &&
|
|
||||||
(img->uri[4] == ':'))
|
|
||||||
{
|
|
||||||
// Data URI
|
|
||||||
// Format: data:<mediatype>;base64,<data>
|
|
||||||
|
|
||||||
// Find the comma
|
|
||||||
int i = 0;
|
|
||||||
while ((img->uri[i] != ',') && (img->uri[i] != 0)) i++;
|
|
||||||
|
|
||||||
if (img->uri[i] == 0) TraceLog(LOG_WARNING, "[%s] Invalid data URI", fileName);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int size;
|
|
||||||
unsigned char *data = DecodeBase64(img->uri + i + 1, &size);
|
|
||||||
|
|
||||||
int w, h;
|
|
||||||
unsigned char *raw = stbi_load_from_memory(data, size, &w, &h, NULL, 4);
|
|
||||||
|
|
||||||
Image image = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
|
|
||||||
ImageColorTint(&image, tint);
|
|
||||||
texture = LoadTextureFromImage(image);
|
|
||||||
UnloadImage(image);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char *textureName = img->uri;
|
|
||||||
char *texturePath = RL_MALLOC(strlen(texPath) + strlen(textureName) + 2);
|
|
||||||
strcpy(texturePath, texPath);
|
|
||||||
strcat(texturePath, "/");
|
|
||||||
strcat(texturePath, textureName);
|
|
||||||
|
|
||||||
Image image = LoadImage(texturePath);
|
|
||||||
ImageColorTint(&image, tint);
|
|
||||||
texture = LoadTextureFromImage(image);
|
|
||||||
UnloadImage(image);
|
|
||||||
RL_FREE(texturePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (img->buffer_view)
|
|
||||||
{
|
|
||||||
unsigned char *data = RL_MALLOC(img->buffer_view->size);
|
|
||||||
int n = img->buffer_view->offset;
|
|
||||||
int stride = img->buffer_view->stride ? img->buffer_view->stride : 1;
|
|
||||||
|
|
||||||
for (int i = 0; i < img->buffer_view->size; i++)
|
|
||||||
{
|
|
||||||
data[i] = ((unsigned char *)img->buffer_view->buffer->data)[n];
|
|
||||||
n += stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
int w, h;
|
|
||||||
unsigned char *raw = stbi_load_from_memory(data, img->buffer_view->size, &w, &h, NULL, 4);
|
|
||||||
|
|
||||||
Image image = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
|
|
||||||
ImageColorTint(&image, tint);
|
|
||||||
texture = LoadTextureFromImage(image);
|
|
||||||
UnloadImage(image);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Image image = LoadImageEx(&tint, 1, 1);
|
|
||||||
texture = LoadTextureFromImage(image);
|
|
||||||
UnloadImage(image);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
model.materials[i] = LoadMaterialDefault();
|
// NOTE: Tint isn't need for other textures.. pass null or clear?
|
||||||
model.materials[i].maps[MAP_DIFFUSE].texture = texture;
|
// Just set as white, multiplying by white has no effect
|
||||||
|
tint = WHITE;
|
||||||
|
|
||||||
|
if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture)
|
||||||
|
{
|
||||||
|
model.materials[i].maps[MAP_ROUGHNESS].texture = LoadTextureFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath, tint);
|
||||||
|
}
|
||||||
|
model.materials[i].maps[MAP_ROUGHNESS].value = roughness;
|
||||||
|
model.materials[i].maps[MAP_METALNESS].value = metallic;
|
||||||
|
|
||||||
|
if (data->materials[i].normal_texture.texture)
|
||||||
|
{
|
||||||
|
model.materials[i].maps[MAP_NORMAL].texture = LoadTextureFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath, tint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->materials[i].occlusion_texture.texture)
|
||||||
|
{
|
||||||
|
model.materials[i].maps[MAP_OCCLUSION].texture = LoadTextureFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath, tint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
80
src/raudio.c
80
src/raudio.c
|
|
@ -198,10 +198,10 @@ 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
|
||||||
|
|
@ -209,11 +209,11 @@ struct rAudioBuffer {
|
||||||
|
|
||||||
bool isSubBufferProcessed[2]; // SubBuffer processed (virtual double buffer)
|
bool isSubBufferProcessed[2]; // SubBuffer processed (virtual double buffer)
|
||||||
unsigned int frameCursorPos; // Frame cursor position
|
unsigned int frameCursorPos; // Frame cursor position
|
||||||
unsigned int bufferSizeInFrames; // Total buffer size in frames
|
unsigned int bufferSizeInFrames; // Total buffer size in frames
|
||||||
unsigned int totalFramesProcessed; // Total frames processed in this buffer (required for play timming)
|
unsigned int totalFramesProcessed; // Total frames processed in this buffer (required for play timming)
|
||||||
|
|
||||||
unsigned char *buffer; // Data buffer, on music stream keeps filling
|
unsigned char *buffer; // Data buffer, on music stream keeps filling
|
||||||
|
|
||||||
rAudioBuffer *next; // Next audio buffer on the list
|
rAudioBuffer *next; // Next audio buffer on the list
|
||||||
rAudioBuffer *prev; // Previous audio buffer on the list
|
rAudioBuffer *prev; // Previous audio buffer on the list
|
||||||
};
|
};
|
||||||
|
|
@ -289,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)
|
||||||
|
|
@ -302,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
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
@ -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]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -486,7 +490,7 @@ 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)
|
||||||
{
|
{
|
||||||
|
|
@ -589,7 +593,7 @@ AudioBuffer *InitAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
|
||||||
{
|
{
|
||||||
AudioBuffer *audioBuffer = (AudioBuffer *)RL_CALLOC(1, sizeof(AudioBuffer));
|
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");
|
||||||
|
|
@ -608,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)
|
||||||
|
|
@ -655,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");
|
||||||
|
|
||||||
|
|
@ -698,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
|
||||||
|
|
@ -722,8 +726,8 @@ 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.
|
// Pitching is just an adjustment of the sample rate.
|
||||||
// Note that this changes the duration of the sound:
|
// Note that this changes the duration of the sound:
|
||||||
// - higher pitches will make the sound faster
|
// - higher pitches will make the sound faster
|
||||||
// - lower pitches make it slower
|
// - 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);
|
||||||
|
|
@ -816,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:
|
||||||
//
|
//
|
||||||
|
|
@ -909,7 +913,7 @@ void ExportWaveAsCode(Wave wave, const char *fileName)
|
||||||
int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
|
int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
|
||||||
|
|
||||||
FILE *txtFile = fopen(fileName, "wt");
|
FILE *txtFile = fopen(fileName, "wt");
|
||||||
|
|
||||||
if (txtFile != NULL)
|
if (txtFile != NULL)
|
||||||
{
|
{
|
||||||
fprintf(txtFile, "\n//////////////////////////////////////////////////////////////////////////////////\n");
|
fprintf(txtFile, "\n//////////////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1211,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)
|
||||||
|
|
@ -1242,7 +1246,7 @@ Music LoadMusicStream(const char *fileName)
|
||||||
music.sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm);
|
music.sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm);
|
||||||
music.loopCount = 0; // Infinite loop by default
|
music.loopCount = 0; // Infinite loop by default
|
||||||
musicLoaded = true;
|
musicLoaded = true;
|
||||||
|
|
||||||
music.ctxData = ctxXm;
|
music.ctxData = ctxXm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1252,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);
|
||||||
|
|
||||||
|
|
@ -1335,7 +1339,7 @@ void PlayMusicStream(Music music)
|
||||||
{
|
{
|
||||||
// For music streams, we need to make sure we maintain the frame cursor position
|
// For music streams, we need to make sure we maintain the frame cursor position
|
||||||
// This is a hack for this section of code in UpdateMusicStream()
|
// 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
|
// NOTE: In case window is minimized, music stream is stopped, just make sure to
|
||||||
// play again on window restore: if (IsMusicPlaying(music)) PlayMusicStream(music);
|
// play again on window restore: if (IsMusicPlaying(music)) PlayMusicStream(music);
|
||||||
ma_uint32 frameCursorPos = audioBuffer->frameCursorPos;
|
ma_uint32 frameCursorPos = audioBuffer->frameCursorPos;
|
||||||
PlayAudioStream(music.stream); // WARNING: This resets the cursor position.
|
PlayAudioStream(music.stream); // WARNING: This resets the cursor position.
|
||||||
|
|
@ -1395,7 +1399,7 @@ void UpdateMusicStream(Music music)
|
||||||
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 streamed 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
|
||||||
|
|
||||||
// TODO: Get the sampleLeft using totalFramesProcessed... but first, get total frames processed correctly...
|
// 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;
|
//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);
|
int sampleLeft = music.sampleCount - (music.stream.buffer->totalFramesProcessed*music.stream.channels);
|
||||||
|
|
@ -1449,7 +1453,7 @@ 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) sampleLeft -= samplesCount/2;
|
if (samplesCount > 1) sampleLeft -= samplesCount/2;
|
||||||
|
|
@ -1549,11 +1553,11 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
|
||||||
// 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;
|
||||||
|
|
||||||
stream.buffer = 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 (stream.buffer != NULL)
|
if (stream.buffer != NULL)
|
||||||
{
|
{
|
||||||
stream.buffer->looping = true; // Always loop for streaming buffers
|
stream.buffer->looping = true; // Always loop for streaming buffers
|
||||||
|
|
@ -1578,7 +1582,7 @@ void CloseAudioStream(AudioStream stream)
|
||||||
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)
|
||||||
{
|
{
|
||||||
if (audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1])
|
if (audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1])
|
||||||
|
|
@ -1587,7 +1591,7 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
|
||||||
|
|
||||||
if (audioBuffer->isSubBufferProcessed[0] && audioBuffer->isSubBufferProcessed[1])
|
if (audioBuffer->isSubBufferProcessed[0] && audioBuffer->isSubBufferProcessed[1])
|
||||||
{
|
{
|
||||||
// Both buffers are available for updating.
|
// Both buffers are available for updating.
|
||||||
// Update the first one and make sure the cursor is moved back to the front.
|
// Update the first one and make sure the cursor is moved back to the front.
|
||||||
subBufferToUpdate = 0;
|
subBufferToUpdate = 0;
|
||||||
audioBuffer->frameCursorPos = 0;
|
audioBuffer->frameCursorPos = 0;
|
||||||
|
|
@ -1604,7 +1608,7 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
|
||||||
// TODO: Get total frames processed on this buffer... DOES NOT WORK.
|
// TODO: Get total frames processed on this buffer... DOES NOT WORK.
|
||||||
audioBuffer->totalFramesProcessed += subBufferSizeInFrames;
|
audioBuffer->totalFramesProcessed += subBufferSizeInFrames;
|
||||||
|
|
||||||
// Does this API expect a whole buffer to be updated in one go?
|
// Does this API expect a whole buffer to be updated in one go?
|
||||||
// Assuming so, but if not will need to change this logic.
|
// Assuming so, but if not will need to change this logic.
|
||||||
if (subBufferSizeInFrames >= (ma_uint32)samplesCount/stream.channels)
|
if (subBufferSizeInFrames >= (ma_uint32)samplesCount/stream.channels)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ 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 loopCount; // Loops count (times music will play), 0 means infinite loop
|
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
|
||||||
|
|
||||||
|
|
|
||||||
18
src/raylib.h
18
src/raylib.h
|
|
@ -106,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)
|
||||||
|
|
@ -432,7 +432,7 @@ 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 loopCount; // Loops count (times music will play), 0 means infinite loop
|
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
|
||||||
|
|
||||||
|
|
@ -1188,14 +1188,11 @@ 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 should be freed!)
|
||||||
|
|
@ -1208,6 +1205,12 @@ 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 const char *TextToUtf8(int codepoint, int *byteLength); // Encode codepoint into utf8 text (char array length returned as parameter)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Basic 3d Shapes Drawing Functions (Module: models)
|
// Basic 3d Shapes Drawing Functions (Module: models)
|
||||||
|
|
@ -1319,6 +1322,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
|
||||||
|
|
@ -1406,7 +1410,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)
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
23
src/rlgl.h
23
src/rlgl.h
|
|
@ -2967,7 +2967,7 @@ char *LoadText(const char *fileName)
|
||||||
Shader LoadShader(const char *vsFileName, const char *fsFileName)
|
Shader LoadShader(const char *vsFileName, const char *fsFileName)
|
||||||
{
|
{
|
||||||
Shader shader = { 0 };
|
Shader shader = { 0 };
|
||||||
|
|
||||||
// NOTE: Shader.locs is allocated by LoadShaderCode()
|
// NOTE: Shader.locs is allocated by LoadShaderCode()
|
||||||
|
|
||||||
char *vShaderStr = NULL;
|
char *vShaderStr = NULL;
|
||||||
|
|
@ -3155,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)
|
||||||
{
|
{
|
||||||
|
|
@ -3170,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
|
||||||
|
|
|
||||||
122
src/rmem.h
122
src/rmem.h
|
|
@ -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,8 +163,8 @@ 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;
|
return (size + (align - 1)) & -align;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,9 +175,9 @@ static inline size_t __AlignSize(const size_t size, const size_t align)
|
||||||
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;
|
||||||
|
|
@ -188,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;
|
||||||
|
|
@ -199,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;
|
||||||
|
|
@ -213,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 };
|
||||||
|
|
@ -228,7 +228,7 @@ 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 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)
|
||||||
{
|
{
|
||||||
|
|
@ -240,7 +240,7 @@ 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)
|
||||||
{
|
{
|
||||||
|
|
@ -251,10 +251,10 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
|
||||||
new_mem = inode;
|
new_mem = inode;
|
||||||
(inode->prev != NULL)? (inode->prev->next = inode->next) : (mempool->freeList.head = inode->next);
|
(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);
|
(inode->next != NULL)? (inode->next->prev = inode->prev) : (mempool->freeList.tail = inode->prev);
|
||||||
|
|
||||||
if (mempool->freeList.head != NULL) mempool->freeList.head->prev = NULL;
|
if (mempool->freeList.head != NULL) mempool->freeList.head->prev = NULL;
|
||||||
else mempool->freeList.tail = NULL;
|
else mempool->freeList.tail = NULL;
|
||||||
|
|
||||||
if (mempool->freeList.tail != NULL) mempool->freeList.tail->next = NULL;
|
if (mempool->freeList.tail != NULL) mempool->freeList.tail->next = NULL;
|
||||||
mempool->freeList.len--;
|
mempool->freeList.len--;
|
||||||
break;
|
break;
|
||||||
|
|
@ -269,7 +269,7 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_mem == NULL)
|
if (new_mem == NULL)
|
||||||
{
|
{
|
||||||
// not enough memory to support the size!
|
// not enough memory to support the size!
|
||||||
|
|
@ -279,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
|
||||||
|
|
@ -314,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
|
||||||
{
|
{
|
||||||
|
|
@ -329,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)
|
||||||
|
|
@ -362,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;
|
||||||
|
|
@ -383,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -392,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;
|
||||||
|
|
@ -402,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -423,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)
|
||||||
{
|
{
|
||||||
|
|
@ -440,42 +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;
|
||||||
((*node)->prev != NULL)? ((*node)->prev->next = (*node)->next) : (mempool->freeList.head = (*node)->next);
|
((*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);
|
((*node)->next != NULL)? ((*node)->next->prev = (*node)->prev) : (mempool->freeList.tail = (*node)->prev);
|
||||||
|
|
||||||
if (mempool->freeList.head != NULL) mempool->freeList.head->prev = NULL;
|
if (mempool->freeList.head != NULL) mempool->freeList.head->prev = NULL;
|
||||||
else mempool->freeList.tail = NULL;
|
else mempool->freeList.tail = NULL;
|
||||||
|
|
||||||
if (mempool->freeList.tail != NULL) mempool->freeList.tail->next = 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;
|
||||||
}
|
}
|
||||||
|
|
@ -484,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;
|
||||||
}
|
}
|
||||||
|
|
@ -501,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;
|
||||||
}
|
}
|
||||||
|
|
@ -514,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -551,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++)
|
||||||
|
|
@ -571,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;
|
||||||
}
|
}
|
||||||
|
|
@ -581,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
|
||||||
|
|
@ -589,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;
|
||||||
}
|
}
|
||||||
|
|
@ -623,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);
|
||||||
|
|
|
||||||
437
src/text.c
437
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]);
|
||||||
}
|
}
|
||||||
|
|
@ -587,7 +608,7 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
|
||||||
|
|
||||||
// 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));
|
||||||
|
|
||||||
|
|
@ -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,22 +1248,20 @@ 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 = 0;
|
int counter = 0;
|
||||||
|
|
||||||
if (text != NULL)
|
if (text != NULL)
|
||||||
{
|
{
|
||||||
counter = 1;
|
counter = 1;
|
||||||
|
|
||||||
// Count how many substrings we have on text and point to every one
|
// Count how many substrings we have on text and point to every one
|
||||||
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
|
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -1389,7 +1273,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
|
||||||
result[counter] = buffer + i + 1;
|
result[counter] = buffer + i + 1;
|
||||||
counter++;
|
counter++;
|
||||||
|
|
||||||
if (counter == MAX_SUBSTRINGS_COUNT) break;
|
if (counter == TEXTSPLIT_MAX_SUBSTRINGS_COUNT) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1492,6 +1376,200 @@ int TextToInteger(const char *text)
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Encode codepoint into utf8 text (char array length returned as parameter)
|
||||||
|
RLAPI const char *TextToUtf8(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -1572,18 +1650,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);
|
||||||
|
|
||||||
|
|
@ -1600,7 +1675,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 };
|
||||||
|
|
||||||
|
|
@ -1609,12 +1684,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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -850,7 +850,7 @@ void ExportImageAsCode(Image image, const char *fileName)
|
||||||
#define BYTES_TEXT_PER_LINE 20
|
#define BYTES_TEXT_PER_LINE 20
|
||||||
|
|
||||||
FILE *txtFile = fopen(fileName, "wt");
|
FILE *txtFile = fopen(fileName, "wt");
|
||||||
|
|
||||||
if (txtFile != NULL)
|
if (txtFile != NULL)
|
||||||
{
|
{
|
||||||
char varFileName[256] = { 0 };
|
char varFileName[256] = { 0 };
|
||||||
|
|
@ -926,11 +926,11 @@ Image ImageCopy(Image image)
|
||||||
Image ImageFromImage(Image image, Rectangle rec)
|
Image ImageFromImage(Image image, Rectangle rec)
|
||||||
{
|
{
|
||||||
Image result = ImageCopy(image);
|
Image result = ImageCopy(image);
|
||||||
|
|
||||||
#if defined(SUPPORT_IMAGE_MANIPULATION)
|
#if defined(SUPPORT_IMAGE_MANIPULATION)
|
||||||
ImageCrop(&result, rec);
|
ImageCrop(&result, rec);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1181,13 +1181,18 @@ void ImageAlphaMask(Image *image, Image alphaMask)
|
||||||
// In case image is only grayscale, we just add alpha channel
|
// In case image is only grayscale, we just add alpha channel
|
||||||
if (image->format == UNCOMPRESSED_GRAYSCALE)
|
if (image->format == UNCOMPRESSED_GRAYSCALE)
|
||||||
{
|
{
|
||||||
ImageFormat(image, UNCOMPRESSED_GRAY_ALPHA);
|
unsigned char *data = (unsigned char *)RL_MALLOC(image->width*image->height*2);
|
||||||
|
|
||||||
// Apply alpha mask to alpha channel
|
// Apply alpha mask to alpha channel
|
||||||
for (int i = 0, k = 1; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 2)
|
for (int i = 0, k = 0; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 2)
|
||||||
{
|
{
|
||||||
((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i];
|
data[k] = ((unsigned char *)image->data)[i];
|
||||||
|
data[k + 1] = ((unsigned char *)mask.data)[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RL_FREE(image->data);
|
||||||
|
image->data = data;
|
||||||
|
image->format = UNCOMPRESSED_GRAY_ALPHA;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1338,13 +1343,13 @@ void ImageCrop(Image *image, Rectangle crop)
|
||||||
{
|
{
|
||||||
// Security check to avoid program crash
|
// Security check to avoid program crash
|
||||||
if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
|
if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
|
||||||
|
|
||||||
// Security checks to validate crop rectangle
|
// Security checks to validate crop rectangle
|
||||||
if (crop.x < 0) { crop.width += crop.x; crop.x = 0; }
|
if (crop.x < 0) { crop.width += crop.x; crop.x = 0; }
|
||||||
if (crop.y < 0) { crop.height += crop.y; crop.y = 0; }
|
if (crop.y < 0) { crop.height += crop.y; crop.y = 0; }
|
||||||
if ((crop.x + crop.width) > image->width) crop.width = image->width - crop.x;
|
if ((crop.x + crop.width) > image->width) crop.width = image->width - crop.x;
|
||||||
if ((crop.y + crop.height) > image->height) crop.height = image->height - crop.y;
|
if ((crop.y + crop.height) > image->height) crop.height = image->height - crop.y;
|
||||||
|
|
||||||
if ((crop.x < image->width) && (crop.y < image->height))
|
if ((crop.x < image->width) && (crop.y < image->height))
|
||||||
{
|
{
|
||||||
// Start the cropping process
|
// Start the cropping process
|
||||||
|
|
@ -1818,7 +1823,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color
|
||||||
}
|
}
|
||||||
|
|
||||||
Image srcCopy = ImageCopy(src); // Make a copy of source image to work with it
|
Image srcCopy = ImageCopy(src); // Make a copy of source image to work with it
|
||||||
|
|
||||||
// Crop source image to desired source rectangle (if required)
|
// Crop source image to desired source rectangle (if required)
|
||||||
if ((src.width != (int)srcRec.width) && (src.height != (int)srcRec.height)) ImageCrop(&srcCopy, srcRec);
|
if ((src.width != (int)srcRec.width) && (src.height != (int)srcRec.height)) ImageCrop(&srcCopy, srcRec);
|
||||||
|
|
||||||
|
|
@ -1827,7 +1832,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color
|
||||||
{
|
{
|
||||||
ImageResize(&srcCopy, (int)dstRec.width, (int)dstRec.height);
|
ImageResize(&srcCopy, (int)dstRec.width, (int)dstRec.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that dstRec is inside dst image
|
// Check that dstRec is inside dst image
|
||||||
// Allow negative position within destination with cropping
|
// Allow negative position within destination with cropping
|
||||||
if (dstRec.x < 0)
|
if (dstRec.x < 0)
|
||||||
|
|
@ -1836,7 +1841,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color
|
||||||
dstRec.width = dstRec.width + dstRec.x;
|
dstRec.width = dstRec.width + dstRec.x;
|
||||||
dstRec.x = 0;
|
dstRec.x = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((dstRec.x + dstRec.width) > dst->width)
|
if ((dstRec.x + dstRec.width) > dst->width)
|
||||||
{
|
{
|
||||||
ImageCrop(&srcCopy, (Rectangle) { 0, 0, dst->width - dstRec.x, dstRec.height });
|
ImageCrop(&srcCopy, (Rectangle) { 0, 0, dst->width - dstRec.x, dstRec.height });
|
||||||
|
|
@ -1849,7 +1854,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color
|
||||||
dstRec.height = dstRec.height + dstRec.y;
|
dstRec.height = dstRec.height + dstRec.y;
|
||||||
dstRec.y = 0;
|
dstRec.y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((dstRec.y + dstRec.height) > dst->height)
|
if ((dstRec.y + dstRec.height) > dst->height)
|
||||||
{
|
{
|
||||||
ImageCrop(&srcCopy, (Rectangle) { 0, 0, dstRec.width, dst->height - dstRec.y });
|
ImageCrop(&srcCopy, (Rectangle) { 0, 0, dstRec.width, dst->height - dstRec.y });
|
||||||
|
|
@ -1875,7 +1880,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color
|
||||||
|
|
||||||
fdst = ColorNormalize(dstPixels[j*(int)dst->width + i]);
|
fdst = ColorNormalize(dstPixels[j*(int)dst->width + i]);
|
||||||
fsrc = ColorNormalize(srcPixels[(j - (int)dstRec.y)*(int)dstRec.width + (i - (int)dstRec.x)]);
|
fsrc = ColorNormalize(srcPixels[(j - (int)dstRec.y)*(int)dstRec.width + (i - (int)dstRec.x)]);
|
||||||
|
|
||||||
// Apply color tint to source image
|
// Apply color tint to source image
|
||||||
fsrc.x *= ftint.x; fsrc.y *= ftint.y; fsrc.z *= ftint.z; fsrc.w *= ftint.w;
|
fsrc.x *= ftint.x; fsrc.y *= ftint.y; fsrc.z *= ftint.z; fsrc.w *= ftint.w;
|
||||||
|
|
||||||
|
|
@ -1938,16 +1943,16 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
|
||||||
|
|
||||||
// Create image to store text
|
// Create image to store text
|
||||||
Image imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK);
|
Image imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK);
|
||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
{
|
{
|
||||||
int next = 0;
|
int next = 0;
|
||||||
letter = GetNextCodepoint(&text[i], &next);
|
letter = GetNextCodepoint(&text[i], &next);
|
||||||
index = GetGlyphIndex(font, letter);
|
index = GetGlyphIndex(font, letter);
|
||||||
|
|
||||||
if (letter == 0x3f) next = 1;
|
if (letter == 0x3f) next = 1;
|
||||||
i += (next - 1);
|
i += (next - 1);
|
||||||
|
|
||||||
if (letter == '\n')
|
if (letter == '\n')
|
||||||
{
|
{
|
||||||
// TODO: Support line break
|
// TODO: Support line break
|
||||||
|
|
@ -1957,7 +1962,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
|
||||||
if (letter != ' ')
|
if (letter != ' ')
|
||||||
{
|
{
|
||||||
ImageDraw(&imText, font.chars[index].image, (Rectangle){ 0, 0, font.chars[index].image.width, font.chars[index].image.height },
|
ImageDraw(&imText, font.chars[index].image, (Rectangle){ 0, 0, font.chars[index].image.width, font.chars[index].image.height },
|
||||||
(Rectangle){ (float)(positionX + font.chars[index].offsetX),(float)font.chars[index].offsetY,
|
(Rectangle){ (float)(positionX + font.chars[index].offsetX),(float)font.chars[index].offsetY,
|
||||||
font.chars[index].image.width, font.chars[index].image.height }, tint);
|
font.chars[index].image.width, font.chars[index].image.height }, tint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1997,7 +2002,7 @@ void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color)
|
||||||
ImageDrawRectangle(dst, (Rectangle){ rec.x, rec.y, rec.width, thick }, color);
|
ImageDrawRectangle(dst, (Rectangle){ rec.x, rec.y, rec.width, thick }, color);
|
||||||
ImageDrawRectangle(dst, (Rectangle){ rec.x, rec.y + thick, thick, rec.height - thick*2 }, color);
|
ImageDrawRectangle(dst, (Rectangle){ rec.x, rec.y + thick, thick, rec.height - thick*2 }, color);
|
||||||
ImageDrawRectangle(dst, (Rectangle){ rec.x + rec.width - thick, rec.y + thick, thick, rec.height - thick*2 }, color);
|
ImageDrawRectangle(dst, (Rectangle){ rec.x + rec.width - thick, rec.y + thick, thick, rec.height - thick*2 }, color);
|
||||||
ImageDrawRectangle(dst, (Rectangle){ rec.x, rec.height - thick, rec.width, thick }, color);
|
ImageDrawRectangle(dst, (Rectangle){ rec.x, rec.y + rec.height - thick, rec.width, thick }, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw text (default font) within an image (destination)
|
// Draw text (default font) within an image (destination)
|
||||||
|
|
@ -2712,9 +2717,9 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
|
||||||
{
|
{
|
||||||
float width = (float)texture.width;
|
float width = (float)texture.width;
|
||||||
float height = (float)texture.height;
|
float height = (float)texture.height;
|
||||||
|
|
||||||
bool flipX = false;
|
bool flipX = false;
|
||||||
|
|
||||||
if (sourceRec.width < 0) { flipX = true; sourceRec.width *= -1; }
|
if (sourceRec.width < 0) { flipX = true; sourceRec.width *= -1; }
|
||||||
if (sourceRec.height < 0) sourceRec.y -= sourceRec.height;
|
if (sourceRec.height < 0) sourceRec.y -= sourceRec.height;
|
||||||
|
|
||||||
|
|
@ -2976,12 +2981,12 @@ static Image LoadAnimatedGIF(const char *fileName, int *frames, int **delays)
|
||||||
fseek(gifFile, 0L, SEEK_END);
|
fseek(gifFile, 0L, SEEK_END);
|
||||||
int size = ftell(gifFile);
|
int size = ftell(gifFile);
|
||||||
fseek(gifFile, 0L, SEEK_SET);
|
fseek(gifFile, 0L, SEEK_SET);
|
||||||
|
|
||||||
unsigned char *buffer = (unsigned char *)RL_CALLOC(size, sizeof(char));
|
unsigned char *buffer = (unsigned char *)RL_CALLOC(size, sizeof(char));
|
||||||
fread(buffer, sizeof(char), size, gifFile);
|
fread(buffer, sizeof(char), size, gifFile);
|
||||||
|
|
||||||
fclose(gifFile); // Close file pointer
|
fclose(gifFile); // Close file pointer
|
||||||
|
|
||||||
int comp = 0;
|
int comp = 0;
|
||||||
image.data = stbi_load_gif_from_memory(buffer, size, delays, &image.width, &image.height, frames, &comp, 4);
|
image.data = stbi_load_gif_from_memory(buffer, size, delays, &image.width, &image.height, frames, &comp, 4);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
// Some basic Defines
|
// Some basic Defines
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
#if defined(PLATFORM_ANDROID)
|
#if defined(PLATFORM_ANDROID)
|
||||||
#define fopen(name, mode) android_fopen(name, mode)
|
#define fopen(name, mode) android_fopen(name, mode)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -86,8 +86,8 @@ typedef enum {
|
||||||
|
|
||||||
typedef struct UWPMessage {
|
typedef struct UWPMessage {
|
||||||
UWPMessageType type; // Message type
|
UWPMessageType type; // Message type
|
||||||
|
|
||||||
Vector2 paramVector0; // Vector parameters
|
Vector2 paramVector0; // Vector parameters
|
||||||
int paramInt0; // Int parameter
|
int paramInt0; // Int parameter
|
||||||
int paramInt1; // Int parameter
|
int paramInt1; // Int parameter
|
||||||
char paramChar0; // Char parameters
|
char paramChar0; // Char parameters
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user