Merge branch 'master' into embedded-optimizations-pico
This commit is contained in:
commit
739b78c43d
64 changed files with 9694 additions and 3281 deletions
|
|
@ -107,6 +107,20 @@ endif ()
|
|||
target_link_libraries(raylib PRIVATE $<BUILD_INTERFACE:${LIBS_PRIVATE}>)
|
||||
target_link_libraries(raylib PUBLIC ${LIBS_PUBLIC})
|
||||
|
||||
# Static libraries must export their private link dependencies for installed consumers.
|
||||
# LINK_ONLY keeps those dependencies out of the compile interface.
|
||||
if (NOT BUILD_SHARED_LIBS)
|
||||
set(raylib_install_private_libs ${LIBS_PRIVATE})
|
||||
|
||||
if (NOT glfw3_FOUND)
|
||||
list(REMOVE_ITEM raylib_install_private_libs glfw)
|
||||
endif()
|
||||
|
||||
foreach(lib IN LISTS raylib_install_private_libs)
|
||||
target_link_libraries(raylib INTERFACE $<INSTALL_INTERFACE:$<LINK_ONLY:${lib}>>)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Sets some compile time definitions for the pre-processor
|
||||
# If CUSTOMIZE_BUILD option is on you will not use config.h by default
|
||||
# and you will be able to select more build options
|
||||
|
|
|
|||
27
src/config.h
27
src/config.h
|
|
@ -173,20 +173,22 @@
|
|||
//#define RL_CULL_DISTANCE_FAR 4000.0 // Default projection matrix far cull distance
|
||||
|
||||
// Default shader vertex attribute locations
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES 7
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8
|
||||
// NOTE: Locations can be redefined by user if required
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES 7
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM 9
|
||||
|
||||
// Default shader vertex attribute/uniform names to set location points
|
||||
// NOTE: When a new shader is loaded, locations are tried to be set for convenience, looking for the names defined here
|
||||
// In case custom shader names are used, it's up to the user to set locations with GetShaderLocation*() functions
|
||||
// WARNING: Location pre-defined names can not be changed, they are used by default shaders and all raylib examples shaders, they are just listed here for reference
|
||||
// WARNING: In case custom shader names are used, it's up to the user to set locations with GetShaderLocation*() functions
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL
|
||||
|
|
@ -196,6 +198,7 @@
|
|||
//#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS
|
||||
//#define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM
|
||||
|
||||
//#define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
|
||||
//#define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
|
||||
//#define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix
|
||||
|
|
@ -203,6 +206,7 @@
|
|||
//#define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))
|
||||
//#define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (tint color, multiplied by texture color)
|
||||
//#define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices
|
||||
|
||||
//#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0)
|
||||
//#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1)
|
||||
//#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)
|
||||
|
|
@ -240,6 +244,9 @@
|
|||
#ifndef SUPPORT_FILEFORMAT_QOI
|
||||
#define SUPPORT_FILEFORMAT_QOI 1
|
||||
#endif
|
||||
#ifndef SUPPORT_FILEFORMAT_PEP
|
||||
#define SUPPORT_FILEFORMAT_PEP 0
|
||||
#endif
|
||||
#ifndef SUPPORT_FILEFORMAT_PSD
|
||||
#define SUPPORT_FILEFORMAT_PSD 0 // Disabled by default
|
||||
#endif
|
||||
|
|
|
|||
1328
src/external/pep.h
vendored
Normal file
1328
src/external/pep.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
8
src/external/rlsw.h
vendored
8
src/external/rlsw.h
vendored
|
|
@ -3924,7 +3924,6 @@ static void sw_immediate_set_color(const float color[4])
|
|||
RLSW.primitive.color[2] = color[2];
|
||||
RLSW.primitive.color[3] = color[3];
|
||||
|
||||
RLSW.primitive.hasColorAlpha |= (color[3] < 1.0f);
|
||||
}
|
||||
|
||||
static void sw_immediate_set_texcoord(const float texcoord[2])
|
||||
|
|
@ -3963,6 +3962,9 @@ static void sw_immediate_push_vertex(const float position[4])
|
|||
for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.primitive.color[i];
|
||||
for (int i = 0; i < 2; i++) vertex->texcoord[i] = RLSW.primitive.texcoord[i];
|
||||
|
||||
// Track whether any vertex in this primitive has alpha < 1.0
|
||||
RLSW.primitive.hasColorAlpha |= (vertex->color[3] < 1.0f);
|
||||
|
||||
// Immediate rendering of the primitive if the required number is reached
|
||||
if (RLSW.primitive.vertexCount == SW_PRIMITIVE_VERTEX_COUNT[RLSW.drawMode])
|
||||
{
|
||||
|
|
@ -4341,8 +4343,8 @@ void swScissor(int x, int y, int width, int height)
|
|||
|
||||
RLSW.scClipMin[0] = (2.0f*(float)RLSW.scMin[0]/(float)RLSW.vpSize[0]) - 1.0f;
|
||||
RLSW.scClipMax[0] = (2.0f*(float)RLSW.scMax[0]/(float)RLSW.vpSize[0]) - 1.0f;
|
||||
RLSW.scClipMax[1] = 1.0f - (2.0f*(float)RLSW.scMin[1]/(float)RLSW.vpSize[1]);
|
||||
RLSW.scClipMin[1] = 1.0f - (2.0f*(float)RLSW.scMax[1]/(float)RLSW.vpSize[1]);
|
||||
RLSW.scClipMin[1] = (2.0f*(float)RLSW.scMin[1]/(float)RLSW.vpSize[1]) - 1.0f;
|
||||
RLSW.scClipMax[1] = (2.0f*(float)RLSW.scMax[1]/(float)RLSW.vpSize[1]) - 1.0f;
|
||||
}
|
||||
|
||||
void swClearColor(float r, float g, float b, float a)
|
||||
|
|
|
|||
23
src/external/tinyobj_loader_c.h
vendored
23
src/external/tinyobj_loader_c.h
vendored
|
|
@ -1020,7 +1020,12 @@ static int parseLine(Command *command, const char *p, unsigned int p_len,
|
|||
int triangulate) {
|
||||
char linebuf[4096];
|
||||
const char *token;
|
||||
assert(p_len < 4095);
|
||||
|
||||
// @raysan5:
|
||||
// WARNING: If -DNDEBUG is set when compiling, assertions will not
|
||||
// be present in the compiled binary, replacing by a runtime check
|
||||
//assert(p_len < 4095);
|
||||
if (p_len > 4095) return 0;
|
||||
|
||||
memcpy(linebuf, p, p_len);
|
||||
linebuf[p_len] = '\0';
|
||||
|
|
@ -1102,8 +1107,12 @@ static int parseLine(Command *command, const char *p, unsigned int p_len,
|
|||
tinyobj_vertex_index_t i1;
|
||||
tinyobj_vertex_index_t i2 = f[1];
|
||||
|
||||
assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
|
||||
|
||||
// @raysan5:
|
||||
// WARNING: If -DNDEBUG is set when compiling, assertions will not
|
||||
// be present in the compiled binary, replacing by a runtime check
|
||||
//assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
|
||||
if (3*num_f > TINYOBJ_MAX_FACES_PER_F_LINE) return 0;
|
||||
|
||||
for (k = 2; k < num_f; k++) {
|
||||
i1 = i2;
|
||||
i2 = f[k];
|
||||
|
|
@ -1119,7 +1128,13 @@ static int parseLine(Command *command, const char *p, unsigned int p_len,
|
|||
|
||||
} else {
|
||||
unsigned int k = 0;
|
||||
assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
|
||||
|
||||
// @raysan5:
|
||||
// WARNING: If -DNDEBUG is set when compiling, assertions will not
|
||||
// be present in the compiled binary, replacing by a runtime check
|
||||
//assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
|
||||
if (num_f > TINYOBJ_MAX_FACES_PER_F_LINE) return 0;
|
||||
|
||||
for (k = 0; k < num_f; k++) {
|
||||
command->f[k] = f[k];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -663,13 +663,22 @@ double GetTime(void)
|
|||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if the provided URL is safe
|
||||
// A user could craft a malicious string performing another action
|
||||
// Avoid calling this function with user input non-validated strings
|
||||
// WARNING: This function is only safe to use if you control the URL given,
|
||||
// a user could craft a malicious string to perform and undesired action
|
||||
// NOTE: Some safety checks have been added to mitigate security issues
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
// Security check to (partially) avoid malicious code
|
||||
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
|
||||
if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL))
|
||||
{
|
||||
// Filter characters: ' and "
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters");
|
||||
}
|
||||
else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0))
|
||||
{
|
||||
// Only allow URL starting with "http://" or "https://" protocols
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols");
|
||||
}
|
||||
else
|
||||
{
|
||||
JNIEnv *env = NULL;
|
||||
|
|
@ -717,7 +726,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
|
|||
void SetMousePosition(int x, int y)
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
}
|
||||
|
||||
// Set mouse cursor
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ static void CharCallback(GLFWwindow *window, unsigned int codepoint);
|
|||
static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed
|
||||
static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move
|
||||
static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Scrolling Callback, runs on mouse wheel
|
||||
static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area
|
||||
static void CursorEnterCallback(GLFWwindow *window, int entered); // GLFW3 Cursor Enter Callback, cursor enters client area
|
||||
static void JoystickCallback(int jid, int event); // GLFW3 Joystick Connected/Disconnected Callback
|
||||
|
||||
// Memory allocator wrappers [used by glfwInitAllocator()]
|
||||
|
|
@ -1181,17 +1181,25 @@ double GetTime(void)
|
|||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if you control the URL given
|
||||
// A user could craft a malicious string performing another action
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself
|
||||
// REF: https://github.com/raysan5/raylib/issues/686
|
||||
// WARNING: This function is only safe to use if you control the URL given,
|
||||
// a user could craft a malicious string to perform and undesired action
|
||||
// NOTE: Some safety checks have been added to mitigate security issues
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
// Security check to (partially) avoid malicious code
|
||||
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
|
||||
else
|
||||
if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL))
|
||||
{
|
||||
char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
|
||||
// Filter characters: ' and "
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters");
|
||||
}
|
||||
else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0))
|
||||
{
|
||||
// Only allow URL starting with "http://" or "https://" protocols
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols");
|
||||
}
|
||||
else
|
||||
{
|
||||
char *cmd = (char *)RL_CALLOC(strlen(url) + 16, sizeof(char));
|
||||
#if defined(_WIN32)
|
||||
sprintf(cmd, "explorer \"%s\"", url);
|
||||
#endif
|
||||
|
|
@ -1201,7 +1209,9 @@ void OpenURL(const char *url)
|
|||
#if defined(__APPLE__)
|
||||
sprintf(cmd, "open '%s'", url);
|
||||
#endif
|
||||
// TODO: Replace system() call by custom process
|
||||
int result = system(cmd);
|
||||
|
||||
if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
|
||||
RL_FREE(cmd);
|
||||
}
|
||||
|
|
@ -1227,7 +1237,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
|
|||
void SetMousePosition(int x, int y)
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
|
||||
// NOTE: emscripten not implemented
|
||||
glfwSetCursorPos(platform.handle, CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y);
|
||||
|
|
@ -1316,7 +1325,7 @@ void PollInputEvents(void)
|
|||
// Register previous gamepad states
|
||||
for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k];
|
||||
|
||||
// Get current gamepad state
|
||||
// Get current gamepad state using internal GLFW mapping, instead of the immediate joystick API
|
||||
// NOTE: There is no callback available, getting it manually
|
||||
GLFWgamepadstate state = { 0 };
|
||||
int result = glfwGetGamepadState(i, &state); // This remaps all gamepads so they have their buttons mapped like an xbox controller
|
||||
|
|
@ -1331,7 +1340,7 @@ void PollInputEvents(void)
|
|||
|
||||
for (int k = 0; (buttons != NULL) && (k < MAX_GAMEPAD_BUTTONS); k++)
|
||||
{
|
||||
int button = -1; // GamepadButton enum values assigned
|
||||
int button = -1; // GamepadButton enum values assigned
|
||||
|
||||
switch (k)
|
||||
{
|
||||
|
|
@ -1357,7 +1366,7 @@ void PollInputEvents(void)
|
|||
default: break;
|
||||
}
|
||||
|
||||
if (button != -1) // Check for valid button
|
||||
if (button != -1) // Check for valid button
|
||||
{
|
||||
if (buttons[k] == GLFW_PRESS)
|
||||
{
|
||||
|
|
@ -1399,10 +1408,10 @@ void PollInputEvents(void)
|
|||
if ((CORE.Window.eventWaiting) ||
|
||||
(FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED) && !FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN)))
|
||||
{
|
||||
glfwWaitEvents(); // Wait for in input events before continue (drawing is paused)
|
||||
glfwWaitEvents(); // Wait for in input events before continue (drawing is paused)
|
||||
CORE.Time.previous = GetTime();
|
||||
}
|
||||
else glfwPollEvents(); // Poll input events: keyboard/mouse/window events (callbacks) -> Update keys state
|
||||
else glfwPollEvents(); // Poll input events: keyboard/mouse/window events (callbacks) -> Update keys state
|
||||
|
||||
CORE.Window.shouldClose = glfwWindowShouldClose(platform.handle);
|
||||
|
||||
|
|
@ -1683,6 +1692,14 @@ int InitPlatform(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// AppKit can constrain the requested window size to the visible work area during creation
|
||||
int windowWidth = 0;
|
||||
int windowHeight = 0;
|
||||
glfwGetWindowSize(platform.handle, &windowWidth, &windowHeight);
|
||||
if ((windowWidth > 0) && (windowHeight > 0)) CORE.Window.screen = (Size){ windowWidth, windowHeight };
|
||||
#endif
|
||||
|
||||
// NOTE: Not considering scale factor now, considered below
|
||||
CORE.Window.render.width = CORE.Window.screen.width;
|
||||
CORE.Window.render.height = CORE.Window.screen.height;
|
||||
|
|
@ -1829,7 +1846,7 @@ int InitPlatform(void)
|
|||
{
|
||||
CORE.Input.Gamepad.ready[i] = true;
|
||||
CORE.Input.Gamepad.axisCount[i] = GLFW_GAMEPAD_AXIS_LAST + 1;
|
||||
strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
snprintf(CORE.Input.Gamepad.name[i], MAX_GAMEPAD_NAME_LENGTH, "%s", glfwGetJoystickName(i));
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
@ -2044,7 +2061,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
|
|||
for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++)
|
||||
{
|
||||
CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
|
||||
strncpy(CORE.Window.dropFilepaths[i], paths[i], MAX_FILEPATH_LENGTH - 1);
|
||||
snprintf(CORE.Window.dropFilepaths[i], MAX_FILEPATH_LENGTH, "%s", paths[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2167,10 +2184,18 @@ static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffs
|
|||
}
|
||||
|
||||
// GLFW3: Cursor ennter callback, when cursor enters the window
|
||||
static void CursorEnterCallback(GLFWwindow *window, int enter)
|
||||
static void CursorEnterCallback(GLFWwindow *window, int entered)
|
||||
{
|
||||
if (enter) CORE.Input.Mouse.cursorOnScreen = true;
|
||||
else CORE.Input.Mouse.cursorOnScreen = false;
|
||||
if (entered)
|
||||
{
|
||||
// NOTE: Mouse position updated by MouseCursorPosCallback()
|
||||
CORE.Input.Mouse.cursorOnScreen = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Input.Mouse.cursorOnScreen = false;
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ 0 };
|
||||
}
|
||||
}
|
||||
|
||||
// GLFW3: Joystick connected/disconnected callback
|
||||
|
|
@ -2183,7 +2208,7 @@ static void JoystickCallback(int jid, int event)
|
|||
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
|
||||
// only copy up to (MAX_GAMEPAD_NAME_LENGTH -1) to destination string
|
||||
memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
|
||||
strncpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
snprintf(CORE.Input.Gamepad.name[jid], MAX_GAMEPAD_NAME_LENGTH, "%s", glfwGetJoystickName(jid));
|
||||
}
|
||||
else if (event == GLFW_DISCONNECTED)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -486,14 +486,14 @@ static void RGFW_cb_dropfunc(const RGFW_event *e)
|
|||
CORE.Window.dropFilepaths = (char **)RL_CALLOC(1024, sizeof(char *));
|
||||
|
||||
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
|
||||
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], e->drop.value->data);
|
||||
snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", e->drop.value->data);
|
||||
|
||||
CORE.Window.dropFileCount++;
|
||||
}
|
||||
else if (CORE.Window.dropFileCount < 1024)
|
||||
{
|
||||
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
|
||||
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], e->drop.value->data);
|
||||
snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", e->drop.value->data);
|
||||
|
||||
CORE.Window.dropFileCount++;
|
||||
}
|
||||
|
|
@ -1471,15 +1471,25 @@ double GetTime(void)
|
|||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if you control the URL given
|
||||
// A user could craft a malicious string performing another action
|
||||
// WARNING: This function is only safe to use if you control the URL given,
|
||||
// a user could craft a malicious string to perform and undesired action
|
||||
// NOTE: Some safety checks have been added to mitigate security issues
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
// Security check to (partially) avoid malicious code on target platform
|
||||
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
|
||||
else
|
||||
// Security check to (partially) avoid malicious code
|
||||
if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL))
|
||||
{
|
||||
char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
|
||||
// Filter characters: ' and "
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters");
|
||||
}
|
||||
else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0))
|
||||
{
|
||||
// Only allow URL starting with "http://" or "https://" protocols
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols");
|
||||
}
|
||||
else
|
||||
{
|
||||
char *cmd = (char *)RL_CALLOC(strlen(url) + 16, sizeof(char));
|
||||
#if defined(_WIN32)
|
||||
sprintf(cmd, "explorer \"%s\"", url);
|
||||
#endif
|
||||
|
|
@ -1516,7 +1526,6 @@ void SetMousePosition(int x, int y)
|
|||
{
|
||||
RGFW_window_moveMouse(platform.window, x, y);
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
}
|
||||
|
||||
// Set mouse cursor
|
||||
|
|
@ -1609,74 +1618,76 @@ void PollInputEvents(void)
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
mg_event gamepad_event;
|
||||
while (mg_gamepads_check_event(&platform.minigamepad, &gamepad_event)) {
|
||||
while (mg_gamepads_check_event(&platform.minigamepad, &gamepad_event))
|
||||
{
|
||||
int gamepadIndex = gamepad_event.gamepad->index;
|
||||
switch (gamepad_event.type) {
|
||||
|
||||
switch (gamepad_event.type)
|
||||
{
|
||||
case MG_EVENT_BUTTON_PRESS:
|
||||
{
|
||||
int button = mg_buttonConvertTable[gamepad_event.button];
|
||||
if (button >= 0)
|
||||
{
|
||||
int button = mg_buttonConvertTable[gamepad_event.button];
|
||||
if (button >= 0)
|
||||
{
|
||||
CORE.Input.Gamepad.currentButtonState[gamepadIndex][button] = 1;
|
||||
CORE.Input.Gamepad.lastButtonPressed = button;
|
||||
}
|
||||
} break;
|
||||
CORE.Input.Gamepad.currentButtonState[gamepadIndex][button] = 1;
|
||||
CORE.Input.Gamepad.lastButtonPressed = button;
|
||||
}
|
||||
} break;
|
||||
case MG_EVENT_BUTTON_RELEASE:
|
||||
{
|
||||
int button = mg_buttonConvertTable[gamepad_event.button];
|
||||
if (button >= 0)
|
||||
{
|
||||
int button = mg_buttonConvertTable[gamepad_event.button];
|
||||
if (button >= 0)
|
||||
{
|
||||
CORE.Input.Gamepad.currentButtonState[gamepadIndex][button] = 0;
|
||||
if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
|
||||
}
|
||||
} break;
|
||||
CORE.Input.Gamepad.currentButtonState[gamepadIndex][button] = 0;
|
||||
if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
|
||||
}
|
||||
} break;
|
||||
case MG_EVENT_AXIS_MOVE:
|
||||
{
|
||||
int axis = mg_axisConvertTable[gamepad_event.axis];
|
||||
{
|
||||
int axis = mg_axisConvertTable[gamepad_event.axis];
|
||||
|
||||
switch (axis) {
|
||||
case GAMEPAD_AXIS_LEFT_X:
|
||||
case GAMEPAD_AXIS_LEFT_Y:
|
||||
case GAMEPAD_AXIS_RIGHT_X:
|
||||
case GAMEPAD_AXIS_RIGHT_Y:
|
||||
CORE.Input.Gamepad.axisState[gamepadIndex][axis] = platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value;
|
||||
break;
|
||||
case GAMEPAD_AXIS_LEFT_TRIGGER:
|
||||
case GAMEPAD_AXIS_RIGHT_TRIGGER:
|
||||
CORE.Input.Gamepad.axisState[gamepadIndex][axis] = platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value;
|
||||
switch (axis) {
|
||||
case GAMEPAD_AXIS_LEFT_X:
|
||||
case GAMEPAD_AXIS_LEFT_Y:
|
||||
case GAMEPAD_AXIS_RIGHT_X:
|
||||
case GAMEPAD_AXIS_RIGHT_Y:
|
||||
{
|
||||
CORE.Input.Gamepad.axisState[gamepadIndex][axis] = platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value;
|
||||
} break;
|
||||
case GAMEPAD_AXIS_LEFT_TRIGGER:
|
||||
case GAMEPAD_AXIS_RIGHT_TRIGGER:
|
||||
{
|
||||
CORE.Input.Gamepad.axisState[gamepadIndex][axis] = platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value;
|
||||
|
||||
// Trigger button press when axis is all the way
|
||||
int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER) ? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
|
||||
int pressed = (platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value >= 1.0f);
|
||||
// Trigger button press when axis is all the way
|
||||
int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER) ? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
|
||||
int pressed = (platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value >= 1.0f);
|
||||
|
||||
CORE.Input.Gamepad.currentButtonState[gamepadIndex][button] = pressed;
|
||||
if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
|
||||
else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
CORE.Input.Gamepad.currentButtonState[gamepadIndex][button] = pressed;
|
||||
if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
|
||||
else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
} break;
|
||||
case MG_EVENT_GAMEPAD_CONNECT:
|
||||
{
|
||||
CORE.Input.Gamepad.ready[gamepadIndex] = true;
|
||||
CORE.Input.Gamepad.axisState[gamepadIndex][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
|
||||
CORE.Input.Gamepad.axisState[gamepadIndex][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
|
||||
|
||||
int axisCount = 0;
|
||||
for (int i = 0; i < MG_AXIS_COUNT; i += 1) {
|
||||
if (platform.minigamepad.gamepads[gamepadIndex].axes[i].supported)
|
||||
{
|
||||
axisCount += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < MG_AXIS_COUNT; i += 1)
|
||||
{
|
||||
if (platform.minigamepad.gamepads[gamepadIndex].axes[i].supported) axisCount += 1;
|
||||
else break;
|
||||
}
|
||||
|
||||
CORE.Input.Gamepad.axisCount[gamepadIndex] = axisCount;
|
||||
strcpy(CORE.Input.Gamepad.name[gamepadIndex], platform.minigamepad.gamepads[gamepadIndex].name);
|
||||
break;
|
||||
case MG_EVENT_GAMEPAD_DISCONNECT:
|
||||
CORE.Input.Gamepad.ready[gamepadIndex] = false;
|
||||
break;
|
||||
snprintf(CORE.Input.Gamepad.name[gamepadIndex], MAX_GAMEPAD_NAME_LENGTH, "%s", platform.minigamepad.gamepads[gamepadIndex].name);
|
||||
|
||||
} break;
|
||||
case MG_EVENT_GAMEPAD_DISCONNECT: CORE.Input.Gamepad.ready[gamepadIndex] = false; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -863,7 +863,7 @@ void SetWindowMonitor(int monitor)
|
|||
// ending up positioned partly outside the target display
|
||||
// NOTE 2: The workaround for that is, previously to moving the window,
|
||||
// setting the window size to the target display size, so they match
|
||||
// NOTE 3: It wasn't done here because it can not bee assumed that changing
|
||||
// NOTE 3: It wasn't done here because it can not be assumed that changing
|
||||
// the window size automatically is acceptable behavior by the user
|
||||
SDL_SetWindowPosition(platform.window, usableBounds.x, usableBounds.y);
|
||||
CORE.Window.position.x = usableBounds.x;
|
||||
|
|
@ -1255,12 +1255,14 @@ Image GetClipboardImage(void)
|
|||
|
||||
for (int i = 0; i < SDL_arraysize(imageFormats); i++)
|
||||
{
|
||||
// NOTE: This pointer should be free with SDL_free() at some point
|
||||
fileData = SDL_GetClipboardData(imageFormats[i], &dataSize);
|
||||
|
||||
if (fileData)
|
||||
{
|
||||
image = LoadImageFromMemory(imageExtensions[i], fileData, (int)dataSize);
|
||||
|
||||
SDL_free(fileData);
|
||||
|
||||
if (IsImageValid(image))
|
||||
{
|
||||
TRACELOG(LOG_INFO, "Clipboard: Got image from clipboard successfully: %s", imageExtensions[i]);
|
||||
|
|
@ -1341,14 +1343,22 @@ double GetTime(void)
|
|||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if the provided URL is safe
|
||||
// A user could craft a malicious string performing another action
|
||||
// Avoid calling this function with user input non-validated strings
|
||||
// REF: https://github.com/raysan5/raylib/issues/686
|
||||
// WARNING: This function is only safe to use if you control the URL given,
|
||||
// a user could craft a malicious string to perform and undesired action
|
||||
// NOTE: Some safety checks have been added to mitigate security issues
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
// Security check to (partially) avoid malicious code
|
||||
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
|
||||
if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL))
|
||||
{
|
||||
// Filter characters: ' and "
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters");
|
||||
}
|
||||
else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0))
|
||||
{
|
||||
// Only allow URL starting with "http://" or "https://" protocols
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols");
|
||||
}
|
||||
else SDL_OpenURL(url);
|
||||
}
|
||||
|
||||
|
|
@ -1401,7 +1411,6 @@ void SetMousePosition(int x, int y)
|
|||
SDL_WarpMouseInWindow(platform.window, x, y);
|
||||
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
}
|
||||
|
||||
// Set mouse cursor
|
||||
|
|
@ -1512,9 +1521,9 @@ void PollInputEvents(void)
|
|||
// Event memory is now managed by SDL, so it should not be freed in SDL_EVENT_DROP_FILE,
|
||||
// in case data needs to be hold onto the text in SDL_EVENT_TEXT_EDITING and SDL_EVENT_TEXT_INPUT events,
|
||||
// a copy is required, SDL_TEXTINPUTEVENT_TEXT_SIZE is no longer necessary and has been removed
|
||||
strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data, MAX_FILEPATH_LENGTH - 1);
|
||||
snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", event.drop.data);
|
||||
#else
|
||||
strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file, MAX_FILEPATH_LENGTH - 1);
|
||||
snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", event.drop.file);
|
||||
SDL_free(event.drop.file);
|
||||
#endif
|
||||
|
||||
|
|
@ -1525,9 +1534,9 @@ void PollInputEvents(void)
|
|||
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
|
||||
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data, MAX_FILEPATH_LENGTH - 1);
|
||||
snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", event.drop.data);
|
||||
#else
|
||||
strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file, MAX_FILEPATH_LENGTH - 1);
|
||||
snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", event.drop.file);
|
||||
SDL_free(event.drop.file);
|
||||
#endif
|
||||
|
||||
|
|
@ -1812,8 +1821,8 @@ void PollInputEvents(void)
|
|||
CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
|
||||
memset(CORE.Input.Gamepad.name[nextAvailableSlot], 0, MAX_GAMEPAD_NAME_LENGTH);
|
||||
const char *controllerName = SDL_GameControllerNameForIndex(nextAvailableSlot);
|
||||
if (controllerName != NULL) strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], controllerName, MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
else strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], "noname", 6);
|
||||
if (controllerName != NULL) snprintf(CORE.Input.Gamepad.name[nextAvailableSlot], MAX_GAMEPAD_NAME_LENGTH, "%s", controllerName);
|
||||
else memcpy(CORE.Input.Gamepad.name[nextAvailableSlot], "noname", 6);
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
|
||||
}
|
||||
|
|
@ -2164,11 +2173,20 @@ int InitPlatform(void)
|
|||
platform.gamepadId[i] = -1; // Set all gamepad initial instance ids as invalid to not conflict with instance id zero
|
||||
}
|
||||
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
int numJoysticks;
|
||||
SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks);
|
||||
#else
|
||||
int numJoysticks = SDL_NumJoysticks();
|
||||
#endif
|
||||
|
||||
for (int i = 0; (i < numJoysticks) && (i < MAX_GAMEPADS); i++)
|
||||
{
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
platform.gamepad[i] = SDL_OpenGamepad(joysticks[i]);
|
||||
#else
|
||||
platform.gamepad[i] = SDL_GameControllerOpen(i);
|
||||
#endif
|
||||
platform.gamepadId[i] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[i]));
|
||||
|
||||
if (platform.gamepad[i])
|
||||
|
|
@ -2177,7 +2195,12 @@ int InitPlatform(void)
|
|||
CORE.Input.Gamepad.axisCount[i] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[i]));
|
||||
CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
|
||||
CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
|
||||
strncpy(CORE.Input.Gamepad.name[i], SDL_GameControllerNameForIndex(i), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
const char *joystickName = SDL_GetJoystickNameForID(joysticks[i]);
|
||||
#else
|
||||
const char *joystickName = SDL_GameControllerNameForIndex(i);
|
||||
#endif
|
||||
snprintf(CORE.Input.Gamepad.name[i], MAX_GAMEPAD_NAME_LENGTH, "%s", joystickName);
|
||||
CORE.Input.Gamepad.name[i][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0';
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
|
||||
|
|
|
|||
|
|
@ -1247,19 +1247,28 @@ double GetTime(void)
|
|||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if the provided URL is safe
|
||||
// A user could craft a malicious string performing another action
|
||||
// Avoid calling this function with user input non-validated strings
|
||||
// REF: https://github.com/raysan5/raylib/issues/686
|
||||
// WARNING: This function is only safe to use if you control the URL given,
|
||||
// a user could craft a malicious string to perform and undesired action
|
||||
// NOTE: Some safety checks have been added to mitigate security issues
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
// Security check to (partially) avoid malicious code on target platform
|
||||
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
|
||||
else
|
||||
// Security check to (partially) avoid malicious code
|
||||
if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL))
|
||||
{
|
||||
int len = strlen(url) + 32;
|
||||
// Filter characters: ' and "
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters");
|
||||
}
|
||||
else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0))
|
||||
{
|
||||
// Only allow URL starting with "http://" or "https://" protocols
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols");
|
||||
}
|
||||
else
|
||||
{
|
||||
int len = strlen(url) + 16;
|
||||
char *cmd = (char *)RL_CALLOC(len, sizeof(char));
|
||||
snprintf(cmd, len, "explorer \"%s\"", url);
|
||||
|
||||
int result = system(cmd);
|
||||
if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
|
||||
RL_FREE(cmd);
|
||||
|
|
@ -1290,8 +1299,8 @@ void SetMousePosition(int x, int y)
|
|||
if (!CORE.Input.Mouse.cursorLocked)
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
TRACELOG(LOG_WARNING, "SetMousePosition not implemented");
|
||||
|
||||
TRACELOG(LOG_WARNING, "SetMousePosition not implemented at platform level");
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "INPUT: MOUSE: Cursor not enabled");
|
||||
}
|
||||
|
|
@ -2213,7 +2222,7 @@ static unsigned SanitizeFlags(int mode, unsigned flags)
|
|||
//
|
||||
// This design takes care of many odd corner cases. For example, in case of restoring
|
||||
// a window that was previously maximized AND minimized and those two flags need to be removed,
|
||||
// ShowWindow with SW_RESTORE twice need to bee actually calleed. Another example is
|
||||
// ShowWindow with SW_RESTORE twice need to be actually calleed. Another example is
|
||||
// wheen having a maximized window, if the undecorated flag is modified then the window style
|
||||
// needs to be updated, but updating the style would mean the window size would change
|
||||
// causing the window to lose its Maximized state which would mean the window size
|
||||
|
|
|
|||
|
|
@ -1014,9 +1014,8 @@ double GetTime(void)
|
|||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if the provided URL is safe
|
||||
// A user could craft a malicious string performing another action
|
||||
// Avoid calling this function with user input non-validated strings
|
||||
// WARNING: This function is only safe to use if you control the URL given,
|
||||
// a user could craft a malicious string to perform and undesired action
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "OpenURL() not implemented on target platform");
|
||||
|
|
@ -1043,7 +1042,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
|
|||
void SetMousePosition(int x, int y)
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
}
|
||||
|
||||
// Set mouse cursor
|
||||
|
|
@ -1446,7 +1444,9 @@ int InitPlatform(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (!eglChooseConfig(platform.device, NULL, NULL, 0, &numConfigs))
|
||||
// WARNING: Providing framebufferAttribs is not logically necessary,
|
||||
// but it may prevent segfaults on some nvidia drivers
|
||||
if (!eglChooseConfig(platform.device, framebufferAttribs, NULL, 0, &numConfigs))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config count: 0x%x", eglGetError());
|
||||
return -1;
|
||||
|
|
@ -2732,4 +2732,4 @@ static void SetupFramebuffer(int width, int height)
|
|||
}
|
||||
}
|
||||
|
||||
// EOF
|
||||
// EOF
|
||||
|
|
|
|||
|
|
@ -420,7 +420,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
|
|||
void SetMousePosition(int x, int y)
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
}
|
||||
|
||||
// Set mouse cursor
|
||||
|
|
|
|||
|
|
@ -352,14 +352,22 @@ double GetTime(void)
|
|||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if you control the URL given.
|
||||
// A user could craft a malicious string performing another action.
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself.
|
||||
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||
// WARNING: This function is only safe to use if you control the URL given,
|
||||
// a user could craft a malicious string to perform and undesired action
|
||||
// NOTE: Some safety checks have been added to mitigate security issues
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
// Security check to (partially) avoid malicious code on target platform
|
||||
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
|
||||
// Security check to (partially) avoid malicious code
|
||||
if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL))
|
||||
{
|
||||
// Filter characters: ' and "
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters");
|
||||
}
|
||||
else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0))
|
||||
{
|
||||
// Only allow URL starting with "http://" or "https://" protocols
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols");
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Load url using default browser
|
||||
|
|
@ -387,7 +395,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
|
|||
void SetMousePosition(int x, int y)
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
}
|
||||
|
||||
// Set mouse cursor
|
||||
|
|
|
|||
|
|
@ -1047,7 +1047,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
|
|||
void SetMousePosition(int x, int y)
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
|
||||
if (CORE.Input.Mouse.cursorLocked) CORE.Input.Mouse.lockedPosition = CORE.Input.Mouse.currentPosition;
|
||||
|
||||
|
|
@ -1579,7 +1578,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
|
|||
for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++)
|
||||
{
|
||||
CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
|
||||
strncpy(CORE.Window.dropFilepaths[i], paths[i], MAX_FILEPATH_LENGTH - 1);
|
||||
snprintf(CORE.Window.dropFilepaths[i], MAX_FILEPATH_LENGTH, "%s", paths[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -968,13 +968,22 @@ double GetTime(void)
|
|||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if the provided URL is safe
|
||||
// A user could craft a malicious string performing another action
|
||||
// Avoid calling this function with user input non-validated strings
|
||||
// WARNING: This function is only safe to use if you control the URL given,
|
||||
// a user could craft a malicious string to perform and undesired action
|
||||
// NOTE: Some safety checks have been added to mitigate security issues
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
// Security check to (partially) avoid malicious code on target platform
|
||||
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
|
||||
// Security check to (partially) avoid malicious code
|
||||
if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL))
|
||||
{
|
||||
// Filter characters: ' and "
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters");
|
||||
}
|
||||
else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0))
|
||||
{
|
||||
// Only allow URL starting with "http://" or "https://" protocols
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols");
|
||||
}
|
||||
else emscripten_run_script(TextFormat("window.open('%s', '_blank')", url));
|
||||
}
|
||||
|
||||
|
|
@ -1439,7 +1448,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
|
|||
for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++)
|
||||
{
|
||||
CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
|
||||
strncpy(CORE.Window.dropFilepaths[i], paths[i], MAX_FILEPATH_LENGTH - 1);
|
||||
snprintf(CORE.Window.dropFilepaths[i], MAX_FILEPATH_LENGTH, "%s", paths[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1498,8 +1507,16 @@ static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent
|
|||
{
|
||||
switch (eventType)
|
||||
{
|
||||
case EMSCRIPTEN_EVENT_MOUSEENTER: CORE.Input.Mouse.cursorOnScreen = true; break;
|
||||
case EMSCRIPTEN_EVENT_MOUSELEAVE: CORE.Input.Mouse.cursorOnScreen = false; break;
|
||||
case EMSCRIPTEN_EVENT_MOUSEENTER: {
|
||||
// NOTE: Mouse position updated by EmscriptenMouseMoveCallback(),
|
||||
// EmscriptenPointerlockCallback(), and EmscriptenTouchCallback()
|
||||
CORE.Input.Mouse.cursorOnScreen = true;
|
||||
} break;
|
||||
case EMSCRIPTEN_EVENT_MOUSELEAVE:
|
||||
{
|
||||
CORE.Input.Mouse.cursorOnScreen = false;
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ 0 };
|
||||
} break;
|
||||
case EMSCRIPTEN_EVENT_MOUSEDOWN:
|
||||
{
|
||||
// NOTE: Emscripten and raylib buttons indices are not aligned
|
||||
|
|
|
|||
12
src/raudio.c
12
src/raudio.c
|
|
@ -822,7 +822,7 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
|
|||
wave.sampleRate = wav.sampleRate;
|
||||
wave.sampleSize = 16;
|
||||
wave.channels = wav.channels;
|
||||
wave.data = (short *)RL_MALLOC((size_t)wave.frameCount*wave.channels*sizeof(short));
|
||||
wave.data = (short *)RL_CALLOC((size_t)wave.frameCount*wave.channels, sizeof(short));
|
||||
|
||||
// NOTE: Forcing conversion to 16bit sample size on reading
|
||||
drwav_read_pcm_frames_s16(&wav, wave.frameCount, (drwav_int16 *)wave.data);
|
||||
|
|
@ -845,7 +845,7 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
|
|||
wave.sampleSize = 16; // By default, ogg data is 16 bit per sample (short)
|
||||
wave.channels = info.channels;
|
||||
wave.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples(oggData); // NOTE: It returns frames!
|
||||
wave.data = (short *)RL_MALLOC(wave.frameCount*wave.channels*sizeof(short));
|
||||
wave.data = (short *)RL_CALLOC(wave.frameCount*wave.channels, sizeof(short));
|
||||
|
||||
// NOTE: Get the number of samples to process (be careful! asking for number of shorts, not bytes!)
|
||||
stb_vorbis_get_samples_short_interleaved(oggData, info.channels, (short *)wave.data, wave.frameCount*wave.channels);
|
||||
|
|
@ -1154,7 +1154,7 @@ bool ExportWaveAsCode(Wave wave, const char *fileName)
|
|||
|
||||
// Get file name from path and convert variable name to uppercase
|
||||
char varFileName[256] = { 0 };
|
||||
strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1);
|
||||
snprintf(varFileName, 256, "%s", GetFileNameWithoutExt(fileName)); // NOTE: Using function provided by [rcore] module
|
||||
for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; }
|
||||
|
||||
// Add wave information
|
||||
|
|
@ -1258,7 +1258,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
|
|||
return;
|
||||
}
|
||||
|
||||
void *data = RL_MALLOC(frameCount*channels*(sampleSize/8));
|
||||
void *data = RL_CALLOC(frameCount*channels*(sampleSize/8), 1);
|
||||
|
||||
frameCount = (ma_uint32)ma_convert_frames(data, frameCount, formatOut, channels, sampleRate, wave->data, frameCountIn, formatIn, wave->channels, wave->sampleRate);
|
||||
if (frameCount == 0)
|
||||
|
|
@ -1772,7 +1772,7 @@ void UnloadMusicStream(Music music)
|
|||
{
|
||||
if (false) { }
|
||||
#if SUPPORT_FILEFORMAT_WAV
|
||||
else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData);
|
||||
else if (music.ctxType == MUSIC_AUDIO_WAV) { drwav_uninit((drwav *)music.ctxData); RL_FREE(music.ctxData); }
|
||||
#endif
|
||||
#if SUPPORT_FILEFORMAT_OGG
|
||||
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
|
||||
|
|
@ -2827,7 +2827,7 @@ static const char *GetFileNameWithoutExt(const char *filePath)
|
|||
static char fileName[MAX_FILENAMEWITHOUTEXT_LENGTH] = { 0 };
|
||||
memset(fileName, 0, MAX_FILENAMEWITHOUTEXT_LENGTH);
|
||||
|
||||
if (filePath != NULL) strncpy(fileName, GetFileName(filePath), MAX_FILENAMEWITHOUTEXT_LENGTH - 1); // Get filename with extension
|
||||
if (filePath != NULL) snprintf(fileName, MAX_FILENAMEWITHOUTEXT_LENGTH, "%s", GetFileName(filePath));
|
||||
|
||||
int fileNameLength = (int)strlen(fileName); // Get size in bytes
|
||||
|
||||
|
|
|
|||
22
src/raylib.h
22
src/raylib.h
|
|
@ -409,7 +409,7 @@ typedef struct BoneInfo {
|
|||
|
||||
// Skeleton, animation bones hierarchy
|
||||
typedef struct ModelSkeleton {
|
||||
int boneCount; // Number of bones
|
||||
unsigned int boneCount; // Number of bones
|
||||
BoneInfo *bones; // Bones information (skeleton)
|
||||
ModelAnimPose bindPose; // Bones base transformation (Transform[])
|
||||
} ModelSkeleton;
|
||||
|
|
@ -436,7 +436,7 @@ typedef struct Model {
|
|||
typedef struct ModelAnimation {
|
||||
char name[32]; // Animation name
|
||||
|
||||
int boneCount; // Number of bones (per pose)
|
||||
unsigned int boneCount; // Number of bones (per pose)
|
||||
int keyframeCount; // Number of animation key frames
|
||||
ModelAnimPose *keyframePoses; // Animation sequence keyframe poses [keyframe][pose]
|
||||
} ModelAnimation;
|
||||
|
|
@ -1154,13 +1154,15 @@ RLAPI long GetFileModTime(const char *fileName); // Get file
|
|||
RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png')
|
||||
RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string
|
||||
RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string)
|
||||
RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string)
|
||||
RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string)
|
||||
RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a provided fileName with path (uses static string)
|
||||
RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a provided path (uses static string)
|
||||
RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string)
|
||||
RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string)
|
||||
RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success
|
||||
RLAPI int ChangeDirectory(const char *dirPath); // Change working directory, returns 0 on success
|
||||
RLAPI bool IsPathFile(const char *path); // Check if given path is a file or a directory
|
||||
RLAPI bool IsPathFile(const char *path); // Check if provided path points to a file
|
||||
RLAPI bool IsPathDirectory(const char *path); // Check if provided path points to a directory
|
||||
RLAPI bool IsPathAbsolute(const char *path); // Check if provided path is an absolute path
|
||||
RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS
|
||||
RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths, files and directories, no subdirs scan
|
||||
RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*'
|
||||
|
|
@ -1239,7 +1241,7 @@ RLAPI void SetMouseCursor(int cursor); // Set mouse curso
|
|||
RLAPI int GetTouchX(void); // Get touch position X for touch point 0 (relative to screen size)
|
||||
RLAPI int GetTouchY(void); // Get touch position Y for touch point 0 (relative to screen size)
|
||||
RLAPI Vector2 GetTouchPosition(int index); // Get touch position XY for a touch point index (relative to screen size)
|
||||
RLAPI int GetTouchPointId(int index); // Get touch point identifier for given index
|
||||
RLAPI int GetTouchPointId(int index); // Get touch point identifier for provided index
|
||||
RLAPI int GetTouchPointCount(void); // Get number of touch points
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
|
|
@ -1326,7 +1328,7 @@ RLAPI void DrawSplineSegmentCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vecto
|
|||
RLAPI void DrawSplineSegmentBezierQuadratic(Vector2 p1, Vector2 c2, Vector2 p3, float thick, Color color); // Draw spline segment: Quadratic Bezier, 2 points, 1 control point
|
||||
RLAPI void DrawSplineSegmentBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float thick, Color color); // Draw spline segment: Cubic Bezier, 2 points, 2 control points
|
||||
|
||||
// Spline segment point evaluation functions, for a given t [0.0f .. 1.0f]
|
||||
// Spline segment point evaluation functions, for a provided t [0.0f .. 1.0f]
|
||||
RLAPI Vector2 GetSplinePointLinear(Vector2 startPos, Vector2 endPos, float t); // Get (evaluate) spline point: Linear
|
||||
RLAPI Vector2 GetSplinePointBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t); // Get (evaluate) spline point: B-Spline
|
||||
RLAPI Vector2 GetSplinePointCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t); // Get (evaluate) spline point: Catmull-Rom
|
||||
|
|
@ -1416,7 +1418,7 @@ RLAPI Color GetImageColor(Image image, int x, int y);
|
|||
|
||||
// Image drawing functions
|
||||
// NOTE: Image software-rendering functions (CPU)
|
||||
RLAPI void ImageClearBackground(Image *dst, Color color); // Clear image background with given color
|
||||
RLAPI void ImageClearBackground(Image *dst, Color color); // Clear image background with provided color
|
||||
RLAPI void ImageDrawPixel(Image *dst, int posX, int posY, Color color); // Draw pixel within an image
|
||||
RLAPI void ImageDrawPixelV(Image *dst, Vector2 position, Color color); // Draw pixel within an image (Vector version)
|
||||
RLAPI void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw line within an image
|
||||
|
|
@ -1431,8 +1433,10 @@ RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCo
|
|||
RLAPI void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color); // Draw rectangle within an image
|
||||
RLAPI void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color); // Draw rectangle within an image (Vector version)
|
||||
RLAPI void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color); // Draw rectangle within an image
|
||||
RLAPI void ImageDrawRectanglePro(Image *dst, Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters within and image
|
||||
RLAPI void ImageDrawRectangleLines(Image *dst, int posX, int posY, int width, int height, Color color); // Draw rectangle lines within an image
|
||||
RLAPI void ImageDrawRectangleLinesEx(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image with line thickness
|
||||
RLAPI void ImageDrawRectangleGradientEx(Image *dst, Rectangle rec, Color col1, Color col2, Color col3, Color col4); // Draw rectangle with gradient colors within an image, counter-clockwise color order
|
||||
RLAPI void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color); // Draw a filled circle within an image
|
||||
RLAPI void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color); // Draw a filled circle within an image (Vector version)
|
||||
RLAPI void ImageDrawCircleLines(Image *dst, int centerX, int centerY, int radius, Color color); // Draw circle outline within an image
|
||||
|
|
@ -1440,10 +1444,12 @@ RLAPI void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color c
|
|||
RLAPI void ImageDrawCircleGradient(Image *dst, Vector2 center, float radius, Color inner, Color outer); // Draw a gradient-filled circle within an image
|
||||
|
||||
RLAPI void ImageDrawImage(Image *dst, Image src, int posX, int posY, Color tint); // Draw an image within an image
|
||||
RLAPI void ImageDrawImageEx(Image *dst, Image src, Vector2 position, float rotation, float scale, Color tint); // Draw an image with scaling and rotation within an image
|
||||
RLAPI void ImageDrawImageRec(Image *dst, Image src, Rectangle srcRec, Vector2 position, Color tint); // Draw a part of an image defined by a rectangle within an image
|
||||
RLAPI void ImageDrawImagePro(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Vector2 origin, float rotation, Color tint); // Draw a part of an image defined by a rectangle into destination rectangle, with scaling and rotation, within an image
|
||||
RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination)
|
||||
RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination)
|
||||
RLAPI void ImageDrawTextPro(Image *dst, Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint); // Draw text using Font and pro parameters (rotation)
|
||||
|
||||
// Texture loading functions
|
||||
// NOTE: These functions require GPU access
|
||||
|
|
|
|||
113
src/rcore.c
113
src/rcore.c
|
|
@ -108,7 +108,7 @@
|
|||
|
||||
#include <stdlib.h> // Required for: srand(), rand(), exit()
|
||||
#include <stdio.h> // Required for: FILE, fopen(), fseek(), ftell(), fread(), fwrite(), fprintf(), vprintf(), fclose(), sprintf() [Used in OpenURL()]
|
||||
#include <string.h> // Required for: strlen(), strncpy(), strcmp(), strrchr(), memset(), strcat()
|
||||
#include <string.h> // Required for: strlen(), strcmp(), strrchr(), memset(), memcpy(), strcat()
|
||||
#include <stdarg.h> // Required for: va_list, va_start(), va_end() [Used in TraceLog()]
|
||||
|
||||
#ifndef PICO_RP2350
|
||||
|
|
@ -1813,7 +1813,6 @@ void UnloadRandomSequence(int *sequence)
|
|||
}
|
||||
|
||||
// Takes a screenshot of current screen
|
||||
// NOTE: Provided fileName should not contain paths, saving to working directory
|
||||
void TakeScreenshot(const char *fileName)
|
||||
{
|
||||
#if SUPPORT_MODULE_RTEXTURES
|
||||
|
|
@ -1828,7 +1827,8 @@ void TakeScreenshot(const char *fileName)
|
|||
Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
|
||||
|
||||
char path[MAX_FILEPATH_LENGTH] = { 0 };
|
||||
strncpy(path, TextFormat("%s/%s", CORE.Storage.basePath, fileName), MAX_FILEPATH_LENGTH - 1);
|
||||
if (!IsPathAbsolute(fileName)) snprintf(path, MAX_FILEPATH_LENGTH, "%s", TextFormat("%s/%s", CORE.Storage.basePath, fileName));
|
||||
else snprintf(path, MAX_FILEPATH_LENGTH, "%s", fileName);
|
||||
|
||||
ExportImage(image, path); // WARNING: Module required: rtextures
|
||||
RL_FREE(imgData);
|
||||
|
|
@ -1853,8 +1853,6 @@ void SetConfigFlags(unsigned int flags)
|
|||
FLAG_SET(CORE.Window.flags, flags);
|
||||
}
|
||||
|
||||
// void OpenURL(const char *url); // Defined per platform
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition: Logging system
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -1894,12 +1892,12 @@ void TraceLog(int logType, const char *text, ...)
|
|||
|
||||
switch (logType)
|
||||
{
|
||||
case LOG_TRACE: strncpy(buffer, "TRACE: ", 8); break;
|
||||
case LOG_DEBUG: strncpy(buffer, "DEBUG: ", 8); break;
|
||||
case LOG_INFO: strncpy(buffer, "INFO: ", 7); break;
|
||||
case LOG_WARNING: strncpy(buffer, "WARNING: ", 10); break;
|
||||
case LOG_ERROR: strncpy(buffer, "ERROR: ", 8); break;
|
||||
case LOG_FATAL: strncpy(buffer, "FATAL: ", 8); break;
|
||||
case LOG_TRACE: memcpy(buffer, "TRACE: ", 7); break;
|
||||
case LOG_DEBUG: memcpy(buffer, "DEBUG: ", 7); break;
|
||||
case LOG_INFO: memcpy(buffer, "INFO: ", 6); break;
|
||||
case LOG_WARNING: memcpy(buffer, "WARNING: ", 9); break;
|
||||
case LOG_ERROR: memcpy(buffer, "ERROR: ", 7); break;
|
||||
case LOG_FATAL: memcpy(buffer, "FATAL: ", 7); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
|
@ -2072,7 +2070,7 @@ bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileN
|
|||
|
||||
// Get file name from path
|
||||
char varFileName[256] = { 0 };
|
||||
strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1);
|
||||
snprintf(varFileName, 256, "%s", GetFileNameWithoutExt(fileName));
|
||||
for (int i = 0; varFileName[i] != '\0'; i++)
|
||||
{
|
||||
// Convert variable name to uppercase
|
||||
|
|
@ -2516,7 +2514,7 @@ const char *GetFileNameWithoutExt(const char *filePath)
|
|||
|
||||
if (filePath != NULL)
|
||||
{
|
||||
strncpy(fileName, GetFileName(filePath), MAX_FILENAME_LENGTH - 1); // Get filename.ext without path
|
||||
snprintf(fileName, MAX_FILENAME_LENGTH, "%s", GetFileName(filePath)); // Get filename.ext without path
|
||||
int fileNameLength = (int)strlen(fileName); // Get size in bytes
|
||||
|
||||
for (int i = fileNameLength; i > 0; i--) // Reverse search '.'
|
||||
|
|
@ -2533,7 +2531,7 @@ const char *GetFileNameWithoutExt(const char *filePath)
|
|||
return fileName;
|
||||
}
|
||||
|
||||
// Get directory for a given filePath
|
||||
// Get directory for a provided filePath
|
||||
const char *GetDirectoryPath(const char *filePath)
|
||||
{
|
||||
/*
|
||||
|
|
@ -2570,7 +2568,6 @@ const char *GetDirectoryPath(const char *filePath)
|
|||
}
|
||||
else
|
||||
{
|
||||
// NOTE: Be careful, strncpy() is not safe, it does not care about '\0'
|
||||
char *dirPathPtr = dirPath;
|
||||
if ((filePath[1] != ':') && (filePath[0] != '\\') && (filePath[0] != '/')) dirPathPtr += 2; // Skip drive letter, "C:"
|
||||
memcpy(dirPathPtr, filePath, strlen(filePath) - (strlen(lastSlash) - 1));
|
||||
|
|
@ -2581,14 +2578,14 @@ const char *GetDirectoryPath(const char *filePath)
|
|||
return dirPath;
|
||||
}
|
||||
|
||||
// Get previous directory path for a given path
|
||||
// Get previous directory path for a provided path
|
||||
const char *GetPrevDirectoryPath(const char *dirPath)
|
||||
{
|
||||
static char prevDirPath[MAX_FILEPATH_LENGTH] = { 0 };
|
||||
memset(prevDirPath, 0, MAX_FILEPATH_LENGTH);
|
||||
int dirPathLength = (int)strlen(dirPath);
|
||||
|
||||
if (dirPathLength <= 3) strncpy(prevDirPath, dirPath, MAX_FILEPATH_LENGTH - 1);
|
||||
if (dirPathLength <= 3) snprintf(prevDirPath, MAX_FILEPATH_LENGTH, "%s", dirPath);
|
||||
|
||||
for (int i = (dirPathLength - 1); (i >= 0) && (dirPathLength > 3); i--)
|
||||
{
|
||||
|
|
@ -2597,7 +2594,7 @@ const char *GetPrevDirectoryPath(const char *dirPath)
|
|||
// Check for root: "C:\" or "/"
|
||||
if (((i == 2) && (dirPath[1] ==':')) || (i == 0)) i++;
|
||||
|
||||
strncpy(prevDirPath, dirPath, i);
|
||||
memcpy(prevDirPath, dirPath, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -2831,13 +2828,49 @@ int ChangeDirectory(const char *dirPath)
|
|||
return result;
|
||||
}
|
||||
|
||||
// Check if given path point to a file
|
||||
// Check if provided path point to a file
|
||||
bool IsPathFile(const char *path)
|
||||
{
|
||||
struct stat result = { 0 };
|
||||
stat(path, &result);
|
||||
bool result = false;
|
||||
|
||||
return S_ISREG(result.st_mode);
|
||||
struct stat info = { 0 };
|
||||
stat(path, &info);
|
||||
|
||||
if (S_ISREG(info.st_mode)) result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check if provided path point to a directory
|
||||
bool IsPathDirectory(const char *path)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (!IsPathFile(path)) result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check if provided path is an absolute path
|
||||
bool IsPathAbsolute(const char *path)
|
||||
{
|
||||
int result = false;
|
||||
|
||||
if ((path != NULL) && (path[0] != '\0'))
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
// UNC path (\\server\share)
|
||||
if ((path[0] == '\\') && (path[1] == '\\')) result = true;
|
||||
// Drive letter (e.g. C:\ or D:/)
|
||||
else if (isalpha((unsigned char)path[0]) && (path[1] == ':') &&
|
||||
((path[2] == '\\') || (path[2] == '/'))) result = true;
|
||||
#else
|
||||
// POSIX: must start with /
|
||||
if (path[0] == '/') result = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check if fileName is valid for the platform/OS
|
||||
|
|
@ -3271,7 +3304,7 @@ unsigned int *ComputeMD5(const unsigned char *data, int dataSize)
|
|||
memcpy(msg + newDataSize, &bitsLen, 4); // Append the len in bits at the end of the buffer
|
||||
|
||||
// Process the message in successive 512-bit chunks for each 512-bit chunk of message
|
||||
for (int offset = 0; offset < newDataSize; offset += (512/8))
|
||||
for (int offset = 0; offset < newDataSize; offset += 64) // 512/8
|
||||
{
|
||||
// Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15
|
||||
unsigned int *w = (unsigned int *)(msg + offset);
|
||||
|
|
@ -3368,16 +3401,16 @@ unsigned int *ComputeSHA1(const unsigned char *data, int dataSize)
|
|||
msg[newDataSize - 8] = (unsigned char)(bitsLen >> 56);
|
||||
|
||||
// Process the message in successive 512-bit chunks
|
||||
for (int offset = 0; offset < newDataSize; offset += (512/8))
|
||||
for (int offset = 0; offset < newDataSize; offset += 64) // 512/8
|
||||
{
|
||||
// Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15
|
||||
unsigned int w[80] = { 0 };
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
w[i] = (msg[offset + (i*4) + 0] << 24) |
|
||||
(msg[offset + (i*4) + 1] << 16) |
|
||||
(msg[offset + (i*4) + 2] << 8) |
|
||||
(msg[offset + (i*4) + 3]);
|
||||
w[i] = ((unsigned int)msg[offset + (i*4) + 0] << 24) |
|
||||
((unsigned int)msg[offset + (i*4) + 1] << 16) |
|
||||
((unsigned int)msg[offset + (i*4) + 2] << 8) |
|
||||
((unsigned int)msg[offset + (i*4) + 3]);
|
||||
}
|
||||
|
||||
// Message schedule: extend the sixteen 32-bit words into eighty 32-bit words:
|
||||
|
|
@ -3599,10 +3632,14 @@ AutomationEventList LoadAutomationEventList(const char *fileName)
|
|||
case 'c': sscanf(buffer, "c %i", &list.count); break;
|
||||
case 'e':
|
||||
{
|
||||
sscanf(buffer, "e %d %d %d %d %d %d %[^\n]s", &list.events[counter].frame, &list.events[counter].type,
|
||||
&list.events[counter].params[0], &list.events[counter].params[1], &list.events[counter].params[2], &list.events[counter].params[3], eventDesc);
|
||||
if (counter < list.capacity)
|
||||
{
|
||||
sscanf(buffer, "e %d %d %d %d %d %d %63[^\n]s", &list.events[counter].frame, &list.events[counter].type,
|
||||
&list.events[counter].params[0], &list.events[counter].params[1], &list.events[counter].params[2], &list.events[counter].params[3], eventDesc);
|
||||
|
||||
counter++;
|
||||
counter++;
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "AUTOMATION: Event goes beyond automated list capacity (MAX: %u): %s", list.capacity, buffer);
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
|
|
@ -3935,7 +3972,7 @@ bool IsGamepadAvailable(int gamepad)
|
|||
{
|
||||
bool result = false;
|
||||
|
||||
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad]) result = true;
|
||||
if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad]) result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -3955,7 +3992,7 @@ bool IsGamepadButtonPressed(int gamepad, int button)
|
|||
{
|
||||
bool pressed = false;
|
||||
|
||||
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
|
||||
if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
|
||||
{
|
||||
if ((CORE.Input.Gamepad.previousButtonState[gamepad][button] == 0) && (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 1)) pressed = true;
|
||||
}
|
||||
|
|
@ -3968,7 +4005,7 @@ bool IsGamepadButtonDown(int gamepad, int button)
|
|||
{
|
||||
bool down = false;
|
||||
|
||||
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
|
||||
if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
|
||||
{
|
||||
if (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 1) down = true;
|
||||
}
|
||||
|
|
@ -3981,7 +4018,7 @@ bool IsGamepadButtonReleased(int gamepad, int button)
|
|||
{
|
||||
bool released = false;
|
||||
|
||||
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
|
||||
if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
|
||||
{
|
||||
if ((CORE.Input.Gamepad.previousButtonState[gamepad][button] == 1) && (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 0)) released = true;
|
||||
}
|
||||
|
|
@ -3994,7 +4031,7 @@ bool IsGamepadButtonUp(int gamepad, int button)
|
|||
{
|
||||
bool up = false;
|
||||
|
||||
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
|
||||
if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
|
||||
{
|
||||
if (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 0) up = true;
|
||||
}
|
||||
|
|
@ -4024,7 +4061,7 @@ float GetGamepadAxisMovement(int gamepad, int axis)
|
|||
{
|
||||
float value = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f;
|
||||
|
||||
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXES))
|
||||
if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXES))
|
||||
{
|
||||
float movement = (value < 0.0f)? CORE.Input.Gamepad.axisState[gamepad][axis] : fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]);
|
||||
|
||||
|
|
@ -4208,7 +4245,7 @@ Vector2 GetTouchPosition(int index)
|
|||
return position;
|
||||
}
|
||||
|
||||
// Get touch point identifier for given index
|
||||
// Get touch point identifier for provided index
|
||||
int GetTouchPointId(int index)
|
||||
{
|
||||
int id = -1;
|
||||
|
|
|
|||
126
src/rlgl.h
126
src/rlgl.h
|
|
@ -56,8 +56,8 @@
|
|||
* #define RL_CULL_DISTANCE_NEAR 0.05 // Default projection matrix near cull distance
|
||||
* #define RL_CULL_DISTANCE_FAR 4000.0 // Default projection matrix far cull distance
|
||||
*
|
||||
* When loading a shader, the following vertex attributes and uniform
|
||||
* location names are tried to be set automatically:
|
||||
* When loading a shader, the following vertex attributes and uniform location names are tried to be set automatically:
|
||||
* WARNING: Pre-defined names can not be changed, they are used by default shaders and all raylib examples shaders, they are just listed here for reference
|
||||
*
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD
|
||||
|
|
@ -67,6 +67,8 @@
|
|||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM
|
||||
*
|
||||
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
|
||||
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
|
||||
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix
|
||||
|
|
@ -74,6 +76,7 @@
|
|||
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView)))
|
||||
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color)
|
||||
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices
|
||||
*
|
||||
* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0)
|
||||
* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1)
|
||||
* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)
|
||||
|
|
@ -324,6 +327,7 @@
|
|||
#define RL_DRAW_FRAMEBUFFER 0x8CA9 // GL_DRAW_FRAMEBUFFER
|
||||
|
||||
// Default shader vertex attribute locations
|
||||
// NOTE: Locations can be redefined by user if required
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
|
||||
#endif
|
||||
|
|
@ -843,11 +847,11 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
|
|||
#define SW_CALLOC(n,sz) RL_CALLOC(n, sz)
|
||||
#define SW_REALLOC(ptr, newSz) RL_REALLOC(ptr, newSz)
|
||||
#define SW_FREE(ptr) RL_FREE(ptr)
|
||||
#include "external/rlsw.h" // OpenGL 1.1 software implementation
|
||||
#include "external/rlsw.h" // OpenGL 1.1 software implementation
|
||||
#else
|
||||
#if defined(__APPLE__)
|
||||
#include <OpenGL/gl.h> // OpenGL 1.1 library for OSX
|
||||
#include <OpenGL/glext.h> // OpenGL extensions library
|
||||
#include <OpenGL/gl.h> // OpenGL 1.1 library for OSX
|
||||
#include <OpenGL/glext.h> // OpenGL extensions library
|
||||
#else
|
||||
// APIENTRY for OpenGL function pointer declarations is required
|
||||
#if !defined(APIENTRY)
|
||||
|
|
@ -862,7 +866,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
|
|||
#define WINGDIAPI __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#include <GL/gl.h> // OpenGL 1.1 library
|
||||
#include <GL/gl.h> // OpenGL 1.1 library
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -903,9 +907,10 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdlib.h> // Required for: calloc(), free()
|
||||
#include <string.h> // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading]
|
||||
#include <math.h> // Required for: sqrtf(), sinf(), cosf(), floor(), log()
|
||||
#include <stdlib.h> // Required for: calloc(), free()
|
||||
#include <string.h> // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading]
|
||||
#include <math.h> // Required for: sqrtf(), sinf(), cosf(), floor(), log()
|
||||
#include <limits.h> // Required for: INT_MAX
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
|
|
@ -993,65 +998,28 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
|
|||
#endif
|
||||
|
||||
// Default shader vertex attribute names to set location points
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS
|
||||
#endif
|
||||
// WARNING: Pre-defined names can not be changed, they are used by default shaders and all raylib examples shaders, they are just listed here for reference
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM
|
||||
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM
|
||||
#endif
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color)
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices (required for GPU skinning)
|
||||
|
||||
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MVP
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color)
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0
|
||||
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0)
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1
|
||||
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1)
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2
|
||||
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices (required for GPU skinning)
|
||||
#endif
|
||||
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0)
|
||||
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1)
|
||||
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Types and Structures Definition
|
||||
|
|
@ -2502,7 +2470,7 @@ void rlLoadExtensions(void *loader)
|
|||
// NOTE: String duplication rquired because glGetString() returns a const string
|
||||
int extensionsLength = (int)strlen(extensions); // Get extensions string size in bytes
|
||||
char *extensionsDup = (char *)RL_CALLOC(extensionsLength + 1, sizeof(char)); // Allocate space for copy with additional EOL byte
|
||||
strncpy(extensionsDup, extensions, extensionsLength);
|
||||
snprintf(extensionsDup, extensionsLength, "%s", extensions);
|
||||
extList[numExt] = extensionsDup;
|
||||
|
||||
for (int i = 0; i < extensionsLength; i++)
|
||||
|
|
@ -3022,7 +2990,7 @@ void rlDrawRenderBatch(rlRenderBatch *batch)
|
|||
|
||||
// NOTE: glMapBuffer() causes sync issue
|
||||
// If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job
|
||||
// To avoid waiting (idle), glBufferData() can bee called first with NULL pointer before glMapBuffer()
|
||||
// To avoid waiting (idle), glBufferData() can be called first with NULL pointer before glMapBuffer()
|
||||
// Doing that, the previous data in PBO will be discarded and glMapBuffer() returns a new
|
||||
// allocated pointer immediately even if GPU is still working with the previous data
|
||||
|
||||
|
|
@ -3825,6 +3793,10 @@ unsigned char *rlReadScreenPixels(int width, int height)
|
|||
{
|
||||
unsigned char *imgData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char));
|
||||
|
||||
// NOTE: Buffer retrieved is GL_FRONT in single-buffered configurations
|
||||
// and GL_BACK in double-buffered configurations, make sure to call it at the end of frame
|
||||
//glReadBuffer(GL_BACK);
|
||||
|
||||
// NOTE: glReadPixels() returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer
|
||||
// WARNING: Getting alpha channel! Be careful, it can be transparent if not cleared properly!
|
||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, imgData);
|
||||
|
|
@ -5269,7 +5241,9 @@ static int rlGetPixelDataSize(int width, int height, int format)
|
|||
{
|
||||
int blockWidth = (width + 3)/4;
|
||||
int blockHeight = (height + 3)/4;
|
||||
dataSize = blockWidth*blockHeight*8;
|
||||
unsigned long long dataSizeBytes = (unsigned long long)blockWidth*blockHeight*8;
|
||||
if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes;
|
||||
|
||||
} break;
|
||||
case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA:
|
||||
case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA:
|
||||
|
|
@ -5278,13 +5252,17 @@ static int rlGetPixelDataSize(int width, int height, int format)
|
|||
{
|
||||
int blockWidth = (width + 3)/4;
|
||||
int blockHeight = (height + 3)/4;
|
||||
dataSize = blockWidth*blockHeight*16;
|
||||
unsigned long long dataSizeBytes = (unsigned long long)blockWidth*blockHeight*16;
|
||||
if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes;
|
||||
|
||||
} break;
|
||||
case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: // 4 bytes per each 4x4 block
|
||||
{
|
||||
int blockWidth = (width + 3)/4;
|
||||
int blockHeight = (height + 3)/4;
|
||||
dataSize = blockWidth*blockHeight*4;
|
||||
unsigned long long dataSizeBytes = (unsigned long long)blockWidth*blockHeight*4;
|
||||
if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes;
|
||||
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
|
|
@ -5293,9 +5271,11 @@ static int rlGetPixelDataSize(int width, int height, int format)
|
|||
if ((format >= RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) &&
|
||||
(format <= RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16))
|
||||
{
|
||||
double bytesPerPixel = (double)bpp/8.0;
|
||||
dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes
|
||||
unsigned long long dataSizeBytes = ((unsigned long long)width*height*bpp) >> 3; // Get size in bytes (dividing by 8)
|
||||
if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes;
|
||||
}
|
||||
|
||||
if (dataSize == 0) TRACELOG(LOG_WARNING, "Requested image size is larger than 2GB, it can not be allocated");
|
||||
|
||||
return dataSize;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,9 +50,9 @@
|
|||
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
|
||||
#include "raymath.h" // Required for: Vector3, Quaternion and Matrix functionality
|
||||
|
||||
#include <stdio.h> // Required for: sprintf()
|
||||
#include <stdio.h> // Required for: sprintf(), snprintf()
|
||||
#include <stdlib.h> // Required for: malloc(), calloc(), free()
|
||||
#include <string.h> // Required for: memcmp(), strlen(), strncpy()
|
||||
#include <string.h> // Required for: strlen(), memcmp()
|
||||
#include <math.h> // Required for: sinf(), cosf(), sqrtf(), fabsf()
|
||||
|
||||
#if SUPPORT_FILEFORMAT_OBJ || SUPPORT_FILEFORMAT_MTL
|
||||
|
|
@ -2073,7 +2073,7 @@ bool ExportMeshAsCode(Mesh mesh, const char *fileName)
|
|||
|
||||
// Get file name from path and convert variable name to uppercase
|
||||
char varFileName[256] = { 0 };
|
||||
strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); // NOTE: Using function provided by [rcore] module
|
||||
snprintf(varFileName, 256, "%s", GetFileNameWithoutExt(fileName)); // NOTE: Using function provided by [rcore] module
|
||||
for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
|
||||
|
||||
// Add image information
|
||||
|
|
@ -2320,7 +2320,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, float frame)
|
|||
Matrix currentPoseMatrix = { 0 };
|
||||
|
||||
// Update all bones and bone matrices of model
|
||||
for (int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++)
|
||||
for (unsigned int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++)
|
||||
{
|
||||
// Compute interpolated pose between current and next frame
|
||||
// NOTE: Storing animation frame data in model.currentPose
|
||||
|
|
@ -2390,7 +2390,7 @@ void UpdateModelAnimationEx(Model model, ModelAnimation animA, float frameA, Mod
|
|||
Matrix bindPoseMatrix = { 0 };
|
||||
Matrix currentPoseMatrix = { 0 };
|
||||
|
||||
for (int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++)
|
||||
for (unsigned int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++)
|
||||
{
|
||||
// Get frame-interpolation for first animation
|
||||
Vector3 frameATranslation = Vector3Lerp(
|
||||
|
|
@ -4421,7 +4421,7 @@ static Model LoadOBJ(const char *fileName)
|
|||
}
|
||||
|
||||
char currentDir[MAX_FILEPATH_LENGTH] = { 0 };
|
||||
strncpy(currentDir, GetWorkingDirectory(), MAX_FILEPATH_LENGTH - 1); // Save current working directory
|
||||
snprintf(currentDir, MAX_FILEPATH_LENGTH, "%s", GetWorkingDirectory()); // Save current working directory
|
||||
const char *workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness
|
||||
if (CHDIR(workingDir) != 0) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir);
|
||||
|
||||
|
|
@ -5013,7 +5013,7 @@ static Model LoadIQM(const char *fileName)
|
|||
// Initialize runtime animation data: current pose and bone matrices
|
||||
model.currentPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform));
|
||||
model.boneMatrices = (Matrix *)RL_CALLOC(model.skeleton.boneCount, sizeof(Matrix));
|
||||
for (int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
|
||||
for (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
|
||||
|
||||
UnloadFileData(fileData);
|
||||
|
||||
|
|
@ -5241,7 +5241,7 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou
|
|||
// Build frameposes
|
||||
for (unsigned int frame = 0; frame < anim[a].num_frames; frame++)
|
||||
{
|
||||
for (int i = 0; i < animations[a].boneCount; i++)
|
||||
for (unsigned int i = 0; i < animations[a].boneCount; i++)
|
||||
{
|
||||
if (bones[i].parent >= 0)
|
||||
{
|
||||
|
|
@ -5316,8 +5316,8 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
|
|||
{
|
||||
int base64Size = (int)strlen(cgltfImage->uri + i + 1);
|
||||
while (cgltfImage->uri[i + base64Size] == '=') base64Size--; // Ignore optional paddings
|
||||
int numberOfEncodedBits = base64Size*6 - (base64Size*6) % 8 ; // Encoded bits minus extra bits, so it becomes a multiple of 8 bits
|
||||
int outSize = numberOfEncodedBits/8 ; // Actual encoded bytes
|
||||
int numberOfEncodedBits = base64Size*6 - (base64Size*6)%8; // Encoded bits minus extra bits, so it becomes a multiple of 8 bits
|
||||
int outSize = numberOfEncodedBits >> 3; // Actual encoded bytes
|
||||
void *data = NULL;
|
||||
|
||||
cgltf_options options = { 0 };
|
||||
|
|
@ -5369,15 +5369,15 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
|
|||
}
|
||||
|
||||
// Load bone info from GLTF skin data
|
||||
static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount)
|
||||
static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, unsigned int *boneCount)
|
||||
{
|
||||
*boneCount = (int)skin.joints_count;
|
||||
*boneCount = (unsigned int)skin.joints_count;
|
||||
BoneInfo *bones = (BoneInfo *)RL_CALLOC(skin.joints_count, sizeof(BoneInfo));
|
||||
|
||||
for (unsigned int i = 0; i < skin.joints_count; i++)
|
||||
{
|
||||
cgltf_node node = *skin.joints[i];
|
||||
if (node.name != NULL) strncpy(bones[i].name, node.name, sizeof(bones[i].name) - 1);
|
||||
if (node.name != NULL) snprintf(bones[i].name, sizeof(bones[i].name), "%s", node.name);
|
||||
|
||||
// Find parent bone index by walking up the node tree past any
|
||||
// non-joint ancestors (intermediate transform nodes used by some
|
||||
|
|
@ -6144,7 +6144,7 @@ static Model LoadGLTF(const char *fileName)
|
|||
model.skeleton.bones = LoadBoneInfoGLTF(skin, &model.skeleton.boneCount);
|
||||
model.skeleton.bindPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform));
|
||||
|
||||
for (int i = 0; i < model.skeleton.boneCount; i++)
|
||||
for (unsigned int i = 0; i < model.skeleton.boneCount; i++)
|
||||
{
|
||||
Matrix bindMatrix = { 0 };
|
||||
cgltf_float inverseBindTransform[16] = { 0 };
|
||||
|
|
@ -6309,7 +6309,7 @@ static Model LoadGLTF(const char *fileName)
|
|||
if ((data->skins_count > 0) && !hasJoints && (node->parent != NULL) && (node->parent->mesh == NULL))
|
||||
{
|
||||
int parentBoneId = -1;
|
||||
for (int joint = 0; joint < model.skeleton.boneCount; joint++)
|
||||
for (unsigned int joint = 0; joint < model.skeleton.boneCount; joint++)
|
||||
{
|
||||
if (data->skins[0].joints[joint] == node->parent)
|
||||
{
|
||||
|
|
@ -6347,7 +6347,7 @@ static Model LoadGLTF(const char *fileName)
|
|||
// Initialize runtime animation data: current pose and bone matrices
|
||||
model.currentPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform));
|
||||
model.boneMatrices = (Matrix *)RL_CALLOC(model.skeleton.boneCount, sizeof(Matrix));
|
||||
for (int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
|
||||
for (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
||||
// Free unused allocated memory in case of no bones defined
|
||||
|
|
@ -6660,7 +6660,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
|
|||
animDuration = (time > animDuration)? time : animDuration;
|
||||
}
|
||||
|
||||
if (animData.name != NULL) strncpy(animations[a].name, animData.name, sizeof(animations[a].name) - 1);
|
||||
if (animData.name != NULL) snprintf(animations[a].name, sizeof(animations[a].name), "%s", animData.name);
|
||||
|
||||
animations[a].keyframeCount = (int)(animDuration*GLTF_FRAMERATE) + 1;
|
||||
animations[a].keyframePoses = (Transform **)RL_CALLOC(animations[a].keyframeCount, sizeof(Transform *));
|
||||
|
|
@ -6670,7 +6670,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
|
|||
animations[a].keyframePoses[j] = (Transform *)RL_CALLOC(animations[a].boneCount, sizeof(Transform));
|
||||
float time = (float)j / GLTF_FRAMERATE;
|
||||
|
||||
for (int k = 0; k < animations[a].boneCount; k++)
|
||||
for (unsigned int k = 0; k < animations[a].boneCount; k++)
|
||||
{
|
||||
Vector3 translation = {skin.joints[k]->translation[0], skin.joints[k]->translation[1], skin.joints[k]->translation[2]};
|
||||
Quaternion rotation = {skin.joints[k]->rotation[0], skin.joints[k]->rotation[1], skin.joints[k]->rotation[2], skin.joints[k]->rotation[3]};
|
||||
|
|
@ -7150,7 +7150,7 @@ static Model LoadM3D(const char *fileName)
|
|||
for (i = 0; i < (int)m3d->numbone; i++)
|
||||
{
|
||||
model.skeleton.bones[i].parent = m3d->bone[i].parent;
|
||||
strncpy(model.skeleton.bones[i].name, m3d->bone[i].name, sizeof(model.skeleton.bones[i].name) - 1);
|
||||
snprintf(model.skeleton.bones[i].name, sizeof(model.skeleton.bones[i].name), "%s", m3d->bone[i].name);
|
||||
model.skeleton.bindPose[i].translation.x = m3d->vertex[m3d->bone[i].pos].x*m3d->scale;
|
||||
model.skeleton.bindPose[i].translation.y = m3d->vertex[m3d->bone[i].pos].y*m3d->scale;
|
||||
model.skeleton.bindPose[i].translation.z = m3d->vertex[m3d->bone[i].pos].z*m3d->scale;
|
||||
|
|
@ -7204,7 +7204,7 @@ static Model LoadM3D(const char *fileName)
|
|||
// Initialize runtime animation data: current pose and bone matrices
|
||||
model.currentPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform));
|
||||
model.boneMatrices = (Matrix *)RL_CALLOC(model.skeleton.boneCount, sizeof(Matrix));
|
||||
for (int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
|
||||
for (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
|
||||
}
|
||||
|
||||
m3d_free(m3d);
|
||||
|
|
@ -7258,14 +7258,14 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCou
|
|||
|
||||
animations[a].keyframeCount = m3d->action[a].durationmsec/M3D_ANIMDELAY;
|
||||
animations[a].keyframePoses = (Transform **)RL_CALLOC(animations[a].keyframeCount, sizeof(Transform *));
|
||||
strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name) - 1);
|
||||
snprintf(animations[a].name, sizeof(animations[a].name), "%s", m3d->action[a].name);
|
||||
|
||||
TRACELOG(LOG_INFO, "MODEL: [%s] Loaded animation: %s | Frames: %d | Duration: %fs", fileName, animations[a].name, animations[a].keyframeCount, m3d->action[a].durationmsec);
|
||||
|
||||
for (i = 0; i < (int)m3d->numbone; i++)
|
||||
{
|
||||
bones[i].parent = m3d->bone[i].parent;
|
||||
strncpy(bones[i].name, m3d->bone[i].name, sizeof(bones[i].name) - 1);
|
||||
snprintf(bones[i].name, sizeof(bones[i].name), "%s", m3d->bone[i].name);
|
||||
}
|
||||
|
||||
// A special, never transformed "no bone" bone, used for boneless vertices
|
||||
|
|
|
|||
300
src/rshapes.c
300
src/rshapes.c
|
|
@ -888,14 +888,13 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
|
|||
// Draw rectangle with rounded edges
|
||||
void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color)
|
||||
{
|
||||
// NOTE: For line thicknes <=1.0f using RL_LINES, otherwise using RL_QUADS/RL_TRIANGLES
|
||||
DrawRectangleRoundedLinesEx(rec, roundness, segments, 1.0f, color);
|
||||
}
|
||||
|
||||
// Draw rectangle with rounded edges outline with line thickness
|
||||
void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float thick, Color color)
|
||||
{
|
||||
if (thick < 0) thick = 0;
|
||||
if (thick <= 0) return;
|
||||
|
||||
// Not a rounded rectangle
|
||||
if (roundness <= 0.0f)
|
||||
|
|
@ -966,176 +965,145 @@ void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, f
|
|||
|
||||
const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };
|
||||
|
||||
if (thick > 1)
|
||||
{
|
||||
#if SUPPORT_QUADS_DRAW_MODE
|
||||
rlSetTexture(GetShapesTexture().id);
|
||||
Rectangle shapeRect = GetShapesTextureRectangle();
|
||||
rlSetTexture(GetShapesTexture().id);
|
||||
Rectangle shapeRect = GetShapesTextureRectangle();
|
||||
|
||||
rlBegin(RL_QUADS);
|
||||
rlBegin(RL_QUADS);
|
||||
|
||||
// Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
|
||||
for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
|
||||
{
|
||||
float angle = angles[k];
|
||||
const Vector2 center = centers[k];
|
||||
for (int i = 0; i < segments; i++)
|
||||
{
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
|
||||
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
|
||||
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
|
||||
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
|
||||
|
||||
angle += stepLength;
|
||||
}
|
||||
}
|
||||
|
||||
// Upper rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[0].x, point[0].y);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[8].x, point[8].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[9].x, point[9].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[1].x, point[1].y);
|
||||
|
||||
// Right rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[2].x, point[2].y);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[10].x, point[10].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[11].x, point[11].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[3].x, point[3].y);
|
||||
|
||||
// Lower rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[13].x, point[13].y);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[5].x, point[5].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[4].x, point[4].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[12].x, point[12].y);
|
||||
|
||||
// Left rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[15].x, point[15].y);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[7].x, point[7].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[6].x, point[6].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[14].x, point[14].y);
|
||||
|
||||
rlEnd();
|
||||
rlSetTexture(0);
|
||||
#else
|
||||
rlBegin(RL_TRIANGLES);
|
||||
|
||||
// Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
|
||||
for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
|
||||
{
|
||||
float angle = angles[k];
|
||||
const Vector2 center = centers[k];
|
||||
|
||||
for (int i = 0; i < segments; i++)
|
||||
{
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
|
||||
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
|
||||
|
||||
angle += stepLength;
|
||||
}
|
||||
}
|
||||
|
||||
// Upper rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f(point[0].x, point[0].y);
|
||||
rlVertex2f(point[8].x, point[8].y);
|
||||
rlVertex2f(point[9].x, point[9].y);
|
||||
rlVertex2f(point[1].x, point[1].y);
|
||||
rlVertex2f(point[0].x, point[0].y);
|
||||
rlVertex2f(point[9].x, point[9].y);
|
||||
|
||||
// Right rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f(point[10].x, point[10].y);
|
||||
rlVertex2f(point[11].x, point[11].y);
|
||||
rlVertex2f(point[3].x, point[3].y);
|
||||
rlVertex2f(point[2].x, point[2].y);
|
||||
rlVertex2f(point[10].x, point[10].y);
|
||||
rlVertex2f(point[3].x, point[3].y);
|
||||
|
||||
// Lower rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f(point[13].x, point[13].y);
|
||||
rlVertex2f(point[5].x, point[5].y);
|
||||
rlVertex2f(point[4].x, point[4].y);
|
||||
rlVertex2f(point[12].x, point[12].y);
|
||||
rlVertex2f(point[13].x, point[13].y);
|
||||
rlVertex2f(point[4].x, point[4].y);
|
||||
|
||||
// Left rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f(point[7].x, point[7].y);
|
||||
rlVertex2f(point[6].x, point[6].y);
|
||||
rlVertex2f(point[14].x, point[14].y);
|
||||
rlVertex2f(point[15].x, point[15].y);
|
||||
rlVertex2f(point[7].x, point[7].y);
|
||||
rlVertex2f(point[14].x, point[14].y);
|
||||
rlEnd();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use LINES to draw the outline
|
||||
rlBegin(RL_LINES);
|
||||
// Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
|
||||
for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
|
||||
{
|
||||
float angle = angles[k];
|
||||
const Vector2 center = centers[k];
|
||||
|
||||
for (int i = 0; i < segments; i++)
|
||||
{
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
|
||||
angle += stepLength;
|
||||
}
|
||||
}
|
||||
|
||||
// And now the remaining 4 lines
|
||||
for (int i = 0; i < 8; i += 2)
|
||||
// Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
|
||||
for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
|
||||
{
|
||||
float angle = angles[k];
|
||||
const Vector2 center = centers[k];
|
||||
for (int i = 0; i < segments; i++)
|
||||
{
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f(point[i].x, point[i].y);
|
||||
rlVertex2f(point[i + 1].x, point[i + 1].y);
|
||||
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
|
||||
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
|
||||
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
|
||||
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
|
||||
|
||||
angle += stepLength;
|
||||
}
|
||||
rlEnd();
|
||||
}
|
||||
}
|
||||
|
||||
// Upper rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[0].x, point[0].y);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[8].x, point[8].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[9].x, point[9].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[1].x, point[1].y);
|
||||
|
||||
// Right rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[2].x, point[2].y);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[10].x, point[10].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[11].x, point[11].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[3].x, point[3].y);
|
||||
|
||||
// Lower rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[13].x, point[13].y);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[5].x, point[5].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[4].x, point[4].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[12].x, point[12].y);
|
||||
|
||||
// Left rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[15].x, point[15].y);
|
||||
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[7].x, point[7].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||
rlVertex2f(point[6].x, point[6].y);
|
||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
||||
rlVertex2f(point[14].x, point[14].y);
|
||||
|
||||
rlEnd();
|
||||
rlSetTexture(0);
|
||||
#else
|
||||
rlBegin(RL_TRIANGLES);
|
||||
|
||||
// Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
|
||||
for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
|
||||
{
|
||||
float angle = angles[k];
|
||||
const Vector2 center = centers[k];
|
||||
|
||||
for (int i = 0; i < segments; i++)
|
||||
{
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
|
||||
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
|
||||
rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
|
||||
|
||||
angle += stepLength;
|
||||
}
|
||||
}
|
||||
|
||||
// Upper rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f(point[0].x, point[0].y);
|
||||
rlVertex2f(point[8].x, point[8].y);
|
||||
rlVertex2f(point[9].x, point[9].y);
|
||||
rlVertex2f(point[1].x, point[1].y);
|
||||
rlVertex2f(point[0].x, point[0].y);
|
||||
rlVertex2f(point[9].x, point[9].y);
|
||||
|
||||
// Right rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f(point[10].x, point[10].y);
|
||||
rlVertex2f(point[11].x, point[11].y);
|
||||
rlVertex2f(point[3].x, point[3].y);
|
||||
rlVertex2f(point[2].x, point[2].y);
|
||||
rlVertex2f(point[10].x, point[10].y);
|
||||
rlVertex2f(point[3].x, point[3].y);
|
||||
|
||||
// Lower rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f(point[13].x, point[13].y);
|
||||
rlVertex2f(point[5].x, point[5].y);
|
||||
rlVertex2f(point[4].x, point[4].y);
|
||||
rlVertex2f(point[12].x, point[12].y);
|
||||
rlVertex2f(point[13].x, point[13].y);
|
||||
rlVertex2f(point[4].x, point[4].y);
|
||||
|
||||
// Left rectangle
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f(point[7].x, point[7].y);
|
||||
rlVertex2f(point[6].x, point[6].y);
|
||||
rlVertex2f(point[14].x, point[14].y);
|
||||
rlVertex2f(point[15].x, point[15].y);
|
||||
rlVertex2f(point[7].x, point[7].y);
|
||||
rlVertex2f(point[14].x, point[14].y);
|
||||
rlEnd();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Draw a polygon of n sides
|
||||
|
|
|
|||
77
src/rtext.c
77
src/rtext.c
|
|
@ -58,8 +58,8 @@
|
|||
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 -> Only DrawTextPro()
|
||||
|
||||
#include <stdlib.h> // Required for: malloc(), free()
|
||||
#include <stdio.h> // Required for: vsprintf()
|
||||
#include <string.h> // Required for: strcmp(), strstr(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()]
|
||||
#include <stdio.h> // Required for: vsprintf(), snprintf()
|
||||
#include <string.h> // Required for: strcmp(), strstr(), strncpy(), sscanf() [Used in LoadBMFont()]
|
||||
#include <stdarg.h> // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()]
|
||||
#include <ctype.h> // Required for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
|
||||
|
||||
|
|
@ -536,7 +536,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
|
|||
Font font = { 0 };
|
||||
|
||||
char fileExtLower[16] = { 0 };
|
||||
strncpy(fileExtLower, TextToLower(fileType), 16 - 1);
|
||||
snprintf(fileExtLower, 16, "%s", TextToLower(fileType));
|
||||
|
||||
font.baseSize = fontSize;
|
||||
font.glyphPadding = 0;
|
||||
|
|
@ -1030,7 +1030,7 @@ bool ExportFontAsCode(Font font, const char *fileName)
|
|||
|
||||
// Get file name from path
|
||||
char fileNamePascal[256] = { 0 };
|
||||
strncpy(fileNamePascal, TextToPascal(GetFileNameWithoutExt(fileName)), 256 - 1);
|
||||
snprintf(fileNamePascal, 256, "%s", TextToPascal(GetFileNameWithoutExt(fileName)));
|
||||
|
||||
// Get font atlas image and size, required to estimate code file size
|
||||
// NOTE: This mechanism is highly coupled to raylib
|
||||
|
|
@ -1532,7 +1532,7 @@ char **LoadTextLines(const char *text, int *count)
|
|||
if ((text[i] == '\n') || (text[i] == '\0'))
|
||||
{
|
||||
lines[l] = (char *)RL_CALLOC(lineLen + 1, 1);
|
||||
strncpy(lines[l], &text[i - lineLen], lineLen);
|
||||
memcpy(lines[l], &text[i - lineLen], lineLen);
|
||||
lineLen = 0;
|
||||
l++;
|
||||
}
|
||||
|
|
@ -1699,7 +1699,7 @@ const char *TextSubtext(const char *text, int position, int length)
|
|||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||
|
||||
if (text != NULL)
|
||||
if ((text != NULL) && (position >= 0) && (length > 0))
|
||||
{
|
||||
int textLength = TextLength(text);
|
||||
|
||||
|
|
@ -1755,8 +1755,8 @@ char *GetTextBetween(const char *text, const char *begin, const char *end)
|
|||
{
|
||||
endIndex += (beginIndex + beginLen);
|
||||
int len = (endIndex - beginIndex - beginLen);
|
||||
if (len < (MAX_TEXT_BUFFER_LENGTH - 1)) strncpy(buffer, text + beginIndex + beginLen, len);
|
||||
else strncpy(buffer, text + beginIndex + beginLen, MAX_TEXT_BUFFER_LENGTH - 1);
|
||||
if (len < (MAX_TEXT_BUFFER_LENGTH - 1)) memcpy(buffer, text + beginIndex + beginLen, len);
|
||||
else snprintf(buffer, MAX_TEXT_BUFFER_LENGTH, "%s", text + beginIndex + beginLen);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1764,7 +1764,7 @@ char *GetTextBetween(const char *text, const char *begin, const char *end)
|
|||
}
|
||||
|
||||
// Replace text string
|
||||
// REQUIRES: strstr(), strncpy()
|
||||
// REQUIRES: strstr(), memcpy()
|
||||
// NOTE: Limited text replace functionality, using static string
|
||||
char *TextReplace(const char *text, const char *search, const char *replacement)
|
||||
{
|
||||
|
|
@ -1821,7 +1821,7 @@ char *TextReplace(const char *text, const char *search, const char *replacement)
|
|||
|
||||
// Copy remaind text part after replacement to result (pointed by moving temp)
|
||||
// NOTE: Text pointer internal copy has been updated along the process
|
||||
strncpy(tempPtr, text, TextLength(text));
|
||||
memcpy(tempPtr, text, TextLength(text));
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "Text with replacement is longer than internal buffer, use TextReplaceAlloc()");
|
||||
}
|
||||
|
|
@ -1830,7 +1830,7 @@ char *TextReplace(const char *text, const char *search, const char *replacement)
|
|||
}
|
||||
|
||||
// Replace text string
|
||||
// REQUIRES: strstr(), strncpy()
|
||||
// REQUIRES: strstr(), memcpy()
|
||||
// WARNING: Allocated memory must be manually freed
|
||||
char *TextReplaceAlloc(const char *text, const char *search, const char *replacement)
|
||||
{
|
||||
|
|
@ -1887,7 +1887,7 @@ char *TextReplaceAlloc(const char *text, const char *search, const char *replace
|
|||
|
||||
// Copy remaind text part after replacement to result (pointed by moving temp)
|
||||
// NOTE: Text pointer internal copy has been updated along the process
|
||||
strncpy(temp, text, TextLength(text));
|
||||
memcpy(temp, text, TextLength(text));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1975,10 +1975,11 @@ char *TextInsert(const char *text, const char *insert, int position)
|
|||
{
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||
int textLen = TextLength(text);
|
||||
|
||||
if ((text != NULL) && (insert != NULL))
|
||||
if ((text != NULL) && (insert != NULL) && (position >= 0))
|
||||
{
|
||||
int textLen = TextLength(text);
|
||||
if (position > textLen) position = textLen; // End of text string
|
||||
int insertLen = TextLength(insert);
|
||||
|
||||
if ((textLen + insertLen) < (MAX_TEXT_BUFFER_LENGTH - 1))
|
||||
|
|
@ -1987,7 +1988,7 @@ char *TextInsert(const char *text, const char *insert, int position)
|
|||
|
||||
for (int i = 0; i < position; i++) buffer[i] = text[i];
|
||||
for (int i = position; i < insertLen + position; i++) buffer[i] = insert[i - position];
|
||||
for (int i = (insertLen + position); i < (textLen + insertLen); i++) buffer[i] = text[i];
|
||||
for (int i = (insertLen + position); i < (textLen + insertLen); i++) buffer[i] = text[i - insertLen];
|
||||
|
||||
buffer[textLen + insertLen] = '\0'; // Add EOL
|
||||
}
|
||||
|
|
@ -2002,17 +2003,18 @@ char *TextInsert(const char *text, const char *insert, int position)
|
|||
char *TextInsertAlloc(const char *text, const char *insert, int position)
|
||||
{
|
||||
char *result = NULL;
|
||||
int textLen = TextLength(text);
|
||||
|
||||
if ((text != NULL) && (insert != NULL))
|
||||
if ((text != NULL) && (insert != NULL) && (position >= 0))
|
||||
{
|
||||
int textLen = TextLength(text);
|
||||
if (position > textLen) position = textLen; // End of text string
|
||||
int insertLen = TextLength(insert);
|
||||
|
||||
result = (char *)RL_MALLOC(textLen + insertLen + 1);
|
||||
|
||||
for (int i = 0; i < position; i++) result[i] = text[i];
|
||||
for (int i = position; i < insertLen + position; i++) result[i] = insert[i - position];
|
||||
for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i];
|
||||
for (int i = position; i < (insertLen + position); i++) result[i] = insert[i - position];
|
||||
for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i - insertLen];
|
||||
|
||||
result[textLen + insertLen] = '\0'; // Add EOL
|
||||
}
|
||||
|
|
@ -2036,7 +2038,7 @@ char *TextJoin(char **textList, int count, const char *delimiter)
|
|||
int textLength = TextLength(textList[i]);
|
||||
|
||||
// Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH
|
||||
if ((totalLength + textLength) < MAX_TEXT_BUFFER_LENGTH)
|
||||
if ((totalLength + textLength + delimiterLen) < MAX_TEXT_BUFFER_LENGTH)
|
||||
{
|
||||
memcpy(textPtr, textList[i], textLength);
|
||||
totalLength += textLength;
|
||||
|
|
@ -2200,18 +2202,43 @@ char *TextToSnake(const char *text)
|
|||
if (text != NULL)
|
||||
{
|
||||
// Check for next separator to upper case another character
|
||||
for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++, j++)
|
||||
for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); j++)
|
||||
{
|
||||
if ((text[j] >= 'A') && (text[j] <= 'Z'))
|
||||
if (text[j] == ' ')
|
||||
{
|
||||
if (i >= 1)
|
||||
if ((i > 0) && (buffer[i - 1] != '_'))
|
||||
{
|
||||
buffer[i] = '_';
|
||||
i++;
|
||||
}
|
||||
buffer[i] = text[j] + 32;
|
||||
}
|
||||
else buffer[i] = text[j];
|
||||
else if ((text[j] >= 'A') && (text[j] <= 'Z'))
|
||||
{
|
||||
if ((i > 0) && (buffer[i - 1] != '_'))
|
||||
{
|
||||
char prev = text[j - 1];
|
||||
char next = text[j + 1];
|
||||
|
||||
// Considering multiple cap leters to be on single word (HTTPRequest --> http_request)
|
||||
if (((prev >= 'a') && (prev <= 'z')) ||
|
||||
(((prev >= 'A') && (prev <= 'Z')) && ((next >= 'a') && (next <= 'z'))))
|
||||
{
|
||||
if (i < MAX_TEXT_BUFFER_LENGTH - 2)
|
||||
{
|
||||
buffer[i] = '_';
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffer[i] = text[j] + 32;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[i] = text[j];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
211
src/rtextures.c
211
src/rtextures.c
|
|
@ -12,6 +12,7 @@
|
|||
* #define SUPPORT_FILEFORMAT_JPG 0
|
||||
* #define SUPPORT_FILEFORMAT_GIF 1
|
||||
* #define SUPPORT_FILEFORMAT_QOI 1
|
||||
* #define SUPPORT_FILEFORMAT_PEP 1
|
||||
* #define SUPPORT_FILEFORMAT_PSD 0
|
||||
* #define SUPPORT_FILEFORMAT_HDR 0
|
||||
* #define SUPPORT_FILEFORMAT_PIC 0
|
||||
|
|
@ -69,6 +70,7 @@
|
|||
#include <string.h> // Required for: strlen() [Used in ImageTextEx()], strcmp() [Used in LoadImageFromMemory()/LoadImageAnimFromMemory()/ExportImageToMemory()]
|
||||
#include <math.h> // Required for: fabsf() [Used in DrawTextureRec()]
|
||||
#include <stdio.h> // Required for: sprintf() [Used in ExportImageAsCode()]
|
||||
#include <limits.h> // Required for: INT_MAX
|
||||
|
||||
// Support only desired texture formats on stb_image
|
||||
#if !SUPPORT_FILEFORMAT_BMP
|
||||
|
|
@ -188,7 +190,15 @@
|
|||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop) // Disable MSVC warning suppression
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SUPPORT_FILEFORMAT_PEP
|
||||
#define PEP_MALLOC RL_MALLOC
|
||||
#define PEP_REALLOC RL_REALLOC
|
||||
#define PEP_FREE RL_FREE
|
||||
|
||||
#define PEP_IMPLEMENTATION
|
||||
#include "external/pep.h"
|
||||
#endif
|
||||
|
||||
#if SUPPORT_IMAGE_EXPORT
|
||||
|
|
@ -510,6 +520,31 @@ Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, i
|
|||
}
|
||||
}
|
||||
#endif
|
||||
#if SUPPORT_FILEFORMAT_PEP
|
||||
else if ((strcmp(fileType, ".pep") == 0) || (strcmp(fileType, ".PEP") == 0))
|
||||
{
|
||||
if (fileData != NULL)
|
||||
{
|
||||
// Deserialize file data into pep structure
|
||||
pep p = pep_deserialize(fileData, dataSize);
|
||||
|
||||
// Decompress pep data for image struct
|
||||
// Decompression options:
|
||||
// - First color transparent, 3rd parameter: 1
|
||||
// - Premultiply alpha on loading, 4th parameter: 1
|
||||
unsigned int *pepData = pep_decompress(&p, pep_rgba, 1, 1);
|
||||
|
||||
image.data = pepData;
|
||||
image.width = p.width;
|
||||
image.height = p.height;
|
||||
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
|
||||
image.mipmaps = 1;
|
||||
|
||||
PEP_FREE(pepData);
|
||||
pep_free(&p);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if SUPPORT_FILEFORMAT_DDS
|
||||
else if ((strcmp(fileType, ".dds") == 0) || (strcmp(fileType, ".DDS") == 0))
|
||||
{
|
||||
|
|
@ -681,6 +716,25 @@ bool ExportImage(Image image, const char *fileName)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
#if SUPPORT_FILEFORMAT_PEP
|
||||
else if (IsFileExtension(fileName, ".pep"))
|
||||
{
|
||||
if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
|
||||
{
|
||||
// NOTE: Only RGBA 32bit (8bit per channel) image format supported
|
||||
pep p = pep_compress(image.data, image.width, image.height, pep_rgba, pep_8bit);
|
||||
|
||||
unsigned int pepDataSize = 0;
|
||||
unsigned char *pepData = pep_serialize(&p, &pepDataSize);
|
||||
|
||||
result = SaveFileData(fileName, pepData, pepDataSize);
|
||||
|
||||
PEP_FREE(pepData);
|
||||
pep_free(&p);
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "IMAGE: Image can not be exported, .pep requires RGBA 32bit input");
|
||||
}
|
||||
#endif
|
||||
#if SUPPORT_FILEFORMAT_KTX
|
||||
else if (IsFileExtension(fileName, ".ktx"))
|
||||
{
|
||||
|
|
@ -760,7 +814,7 @@ bool ExportImageAsCode(Image image, const char *fileName)
|
|||
|
||||
// Get file name from path and convert variable name to uppercase
|
||||
char varFileName[256] = { 0 };
|
||||
strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); // NOTE: Using function provided by [rcore] module
|
||||
snprintf(varFileName, 256, "%s", GetFileNameWithoutExt(fileName)); // NOTE: Using function provided by [rcore] module
|
||||
for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
|
||||
|
||||
// Add image information
|
||||
|
|
@ -790,9 +844,10 @@ bool ExportImageAsCode(Image image, const char *fileName)
|
|||
// Generate image: plain color
|
||||
Image GenImageColor(int width, int height, Color color)
|
||||
{
|
||||
Color *pixels = (Color *)RL_CALLOC(width*height, sizeof(Color));
|
||||
int dataSize = GetPixelDataSize(width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8);
|
||||
Color *pixels = (Color *)RL_CALLOC(dataSize, 1);
|
||||
|
||||
for (int i = 0; i < width*height; i++) pixels[i] = color;
|
||||
for (int i = 0; (pixels != NULL) && (i < width*height); i++) pixels[i] = color;
|
||||
|
||||
Image image = {
|
||||
.data = pixels,
|
||||
|
|
@ -1175,18 +1230,34 @@ Image ImageFromImage(Image image, Rectangle rec)
|
|||
{
|
||||
Image result = { 0 };
|
||||
|
||||
int bytesPerPixel = GetPixelDataSize(1, 1, image.format);
|
||||
// Security check to avoid program crash
|
||||
if ((image.data == NULL) || (image.width == 0) || (image.height == 0)) return result;
|
||||
|
||||
result.width = (int)rec.width;
|
||||
result.height = (int)rec.height;
|
||||
result.data = RL_CALLOC((int)rec.width*(int)rec.height*bytesPerPixel, 1);
|
||||
result.format = image.format;
|
||||
result.mipmaps = 1;
|
||||
if (image.format < PIXELFORMAT_COMPRESSED_DXT1_RGB)
|
||||
{
|
||||
// Basic rectangle validation: size smaller than image size
|
||||
if ((rec.x >= 0) && (rec.y >= 0) && (rec.width > 0) && (rec.height > 0) &&
|
||||
(((int)rec.x + (int)rec.width) <= image.width) &&
|
||||
(((int)rec.y + (int)rec.height) <= image.height))
|
||||
{
|
||||
int bytesPerPixel = GetPixelDataSize(1, 1, image.format);
|
||||
|
||||
for (int y = 0; y < (int)rec.height; y++)
|
||||
{
|
||||
memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel, ((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel, (int)rec.width*bytesPerPixel);
|
||||
}
|
||||
result.width = (int)rec.width;
|
||||
result.height = (int)rec.height;
|
||||
result.data = RL_CALLOC((int)rec.width*(int)rec.height*bytesPerPixel, 1);
|
||||
result.format = image.format;
|
||||
result.mipmaps = 1;
|
||||
|
||||
for (int y = 0; y < (int)rec.height; y++)
|
||||
{
|
||||
memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel,
|
||||
((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel,
|
||||
(int)rec.width*bytesPerPixel);
|
||||
}
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "IMAGE: ImageToImage(), rectangle provided not valid");
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "IMAGE: Image manipulation not supported for compressed formats");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -2631,45 +2702,49 @@ void ImageRotate(Image *image, int degrees)
|
|||
int width = (int)(fabsf(image->width*cosRadius) + fabsf(image->height*sinRadius));
|
||||
int height = (int)(fabsf(image->height*cosRadius) + fabsf(image->width*sinRadius));
|
||||
|
||||
int dataSize = GetPixelDataSize(width, height, image->format);
|
||||
int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
|
||||
unsigned char *rotatedData = (unsigned char *)RL_CALLOC(width*height, bytesPerPixel);
|
||||
unsigned char *rotatedData = (unsigned char *)RL_CALLOC(dataSize, 1);
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
if (rotatedData != NULL)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
float oldX = ((x - width/2.0f)*cosRadius + (y - height/2.0f)*sinRadius) + image->width/2.0f;
|
||||
float oldY = ((y - height/2.0f)*cosRadius - (x - width/2.0f)*sinRadius) + image->height/2.0f;
|
||||
|
||||
if ((oldX >= 0) && (oldX < image->width) && (oldY >= 0) && (oldY < image->height))
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
int x1 = (int)floorf(oldX);
|
||||
int y1 = (int)floorf(oldY);
|
||||
int x2 = MIN(x1 + 1, image->width - 1);
|
||||
int y2 = MIN(y1 + 1, image->height - 1);
|
||||
float oldX = ((x - width/2.0f)*cosRadius + (y - height/2.0f)*sinRadius) + image->width/2.0f;
|
||||
float oldY = ((y - height/2.0f)*cosRadius - (x - width/2.0f)*sinRadius) + image->height/2.0f;
|
||||
|
||||
float px = oldX - x1;
|
||||
float py = oldY - y1;
|
||||
|
||||
for (int i = 0; i < bytesPerPixel; i++)
|
||||
if ((oldX >= 0) && (oldX < image->width) && (oldY >= 0) && (oldY < image->height))
|
||||
{
|
||||
float f1 = ((unsigned char *)image->data)[(y1*image->width + x1)*bytesPerPixel + i];
|
||||
float f2 = ((unsigned char *)image->data)[(y1*image->width + x2)*bytesPerPixel + i];
|
||||
float f3 = ((unsigned char *)image->data)[(y2*image->width + x1)*bytesPerPixel + i];
|
||||
float f4 = ((unsigned char *)image->data)[(y2*image->width + x2)*bytesPerPixel + i];
|
||||
int x1 = (int)floorf(oldX);
|
||||
int y1 = (int)floorf(oldY);
|
||||
int x2 = MIN(x1 + 1, image->width - 1);
|
||||
int y2 = MIN(y1 + 1, image->height - 1);
|
||||
|
||||
float val = f1*(1 - px)*(1 - py) + f2*px*(1 - py) + f3*(1 - px)*py + f4*px*py;
|
||||
float px = oldX - x1;
|
||||
float py = oldY - y1;
|
||||
|
||||
rotatedData[(y*width + x)*bytesPerPixel + i] = (unsigned char)val;
|
||||
for (int i = 0; i < bytesPerPixel; i++)
|
||||
{
|
||||
float f1 = ((unsigned char *)image->data)[(y1*image->width + x1)*bytesPerPixel + i];
|
||||
float f2 = ((unsigned char *)image->data)[(y1*image->width + x2)*bytesPerPixel + i];
|
||||
float f3 = ((unsigned char *)image->data)[(y2*image->width + x1)*bytesPerPixel + i];
|
||||
float f4 = ((unsigned char *)image->data)[(y2*image->width + x2)*bytesPerPixel + i];
|
||||
|
||||
float val = f1*(1 - px)*(1 - py) + f2*px*(1 - py) + f3*(1 - px)*py + f4*px*py;
|
||||
|
||||
rotatedData[(y*width + x)*bytesPerPixel + i] = (unsigned char)val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RL_FREE(image->data);
|
||||
image->data = rotatedData;
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
RL_FREE(image->data);
|
||||
image->data = rotatedData;
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3865,10 +3940,16 @@ void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color)
|
|||
}
|
||||
}
|
||||
|
||||
// Draw a color-filled rectangle with pro parameters within and image
|
||||
void ImageDrawRectanglePro(Image *dst, Rectangle rec, Vector2 origin, float rotation, Color color)
|
||||
{
|
||||
// TODO: NEW: Implement ImageDrawRectanglePro()
|
||||
}
|
||||
|
||||
// Draw rectangle lines within an image
|
||||
void ImageDrawRectangleLines(Image *dst, int posX, int posY, int width, int height, Color color)
|
||||
{
|
||||
Rectangle rec = { posX, posY, width, height };
|
||||
Rectangle rec = { (float)posX, (float)posY, (float)width, (float)height };
|
||||
ImageDrawRectangleLinesEx(dst, rec, 1, color);
|
||||
}
|
||||
|
||||
|
|
@ -3881,6 +3962,12 @@ void ImageDrawRectangleLinesEx(Image *dst, Rectangle rec, int thick, Color color
|
|||
ImageDrawRectangle(dst, (int)rec.x, (int)(rec.y + rec.height - thick), (int)rec.width, thick, color);
|
||||
}
|
||||
|
||||
// Draw rectangle with gradient colors within an image, counter-clockwise color order
|
||||
void ImageDrawRectangleGradientEx(Image *dst, Rectangle rec, Color col1, Color col2, Color col3, Color col4)
|
||||
{
|
||||
// TODO: NEW: Implement ImageDrawRectangleGradientEx()
|
||||
}
|
||||
|
||||
// Draw circle within an image
|
||||
void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color)
|
||||
{
|
||||
|
|
@ -3948,17 +4035,23 @@ void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color color)
|
|||
// Draw a gradient-filled circle within an image
|
||||
void ImageDrawCircleGradient(Image *dst, Vector2 center, float radius, Color inner, Color outer)
|
||||
{
|
||||
// TODO: Implement gradient circle drawing
|
||||
// TODO: NEW: Implement ImageDrawCircleGradient()
|
||||
}
|
||||
|
||||
// Draw an image within an image
|
||||
void ImageDrawImage(Image *dst, Image src, int posX, int posY, Color tint)
|
||||
{
|
||||
Rectangle srcRec = { 0, 0, src.width, src.height };
|
||||
Rectangle dstRec = { posX, posY, srcRec.width, srcRec.height };
|
||||
Rectangle srcRec = { 0.0f, 0.0f, (float)src.width, (float)src.height };
|
||||
Rectangle dstRec = { (float)posX, (float)posY, srcRec.width, srcRec.height };
|
||||
ImageDrawImagePro(dst, src, srcRec, dstRec, (Vector2){ 0 }, 0.0f, tint);
|
||||
}
|
||||
|
||||
// Draw an image with scaling and rotation within an image
|
||||
void ImageDrawImageEx(Image *dst, Image src, Vector2 position, float rotation, float scale, Color tint)
|
||||
{
|
||||
// TODO: NEW: Implement ImageDrawImageEx()
|
||||
}
|
||||
|
||||
// Draw a part of an image defined by a rectangle within an image
|
||||
void ImageDrawImageRec(Image *dst, Image src, Rectangle srcRec, Vector2 position, Color tint)
|
||||
{
|
||||
|
|
@ -3967,8 +4060,7 @@ void ImageDrawImageRec(Image *dst, Image src, Rectangle srcRec, Vector2 position
|
|||
}
|
||||
|
||||
// Draw a part of an image defined by a rectangle into destination rectangle, with scaling and rotation, within an image
|
||||
// NOTE: Color tint is applied to source image
|
||||
// TODO: WARNING: origin and rotation are not implemented
|
||||
// TODO: REVIEW: ImageDrawImagePro(), implement origin and rotation for image drawing
|
||||
void ImageDrawImagePro(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Vector2 origin, float rotation, Color tint)
|
||||
{
|
||||
// Security check to avoid program crash
|
||||
|
|
@ -4146,6 +4238,12 @@ void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position,
|
|||
UnloadImage(imText);
|
||||
}
|
||||
|
||||
// Draw text using Font and pro parameters (rotation)
|
||||
void ImageDrawTextPro(Image *dst, Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint)
|
||||
{
|
||||
// TODO: NEW: Implement ImageDrawTextPro()
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Texture loading functions
|
||||
//------------------------------------------------------------------------------------
|
||||
|
|
@ -5425,17 +5523,24 @@ int GetPixelDataSize(int width, int height, int format)
|
|||
case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
unsigned long long dataSizeBytes = ((unsigned long long)width*height*bpp) >> 3; // Get size in bytes (dividing by 8)
|
||||
|
||||
double bytesPerPixel = (double)bpp/8.0;
|
||||
dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes
|
||||
|
||||
// Most compressed formats works on 4x4 blocks,
|
||||
// if texture is smaller, minimum dataSize is 8 or 16
|
||||
if ((width < 4) && (height < 4))
|
||||
if (dataSizeBytes < INT_MAX)
|
||||
{
|
||||
if ((format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8;
|
||||
else if ((format >= PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16;
|
||||
dataSize = (int)dataSizeBytes;
|
||||
|
||||
// Most compressed formats works on 4x4 blocks,
|
||||
// if texture is smaller, minimum dataSize is 8 or 16
|
||||
if ((width < 4) && (height < 4))
|
||||
{
|
||||
if ((format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8;
|
||||
else if ((format >= PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: In case required image data larger than 2GB, no memory allocated at all (NULL)
|
||||
if (dataSize == 0) TRACELOG(LOG_WARNING, "Requested image size is larger than 2GB, it can not be allocated");
|
||||
|
||||
return dataSize;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue