mirror of
https://github.com/raysan5/raylib.git
synced 2026-03-10 02:55:41 +00:00
Code gardening
This commit is contained in:
@@ -126,7 +126,7 @@
|
||||
|
||||
// rcore: Configuration values
|
||||
// NOTE: Below values are alread defined inside [rcore.c] so there is no need to be
|
||||
// redefined here, in case it must be done, just uncomment the required line and update
|
||||
// redefined here, in case it must be done, uncomment the required line and update
|
||||
// the value; it can also be done on compilation with -DVALUE_TO_REDEFINE=128
|
||||
//------------------------------------------------------------------------------------
|
||||
//#define MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message
|
||||
@@ -160,7 +160,7 @@
|
||||
|
||||
// rlgl: Configuration values
|
||||
// NOTE: Below values are alread defined inside [rlgl.h] so there is no need to be
|
||||
// redefined here, in case it must be done, just uncomment the required line and update
|
||||
// redefined here, in case it must be done, uncomment the required line and update
|
||||
// the value; it can also be done on compilation with -DVALUE_TO_REDEFINE=128
|
||||
//------------------------------------------------------------------------------------
|
||||
//#define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 4096 // Default internal render batch elements limits
|
||||
@@ -350,7 +350,7 @@
|
||||
|
||||
// raudio: Configuration values
|
||||
// NOTE: Below values are alread defined inside [rlgl.h] so there is no need to be
|
||||
// redefined here, in case it must be done, just uncomment the required line and update
|
||||
// redefined here, in case it must be done, uncomment the required line and update
|
||||
// the value; it can also be done on compilation with -DVALUE_TO_REDEFINE=128
|
||||
//------------------------------------------------------------------------------------
|
||||
//#define AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (miniaudio: float-32bit)
|
||||
|
||||
2
src/external/rlsw.h
vendored
2
src/external/rlsw.h
vendored
@@ -48,7 +48,7 @@
|
||||
* recommended under specific situations and only if the developers know
|
||||
* what are they doing; this flag is not defined by default
|
||||
*
|
||||
* rlsw capabilities could be customized just defining some internal
|
||||
* rlsw capabilities could be customized defining some internal
|
||||
* values before library inclusion (default values listed):
|
||||
*
|
||||
* #define SW_GL_FRAMEBUFFER_COPY_BGRA true
|
||||
|
||||
2
src/external/win32_clipboard.h
vendored
2
src/external/win32_clipboard.h
vendored
@@ -14,7 +14,7 @@ unsigned char *Win32GetClipboardImageData(int *width, int *height, unsigned long
|
||||
#include <assert.h>
|
||||
|
||||
// NOTE: These search for architecture is taken from "windows.h", and it's necessary to avoid including windows.h
|
||||
// and still make it compile on msvc, because import indirectly importing "winnt.h" (e.g. <minwindef.h>) can cause problems is these are not defined.
|
||||
// and still make it compile on msvc, because import indirectly importing "winnt.h" (e.g. <minwindef.h>) can cause problems is these are not defined
|
||||
#if !defined(_X86_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_IX86)
|
||||
#define _X86_
|
||||
#if !defined(_CHPE_X86_ARM64_) && defined(_M_HYBRID)
|
||||
|
||||
@@ -715,7 +715,7 @@ void PollInputEvents(void)
|
||||
{
|
||||
#if SUPPORT_GESTURES_SYSTEM
|
||||
// NOTE: Gestures update must be called every frame to reset gestures correctly
|
||||
// because ProcessGestureEvent() is just called on an event, not every frame
|
||||
// because ProcessGestureEvent() is called on an event, not every frame
|
||||
UpdateGestures();
|
||||
#endif
|
||||
|
||||
@@ -1055,7 +1055,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
|
||||
InitGraphicsDevice();
|
||||
|
||||
// Initialize OpenGL context (states and resources)
|
||||
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
|
||||
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, stored as globals in rlgl
|
||||
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
|
||||
|
||||
// Setup default viewport
|
||||
@@ -1299,7 +1299,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
||||
}
|
||||
else if ((keycode == AKEYCODE_BACK) || (keycode == AKEYCODE_MENU))
|
||||
{
|
||||
// Eat BACK_BUTTON and AKEYCODE_MENU, just do nothing... and don't let to be handled by OS!
|
||||
// Eat BACK_BUTTON and AKEYCODE_MENU, do nothing... and don't let to be handled by OS!
|
||||
return 1;
|
||||
}
|
||||
else if ((keycode == AKEYCODE_VOLUME_UP) || (keycode == AKEYCODE_VOLUME_DOWN))
|
||||
@@ -1547,7 +1547,7 @@ FILE *__wrap_fopen(const char *fileName, const char *mode)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just do a regular open if file is not found in the assets
|
||||
// Do a regular open if file is not found in the assets
|
||||
file = __real_fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode);
|
||||
if (file == NULL) file = __real_fopen(fileName, mode);
|
||||
}
|
||||
|
||||
@@ -837,7 +837,7 @@ int GetCurrentMonitor(void)
|
||||
{
|
||||
// In case the window is between two monitors, below logic is used
|
||||
// to try to detect the "current monitor" for that window, note that
|
||||
// this is probably an overengineered solution for a very side case
|
||||
// this is probably an overengineered solution for a side case
|
||||
// trying to match SDL behaviour
|
||||
|
||||
int closestDist = 0x7FFFFFFF;
|
||||
@@ -1258,7 +1258,7 @@ void PollInputEvents(void)
|
||||
{
|
||||
#if SUPPORT_GESTURES_SYSTEM
|
||||
// NOTE: Gestures update must be called every frame to reset gestures correctly
|
||||
// because ProcessGestureEvent() is just called on an event, not every frame
|
||||
// because ProcessGestureEvent() is called on an event, not every frame
|
||||
UpdateGestures();
|
||||
#endif
|
||||
|
||||
@@ -1588,7 +1588,7 @@ int InitPlatform(void)
|
||||
}
|
||||
|
||||
// NOTE: GLFW 3.4+ defers initialization of the Joystick subsystem on the first call to any Joystick related functions
|
||||
// Forcing this initialization here avoids doing it on PollInputEvents() called by EndDrawing() after first frame has been just drawn
|
||||
// Forcing this initialization here avoids doing it on PollInputEvents() called by EndDrawing() after first frame has been drawn
|
||||
// The initialization will still happen and possible delays still occur, but before the window is shown, which is a nicer experience
|
||||
// REF: https://github.com/raysan5/raylib/issues/1554
|
||||
glfwSetJoystickCallback(NULL);
|
||||
|
||||
@@ -1198,7 +1198,7 @@ void PollInputEvents(void)
|
||||
{
|
||||
#if SUPPORT_GESTURES_SYSTEM
|
||||
// NOTE: Gestures update must be called every frame to reset gestures correctly
|
||||
// because ProcessGestureEvent() is just called on an event, not every frame
|
||||
// because ProcessGestureEvent() is called on an event, not every frame
|
||||
UpdateGestures();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
#define USING_SDL3_PROJECT
|
||||
#endif
|
||||
#ifndef SDL_ENABLE_OLD_NAMES
|
||||
#define SDL_ENABLE_OLD_NAMES // Just in case on SDL3, some in-between compatibily is needed
|
||||
#define SDL_ENABLE_OLD_NAMES // In case on SDL3, some in-between compatibily is needed
|
||||
#endif
|
||||
// SDL base library (window/rendered, input, timing... functionality)
|
||||
#ifdef USING_SDL3_PROJECT
|
||||
@@ -1365,7 +1365,7 @@ void PollInputEvents(void)
|
||||
{
|
||||
#if SUPPORT_GESTURES_SYSTEM
|
||||
// NOTE: Gestures update must be called every frame to reset gestures correctly
|
||||
// because ProcessGestureEvent() is just called on an event, not every frame
|
||||
// because ProcessGestureEvent() is called on an event, not every frame
|
||||
UpdateGestures();
|
||||
#endif
|
||||
|
||||
@@ -1482,7 +1482,7 @@ void PollInputEvents(void)
|
||||
|
||||
#ifndef USING_VERSION_SDL3
|
||||
// The SDL_WINDOWEVENT_* events have been moved to top level events, and SDL_WINDOWEVENT has been removed
|
||||
// In general, handling this change just means checking for the individual events instead of first checking for SDL_WINDOWEVENT
|
||||
// In general, handling this change means checking for the individual events instead of first checking for SDL_WINDOWEVENT
|
||||
// and then checking for window events; Events >= SDL_EVENT_WINDOW_FIRST and <= SDL_EVENT_WINDOW_LAST can be compared
|
||||
// to see whether it's a window event
|
||||
case SDL_WINDOWEVENT:
|
||||
|
||||
@@ -2198,7 +2198,7 @@ static unsigned SanitizeFlags(int mode, unsigned flags)
|
||||
// retry loop that continues until either the desired state is reached or the state stops changing
|
||||
static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height)
|
||||
{
|
||||
// Flags that just apply immediately without needing any operations
|
||||
// Flags that apply immediately without needing any operations
|
||||
CORE.Window.flags |= (desiredFlags & FLAG_MASK_NO_UPDATE);
|
||||
|
||||
int vsync = (desiredFlags & FLAG_VSYNC_HINT)? 1 : 0;
|
||||
|
||||
@@ -183,14 +183,14 @@ static const int evkeyToUnicodeLUT[] = {
|
||||
0, 27, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 45, 61, 8, 0, 113, 119, 101, 114,
|
||||
116, 121, 117, 105, 111, 112, 0, 0, 13, 0, 97, 115, 100, 102, 103, 104, 106, 107, 108, 59,
|
||||
39, 96, 0, 92, 122, 120, 99, 118, 98, 110, 109, 44, 46, 47, 0, 0, 0, 32
|
||||
// LUT currently incomplete, just mapped the most essential keys
|
||||
// LUT currently incomplete, only mapped the most essential keys
|
||||
};
|
||||
|
||||
// This is the map used to map any keycode returned from linux to a raylib code from 'raylib.h'
|
||||
// NOTE: Use short here to save a little memory
|
||||
static const short linuxToRaylibMap[KEYMAP_SIZE] = {
|
||||
// We don't map those with designated initialization, because we would getting
|
||||
// into loads of naming conflicts
|
||||
// Don't map with designated initialization,
|
||||
// it will geenrate many naming conflicts
|
||||
0, 256, 49, 50, 51, 52, 53, 54,
|
||||
55, 56, 57, 48, 45, 61, 259, 258,
|
||||
81, 87, 69, 82, 84, 89, 85, 73,
|
||||
@@ -764,9 +764,9 @@ void SwapScreenBuffer()
|
||||
// Attempt page flip
|
||||
// NOTE: rmModePageFlip() schedules a buffer-flip for the next vblank and then notifies us about it
|
||||
// It takes a CRTC-id, fb-id and an arbitrary data-pointer and then schedules the page-flip
|
||||
// This is fully asynchronous and when the page-flip happens, the DRM-fd will become readable and we can call drmHandleEvent()
|
||||
// This will read all vblank/page-flip events and call our modeset_page_flip_event() callback with the data-pointer that we passed to drmModePageFlip()
|
||||
// We simply call modeset_draw_dev() then so the next frame is rendered... returns immediately
|
||||
// This is fully asynchronous and when the page-flip happens, the DRM-fd will become readable and drmHandleEvent() can be called
|
||||
// This will read all vblank/page-flip events and call our modeset_page_flip_event() callback with the data-pointer passed to drmModePageFlip()
|
||||
// Simply call modeset_draw_dev() then so the next frame is rendered... returns immediately
|
||||
if (drmModePageFlip(platform.fd, platform.crtc->crtc_id, fbId, DRM_MODE_PAGE_FLIP_EVENT, platform.prevBO))
|
||||
{
|
||||
if (errno == EBUSY) errCnt[3]++; // Display busy - skip flip
|
||||
@@ -1067,7 +1067,7 @@ void PollInputEvents(void)
|
||||
{
|
||||
#if SUPPORT_GESTURES_SYSTEM
|
||||
// NOTE: Gestures update must be called every frame to reset gestures correctly
|
||||
// because ProcessGestureEvent() is just called on an event, not every frame
|
||||
// because ProcessGestureEvent() is called on an event, not every frame
|
||||
UpdateGestures();
|
||||
#endif
|
||||
|
||||
@@ -1089,7 +1089,7 @@ void PollInputEvents(void)
|
||||
PollKeyboardEvents();
|
||||
|
||||
#if SUPPORT_SSH_KEYBOARD_RPI
|
||||
// NOTE: Keyboard reading could be done using input_event(s) or just read from stdin, both methods are used here
|
||||
// NOTE: Keyboard reading could be done using input_event(s) or read from stdin, both methods are used here
|
||||
// stdin reading is still used for legacy purposes, it allows keyboard input trough SSH console
|
||||
if (!platform.eventKeyboardMode) ProcessKeyboard();
|
||||
#endif
|
||||
@@ -1225,7 +1225,7 @@ int InitPlatform(void)
|
||||
if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->count_modes > 0))
|
||||
{
|
||||
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
// For hardware rendering, we need an encoder_id
|
||||
// For hardware rendering, an encoder_id is needed
|
||||
if (con->encoder_id)
|
||||
{
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i connected with encoder", i);
|
||||
@@ -1234,7 +1234,7 @@ int InitPlatform(void)
|
||||
}
|
||||
else TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i connected but no encoder", i);
|
||||
#else
|
||||
// For software rendering, we can accept even without encoder_id
|
||||
// For software rendering, accept even without encoder_id
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i suitable for software rendering", i);
|
||||
platform.connector = con;
|
||||
break;
|
||||
@@ -1534,7 +1534,7 @@ int InitPlatform(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// At this point we need to manage render size vs screen size
|
||||
// At this point, manage render size vs screen size
|
||||
// NOTE: This function use and modify global module variables:
|
||||
// -> CORE.Window.screen.width/CORE.Window.screen.height
|
||||
// -> CORE.Window.render.width/CORE.Window.render.height
|
||||
@@ -1572,7 +1572,7 @@ int InitPlatform(void)
|
||||
// NOTE: GL procedures address loader is required to load extensions
|
||||
rlLoadExtensions(eglGetProcAddress);
|
||||
#else
|
||||
// At this point we need to manage render size vs screen size
|
||||
// At this point, manage render size vs screen size
|
||||
// NOTE: This function use and modify global module variables:
|
||||
// -> CORE.Window.screen.width/CORE.Window.screen.height
|
||||
// -> CORE.Window.render.width/CORE.Window.render.height
|
||||
@@ -1596,7 +1596,7 @@ int InitPlatform(void)
|
||||
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) MinimizeWindow();
|
||||
|
||||
// If graphic device is no properly initialized, we end program
|
||||
// If graphic device is no properly initialized, end program
|
||||
if (!CORE.Window.ready)
|
||||
{
|
||||
TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device");
|
||||
@@ -1745,7 +1745,7 @@ void ClosePlatform(void)
|
||||
// Initialize Keyboard system (using standard input)
|
||||
static void InitKeyboard(void)
|
||||
{
|
||||
// NOTE: We read directly from Standard Input (stdin) - STDIN_FILENO file descriptor,
|
||||
// NOTE: Read directly from Standard Input (stdin) - STDIN_FILENO file descriptor,
|
||||
// Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE
|
||||
|
||||
// Save terminal keyboard settings
|
||||
@@ -1978,8 +1978,8 @@ static void ConfigureEvdevDevice(char *device)
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point we have a connection to the device, but we don't yet know what the device is
|
||||
// It could be many things, even as simple as a power button...
|
||||
// At this point, a connection to the device has been stablished, but still left to know what the device is,
|
||||
// it could be many things, even as simple as a power button...
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Identify the device
|
||||
@@ -1990,8 +1990,8 @@ static void ConfigureEvdevDevice(char *device)
|
||||
} absinfo[ABS_CNT] = { 0 };
|
||||
|
||||
// These flags aren't really a one of
|
||||
// Some devices could have properties we assosciate with keyboards as well as properties
|
||||
// we assosciate with mice
|
||||
// Some devices could have properties associated with keyboards
|
||||
// as well as properties associated with mice
|
||||
bool isKeyboard = false;
|
||||
bool isMouse = false;
|
||||
bool isTouch = false;
|
||||
@@ -2027,11 +2027,10 @@ static void ConfigureEvdevDevice(char *device)
|
||||
TEST_BIT(keyBits, BTN_TOOL_FINGER) ||
|
||||
TEST_BIT(keyBits, BTN_TOUCH))) isTouch = true;
|
||||
|
||||
// Absolute mice should really only exist with VMWare, but it shouldn't
|
||||
// matter if we support them
|
||||
// Absolute mice should really only exist with VMWare
|
||||
else if (hasAbsXY && TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true;
|
||||
|
||||
// If any of the common joystick axes are present, we assume it's a gamepad
|
||||
// If any of the common joystick axes are present, assume it's a gamepad
|
||||
else
|
||||
{
|
||||
for (int axis = (hasAbsXY? ABS_Z : ABS_X); axis < ABS_PRESSURE; axis++)
|
||||
@@ -2056,7 +2055,7 @@ static void ConfigureEvdevDevice(char *device)
|
||||
{
|
||||
ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relBits)), relBits);
|
||||
|
||||
// If it has any of the gamepad or touch features we tested so far, it's not a mouse
|
||||
// If it has any of the gamepad or touch features tested so far, it's not a mouse
|
||||
if (!isTouch &&
|
||||
!isGamepad &&
|
||||
TEST_BIT(relBits, REL_X) &&
|
||||
@@ -2067,12 +2066,12 @@ static void ConfigureEvdevDevice(char *device)
|
||||
if (TEST_BIT(evBits, EV_KEY))
|
||||
{
|
||||
// The first 32 keys as defined in input-event-codes.h are pretty much
|
||||
// exclusive to keyboards, so we can test them using a mask
|
||||
// exclusive to keyboards, so they can be tested using a mask
|
||||
// Leave out the first bit to not test KEY_RESERVED
|
||||
const unsigned long mask = 0xFFFFFFFE;
|
||||
if ((keyBits[0] & mask) == mask) isKeyboard = true;
|
||||
|
||||
// If we find any of the common gamepad buttons we assume it's a gamepad
|
||||
// If any of the common gamepad buttons is found, assume it's a gamepad
|
||||
else
|
||||
{
|
||||
for (int button = BTN_JOYSTICK; button < BTN_DIGI; ++button)
|
||||
@@ -2149,7 +2148,7 @@ static void ConfigureEvdevDevice(char *device)
|
||||
if (absAxisCount > 0)
|
||||
{
|
||||
// TODO: Review GamepadAxis enum matching
|
||||
// So gamepad axes (as in the actual linux joydev.c) are just simply enumerated
|
||||
// So gamepad axes (as in the actual linux joydev.c) are simply enumerated
|
||||
// and (at least for some input drivers like xpat) it's convention to use
|
||||
// ABS_X, ABX_Y for one joystick ABS_RX, ABS_RY for the other and the Z axes for the shoulder buttons
|
||||
// If these are now enumerated, it results to LJOY_X, LJOY_Y, LEFT_SHOULDERB, RJOY_X, ...
|
||||
@@ -2197,7 +2196,7 @@ static void PollKeyboardEvents(void)
|
||||
if (event.type != EV_KEY) continue;
|
||||
|
||||
#if SUPPORT_SSH_KEYBOARD_RPI
|
||||
// If the event was a key, we know a working keyboard is connected, so disable the SSH keyboard
|
||||
// If the event was a key, assume a working keyboard is connected, so disable the SSH keyboard
|
||||
platform.eventKeyboardMode = true;
|
||||
#endif
|
||||
// Keyboard keys appear for codes 1 to 255, ignore everthing else
|
||||
@@ -2206,7 +2205,7 @@ static void PollKeyboardEvents(void)
|
||||
// Lookup the scancode in the keymap to get a keycode
|
||||
keycode = linuxToRaylibMap[event.code];
|
||||
|
||||
// Make sure we got a valid keycode
|
||||
// Make sure a valid keycode is obtained
|
||||
if ((keycode > 0) && (keycode < MAX_KEYBOARD_KEYS))
|
||||
{
|
||||
// WARNING: https://www.kernel.org/doc/Documentation/input/input.txt
|
||||
@@ -2380,8 +2379,8 @@ static void PollMouseEvents(void)
|
||||
{
|
||||
platform.touchPosition[platform.touchSlot].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width;
|
||||
|
||||
// If this slot is active, it's a move. If not, we are just updating the buffer for when it becomes active.
|
||||
// Only set to MOVE if we haven't already detected a DOWN or UP event this frame
|
||||
// If this slot is active, it's a move; If not, update the buffer for when it becomes active
|
||||
// Only set to MOVE if a DOWN or UP event has not been detected this frame
|
||||
if (platform.touchActive[platform.touchSlot] && touchAction == -1) touchAction = 2; // TOUCH_ACTION_MOVE
|
||||
}
|
||||
}
|
||||
@@ -2392,8 +2391,8 @@ static void PollMouseEvents(void)
|
||||
{
|
||||
platform.touchPosition[platform.touchSlot].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height;
|
||||
|
||||
// If this slot is active, it's a move. If not, we are just updating the buffer for when it becomes active.
|
||||
// Only set to MOVE if we haven't already detected a DOWN or UP event this frame
|
||||
// If this slot is active, it's a move; If not, update the buffer for when it becomes active
|
||||
// Only set to MOVE if a DOWN or UP event have not been detected this frame
|
||||
if (platform.touchActive[platform.touchSlot] && touchAction == -1) touchAction = 2; // TOUCH_ACTION_MOVE
|
||||
}
|
||||
}
|
||||
@@ -2418,7 +2417,7 @@ static void PollMouseEvents(void)
|
||||
platform.touchPosition[platform.touchSlot].y = -1;
|
||||
platform.touchId[platform.touchSlot] = -1;
|
||||
|
||||
// Force UP action if we haven't already set a DOWN action
|
||||
// Force UP action if DOWN action has not already been set
|
||||
// (DOWN takes priority over UP if both happen in one frame, though rare)
|
||||
if (touchAction != 1) touchAction = 0; // TOUCH_ACTION_UP
|
||||
}
|
||||
@@ -2665,7 +2664,7 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
|
||||
// NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified
|
||||
static void SetupFramebuffer(int width, int height)
|
||||
{
|
||||
// Calculate CORE.Window.render.width and CORE.Window.render.height, we have the display size (input params) and the desired screen size (global var)
|
||||
// Calculate CORE.Window.render.width and CORE.Window.render.height, using the display size (input params) and the desired screen size (global var)
|
||||
if ((CORE.Window.screen.width > CORE.Window.display.width) || (CORE.Window.screen.height > CORE.Window.display.height))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Downscaling required: Screen size (%ix%i) is bigger than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
|
||||
@@ -2693,8 +2692,8 @@ static void SetupFramebuffer(int width, int height)
|
||||
float scaleRatio = (float)CORE.Window.render.width/(float)CORE.Window.screen.width;
|
||||
CORE.Window.screenScale = MatrixScale(scaleRatio, scaleRatio, 1.0f);
|
||||
|
||||
// NOTE: We render to full display resolution!
|
||||
// We just need to calculate above parameters for downscale matrix and offsets
|
||||
// NOTE: Rendering to full display resolution,
|
||||
// calculate above parameters for downscale matrix and offsets
|
||||
CORE.Window.render.width = CORE.Window.display.width;
|
||||
CORE.Window.render.height = CORE.Window.display.height;
|
||||
|
||||
|
||||
@@ -437,7 +437,7 @@ void PollInputEvents(void)
|
||||
{
|
||||
#if SUPPORT_GESTURES_SYSTEM
|
||||
// NOTE: Gestures update must be called every frame to reset gestures correctly
|
||||
// because ProcessGestureEvent() is just called on an event, not every frame
|
||||
// because ProcessGestureEvent() is called on an event, not every frame
|
||||
UpdateGestures();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -407,7 +407,7 @@ void PollInputEvents(void)
|
||||
{
|
||||
#if SUPPORT_GESTURES_SYSTEM
|
||||
// NOTE: Gestures update must be called every frame to reset gestures correctly
|
||||
// because ProcessGestureEvent() is just called on an event, not every frame
|
||||
// because ProcessGestureEvent() is called on an event, not every frame
|
||||
UpdateGestures();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -803,17 +803,20 @@ void SetClipboardText(const char *text)
|
||||
|
||||
// Async EM_JS to be able to await clickboard read asynchronous function
|
||||
EM_ASYNC_JS(void, RequestClipboardData, (void), {
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
if (navigator.clipboard && window.isSecureContext)
|
||||
{
|
||||
let items = await navigator.clipboard.read();
|
||||
for (const item of items) {
|
||||
|
||||
for (const item of items)
|
||||
{
|
||||
// Check if this item contains plain text or image
|
||||
if (item.types.includes("text/plain")) {
|
||||
if (item.types.includes("text/plain"))
|
||||
{
|
||||
const blob = await item.getType("text/plain");
|
||||
const text = await blob.text();
|
||||
window._lastClipboardString = text;
|
||||
}
|
||||
else if (item.types.find(t => t.startsWith("image/"))) {
|
||||
else if (item.types.find(t => t.startsWith("image/")))
|
||||
{
|
||||
const blob = await item.getType(item.types.find(t => t.startsWith("image/")));
|
||||
const bitmap = await createImageBitmap(blob);
|
||||
|
||||
@@ -831,16 +834,16 @@ EM_ASYNC_JS(void, RequestClipboardData, (void), {
|
||||
window._lastImgData = imgData;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.warn("Clipboard read() requires HTTPS/Localhost");
|
||||
}
|
||||
}
|
||||
else console.warn("Clipboard read() requires HTTPS/Localhost");
|
||||
});
|
||||
|
||||
// Returns the string created by RequestClipboardData from JS memory to Emscripten C memory
|
||||
EM_JS(char*, GetLastPastedText, (void), {
|
||||
EM_JS(char *, GetLastPastedText, (void), {
|
||||
var str = window._lastClipboardString || "";
|
||||
var length = lengthBytesUTF8(str) + 1;
|
||||
if (length > 1) {
|
||||
if (length > 1)
|
||||
{
|
||||
var ptr = _malloc(length);
|
||||
stringToUTF8(str, ptr, length);
|
||||
return ptr;
|
||||
@@ -849,10 +852,12 @@ EM_JS(char*, GetLastPastedText, (void), {
|
||||
});
|
||||
|
||||
// Returns the image created by RequestClipboardData from JS memory to Emscripten C memory
|
||||
EM_JS(unsigned char*, GetLastPastedImage, (int* width, int* height), {
|
||||
if (window._lastImgData) {
|
||||
EM_JS(unsigned char *, GetLastPastedImage, (int *width, int *height), {
|
||||
if (window._lastImgData)
|
||||
{
|
||||
const data = window._lastImgData;
|
||||
if (data.length > 0) {
|
||||
if (data.length > 0)
|
||||
{
|
||||
const ptr = _malloc(data.length);
|
||||
HEAPU8.set(data, ptr);
|
||||
|
||||
@@ -861,12 +866,13 @@ EM_JS(unsigned char*, GetLastPastedImage, (int* width, int* height), {
|
||||
if (width) setValue(width, window._lastImgWidth, 'i32');
|
||||
if (height) setValue(height, window._lastImgHeight, 'i32');
|
||||
|
||||
// Clear the JS buffer so we don't fetch the same image twice
|
||||
// Clear the JS buffer so there is no need to fetch the same image twice
|
||||
window._lastImgData = null;
|
||||
|
||||
return ptr;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
@@ -1072,7 +1078,7 @@ void PollInputEvents(void)
|
||||
{
|
||||
#if SUPPORT_GESTURES_SYSTEM
|
||||
// NOTE: Gestures update must be called every frame to reset gestures correctly
|
||||
// because ProcessGestureEvent() is just called on an event, not every frame
|
||||
// because ProcessGestureEvent() is called on an event, not every frame
|
||||
UpdateGestures();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -781,17 +781,20 @@ void SetClipboardText(const char *text)
|
||||
|
||||
// Async EM_JS to be able to await clickboard read asynchronous function
|
||||
EM_ASYNC_JS(void, RequestClipboardData, (void), {
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
if (navigator.clipboard && window.isSecureContext)
|
||||
{
|
||||
let items = await navigator.clipboard.read();
|
||||
for (const item of items) {
|
||||
|
||||
for (const item of items)
|
||||
{
|
||||
// Check if this item contains plain text or image
|
||||
if (item.types.includes("text/plain")) {
|
||||
if (item.types.includes("text/plain"))
|
||||
{
|
||||
const blob = await item.getType("text/plain");
|
||||
const text = await blob.text();
|
||||
window._lastClipboardString = text;
|
||||
}
|
||||
else if (item.types.find(t => t.startsWith("image/"))) {
|
||||
else if (item.types.find(t => t.startsWith("image/")))
|
||||
{
|
||||
const blob = await item.getType(item.types.find(t => t.startsWith("image/")));
|
||||
const bitmap = await createImageBitmap(blob);
|
||||
|
||||
@@ -809,16 +812,16 @@ EM_ASYNC_JS(void, RequestClipboardData, (void), {
|
||||
window._lastImgData = imgData;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.warn("Clipboard read() requires HTTPS/Localhost");
|
||||
}
|
||||
}
|
||||
else console.warn("Clipboard read() requires HTTPS/Localhost");
|
||||
});
|
||||
|
||||
// Returns the string created by RequestClipboardData from JS memory to Emscripten C memory
|
||||
EM_JS(char*, GetLastPastedText, (void), {
|
||||
EM_JS(char *, GetLastPastedText, (void), {
|
||||
var str = window._lastClipboardString || "";
|
||||
var length = lengthBytesUTF8(str) + 1;
|
||||
if (length > 1) {
|
||||
if (length > 1)
|
||||
{
|
||||
var ptr = _malloc(length);
|
||||
stringToUTF8(str, ptr, length);
|
||||
return ptr;
|
||||
@@ -827,10 +830,12 @@ EM_JS(char*, GetLastPastedText, (void), {
|
||||
});
|
||||
|
||||
// Returns the image created by RequestClipboardData from JS memory to Emscripten C memory
|
||||
EM_JS(unsigned char*, GetLastPastedImage, (int* width, int* height), {
|
||||
if (window._lastImgData) {
|
||||
EM_JS(unsigned char *, GetLastPastedImage, (int *width, int *height), {
|
||||
if (window._lastImgData)
|
||||
{
|
||||
const data = window._lastImgData;
|
||||
if (data.length > 0) {
|
||||
if (data.length > 0)
|
||||
{
|
||||
const ptr = _malloc(data.length);
|
||||
HEAPU8.set(data, ptr);
|
||||
|
||||
@@ -839,12 +844,13 @@ EM_JS(unsigned char*, GetLastPastedImage, (int* width, int* height), {
|
||||
if (width) setValue(width, window._lastImgWidth, 'i32');
|
||||
if (height) setValue(height, window._lastImgHeight, 'i32');
|
||||
|
||||
// Clear the JS buffer so we don't fetch the same image twice
|
||||
// Clear the JS buffer so there is no need to fetch the same image twice
|
||||
window._lastImgData = null;
|
||||
|
||||
return ptr;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
@@ -1046,7 +1052,7 @@ void PollInputEvents(void)
|
||||
{
|
||||
#if SUPPORT_GESTURES_SYSTEM
|
||||
// NOTE: Gestures update must be called every frame to reset gestures correctly
|
||||
// because ProcessGestureEvent() is just called on an event, not every frame
|
||||
// because ProcessGestureEvent() is called on an event, not every frame
|
||||
UpdateGestures();
|
||||
#endif
|
||||
|
||||
|
||||
64
src/raudio.c
64
src/raudio.c
@@ -26,7 +26,7 @@
|
||||
* #define SUPPORT_FILEFORMAT_XM
|
||||
* #define SUPPORT_FILEFORMAT_MOD
|
||||
* Selected desired fileformats to be supported for loading. Some of those formats are
|
||||
* supported by default, to remove support, just comment unrequired #define in this module
|
||||
* supported by default, to remove support, comment unrequired #define in this module
|
||||
*
|
||||
* DEPENDENCIES:
|
||||
* miniaudio.h - Audio device management lib (https://github.com/mackron/miniaudio)
|
||||
@@ -299,7 +299,7 @@ typedef struct tagBITMAPINFOHEADER {
|
||||
#endif
|
||||
|
||||
#ifndef AUDIO_BUFFER_RESIDUAL_CAPACITY
|
||||
#define AUDIO_BUFFER_RESIDUAL_CAPACITY 8 // In PCM frames. For resampling and pitch shifting.
|
||||
#define AUDIO_BUFFER_RESIDUAL_CAPACITY 8 // In PCM frames, for resampling and pitch shifting
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -406,7 +406,7 @@ static AudioData AUDIO = { // Global AUDIO context
|
||||
// NOTE: Music buffer size is defined by number of samples, independent of sample size and channels number
|
||||
// After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds and a
|
||||
// standard double-buffering system, a 4096 samples buffer has been chosen, it should be enough
|
||||
// In case of music-stalls, just increase this number
|
||||
// In case of music-stalls, increase this number
|
||||
.Buffer.defaultSize = 0,
|
||||
.mixedProcessor = NULL
|
||||
};
|
||||
@@ -601,7 +601,7 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
|
||||
// be consumed. Any residual input frames need to be kept track of to
|
||||
// ensure there are no discontinuities. Since raylib supports pitch
|
||||
// shifting, which is done through resampling, a cache will always be
|
||||
// required. This will be kept relatively small to avoid too much wastage.
|
||||
// required. This will be kept relatively small to avoid too much wastage
|
||||
audioBuffer->converterResidualCount = 0;
|
||||
audioBuffer->converterResidual = (unsigned char*)RL_CALLOC(AUDIO_BUFFER_RESIDUAL_CAPACITY*ma_get_bytes_per_frame(format, channels), 1);
|
||||
|
||||
@@ -721,7 +721,7 @@ void SetAudioBufferPitch(AudioBuffer *buffer, float pitch)
|
||||
if ((buffer != NULL) && (pitch > 0.0f))
|
||||
{
|
||||
ma_mutex_lock(&AUDIO.System.lock);
|
||||
// Pitching is just an adjustment of the sample rate
|
||||
// Pitching is an adjustment of the sample rate
|
||||
// Note that this changes the duration of the sound:
|
||||
// - higher pitches will make the sound faster
|
||||
// - lower pitches make it slower
|
||||
@@ -1046,7 +1046,7 @@ void UnloadSound(Sound sound)
|
||||
|
||||
void UnloadSoundAlias(Sound alias)
|
||||
{
|
||||
// Untrack and unload just the sound buffer, not the sample data, it is shared with the source for the alias
|
||||
// Untrack and unload the sound buffer, not the sample data, it is shared with the source for the alias
|
||||
if (alias.stream.buffer != NULL)
|
||||
{
|
||||
UntrackAudioBuffer(alias.stream.buffer);
|
||||
@@ -2316,7 +2316,7 @@ void DetachAudioStreamProcessor(AudioStream stream, AudioCallback process)
|
||||
|
||||
// Add processor to audio pipeline. Order of processors is important
|
||||
// Works the same way as {Attach,Detach}AudioStreamProcessor() functions, except
|
||||
// these two work on the already mixed output just before sending it to the sound hardware
|
||||
// these two work on the already mixed output before sending it to the sound hardware
|
||||
void AttachAudioMixedProcessor(AudioCallback process)
|
||||
{
|
||||
ma_mutex_lock(&AUDIO.System.lock);
|
||||
@@ -2397,7 +2397,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
|
||||
if (currentSubBufferIndex > 1) return 0;
|
||||
|
||||
// Another thread can update the processed state of buffers, so
|
||||
// just take a copy here to try and avoid potential synchronization problems
|
||||
// take a copy here to try and avoid potential synchronization problems
|
||||
bool isSubBufferProcessed[2] = { 0 };
|
||||
isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0];
|
||||
isSubBufferProcessed[1] = audioBuffer->isSubBufferProcessed[1];
|
||||
@@ -2478,8 +2478,8 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
|
||||
static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, float *framesOut, ma_uint32 frameCount)
|
||||
{
|
||||
// NOTE: Continuously converting data from the AudioBuffer's internal format to the mixing format,
|
||||
// which should be defined by the output format of the data converter.
|
||||
// This is done until frameCount frames have been output.
|
||||
// which should be defined by the output format of the data converter
|
||||
// This is done until frameCount frames have been output
|
||||
ma_uint32 bpf = ma_get_bytes_per_frame(audioBuffer->converter.formatIn, audioBuffer->converter.channelsIn);
|
||||
ma_uint8 inputBuffer[4096] = { 0 };
|
||||
ma_uint32 inputBufferFrameCap = sizeof(inputBuffer)/bpf;
|
||||
@@ -2491,34 +2491,34 @@ static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, f
|
||||
ma_uint64 outputFramesToProcessThisIteration = frameCount - totalOutputFramesProcessed;
|
||||
//ma_uint64 inputFramesToProcessThisIteration = 0;
|
||||
|
||||
// Process any residual input frames from the previous read first.
|
||||
// Process any residual input frames from the previous read first
|
||||
if (audioBuffer->converterResidualCount > 0)
|
||||
{
|
||||
ma_uint64 inputFramesProcessedThisIteration = audioBuffer->converterResidualCount;
|
||||
ma_uint64 outputFramesProcessedThisIteration = outputFramesToProcessThisIteration;
|
||||
ma_data_converter_process_pcm_frames(&audioBuffer->converter, audioBuffer->converterResidual, &inputFramesProcessedThisIteration, runningFramesOut, &outputFramesProcessedThisIteration);
|
||||
|
||||
// Make sure the data in the cache is consumed. This can be optimized to use a cursor instead of a memmove().
|
||||
memmove(audioBuffer->converterResidual, audioBuffer->converterResidual + inputFramesProcessedThisIteration*bpf, (size_t)(AUDIO_BUFFER_RESIDUAL_CAPACITY - inputFramesProcessedThisIteration) * bpf);
|
||||
// Make sure the data in the cache is consumed, this can be optimized to use a cursor instead of a memmove()
|
||||
memmove(audioBuffer->converterResidual, audioBuffer->converterResidual + inputFramesProcessedThisIteration*bpf, (size_t)(AUDIO_BUFFER_RESIDUAL_CAPACITY - inputFramesProcessedThisIteration)*bpf);
|
||||
audioBuffer->converterResidualCount -= (ma_uint32)inputFramesProcessedThisIteration; // Safe cast
|
||||
|
||||
totalOutputFramesProcessed += (ma_uint32)outputFramesProcessedThisIteration; // Safe cast
|
||||
}
|
||||
else
|
||||
{
|
||||
// Getting here means there are no residual frames from the previous read. Fresh data can now be
|
||||
// pulled from the AudioBuffer and processed.
|
||||
// Getting here means there are no residual frames from the previous read
|
||||
// Fresh data can now be pulled from the AudioBuffer and processed
|
||||
//
|
||||
// A best guess needs to be used made to determine how many input frames to pull from the
|
||||
// buffer. There are three possible outcomes: 1) exact; 2) underestimated; 3) overestimated.
|
||||
// A best guess needs to be used made to determine how many input frames to pull from the buffer
|
||||
// There are three possible outcomes: 1) exact; 2) underestimated; 3) overestimated
|
||||
//
|
||||
// When the guess is exactly correct or underestimated there is nothing special to handle - it'll be
|
||||
// handled naturally by the loop.
|
||||
// When the guess is exactly correct or underestimated there is nothing special to handle,
|
||||
// it'll be handled naturally by the loop
|
||||
//
|
||||
// When the guess is overestimated, that's when it gets more complicated. In this case, any overflow
|
||||
// needs to be stored in a buffer for later processing by the next read.
|
||||
ma_uint32 estimatedInputFrameCount = (ma_uint32)(((float)audioBuffer->converter.resampler.sampleRateIn / audioBuffer->converter.resampler.sampleRateOut) * outputFramesToProcessThisIteration);
|
||||
if (estimatedInputFrameCount == 0) estimatedInputFrameCount = 1; // Make sure at least one input frame is read.
|
||||
// When the guess is overestimated, that's when it gets more complicated
|
||||
// In this case, any overflow needs to be stored in a buffer for later processing by the next read
|
||||
ma_uint32 estimatedInputFrameCount = (ma_uint32)(((float)audioBuffer->converter.resampler.sampleRateIn / audioBuffer->converter.resampler.sampleRateOut)*outputFramesToProcessThisIteration);
|
||||
if (estimatedInputFrameCount == 0) estimatedInputFrameCount = 1; // Make sure at least one input frame is read
|
||||
if (estimatedInputFrameCount > inputBufferFrameCap) estimatedInputFrameCount = inputBufferFrameCap;
|
||||
|
||||
ma_uint32 inputFramesInInternalFormatCount = ReadAudioBufferFramesInInternalFormat(audioBuffer, inputBuffer, estimatedInputFrameCount);
|
||||
@@ -2531,17 +2531,17 @@ static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, f
|
||||
|
||||
if (inputFramesInInternalFormatCount > inputFramesProcessedThisIteration)
|
||||
{
|
||||
// Getting here means the estimated input frame count was overestimated. The residual needs
|
||||
// be stored for later use.
|
||||
// Getting here means the estimated input frame count was overestimated
|
||||
// The residual needs be stored for later use
|
||||
ma_uint64 residualFrameCount = inputFramesInInternalFormatCount - inputFramesProcessedThisIteration;
|
||||
|
||||
// A safety check to make sure the capacity of the residual cache is not exceeded.
|
||||
// A safety check to make sure the capacity of the residual cache is not exceeded
|
||||
if (residualFrameCount > AUDIO_BUFFER_RESIDUAL_CAPACITY)
|
||||
{
|
||||
residualFrameCount = AUDIO_BUFFER_RESIDUAL_CAPACITY;
|
||||
}
|
||||
|
||||
memcpy(audioBuffer->converterResidual, inputBuffer + inputFramesProcessedThisIteration*bpf, (size_t)(residualFrameCount * bpf));
|
||||
memcpy(audioBuffer->converterResidual, inputBuffer + inputFramesProcessedThisIteration*bpf, (size_t)(residualFrameCount*bpf));
|
||||
audioBuffer->converterResidualCount = (unsigned int)residualFrameCount;
|
||||
}
|
||||
|
||||
@@ -2559,7 +2559,7 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const
|
||||
{
|
||||
(void)pDevice;
|
||||
|
||||
// Mixing is basically just an accumulation, need to initialize the output buffer to 0
|
||||
// Mixing is basically an accumulation, need to initialize the output buffer to 0
|
||||
memset(pFramesOut, 0, frameCount*pDevice->playback.channels*ma_get_bytes_per_sample(pDevice->playback.format));
|
||||
|
||||
// Using a mutex here for thread-safety which makes things not real-time
|
||||
@@ -2577,7 +2577,7 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const
|
||||
{
|
||||
if (framesRead >= frameCount) break;
|
||||
|
||||
// Just read as much data as possible from the stream
|
||||
// Read as much data as possible from the stream
|
||||
ma_uint32 framesToRead = (frameCount - framesRead);
|
||||
|
||||
while (framesToRead > 0)
|
||||
@@ -2626,7 +2626,7 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const
|
||||
}
|
||||
else
|
||||
{
|
||||
// Should never get here, but just for safety,
|
||||
// Should never get here, but for safety,
|
||||
// move the cursor position back to the start and continue the loop
|
||||
audioBuffer->frameCursorPos = 0;
|
||||
continue;
|
||||
@@ -2651,7 +2651,7 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const
|
||||
ma_mutex_unlock(&AUDIO.System.lock);
|
||||
}
|
||||
|
||||
// Main mixing function, pretty simple in this project, just an accumulation
|
||||
// Main mixing function, pretty simple in this project, only an accumulation
|
||||
// NOTE: framesOut is both an input and an output, it is initially filled with zeros outside of this function
|
||||
static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, AudioBuffer *buffer)
|
||||
{
|
||||
@@ -2739,7 +2739,7 @@ static void UpdateAudioStreamInLockedState(AudioStream stream, const void *data,
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just update whichever sub-buffer is processed
|
||||
// Update whichever sub-buffer is processed
|
||||
subBufferToUpdate = (stream.buffer->isSubBufferProcessed[0])? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
// NOTE: Set some defines with some data types declared by raylib
|
||||
// Other modules (raymath, rlgl) also require some of those types, so,
|
||||
// to be able to use those other modules as standalone (not depending on raylib)
|
||||
// this defines are very useful for internal check and avoid type (re)definitions
|
||||
// this defines are useful for internal check and avoid type (re)definitions
|
||||
#define RL_COLOR_TYPE
|
||||
#define RL_RECTANGLE_TYPE
|
||||
#define RL_VECTOR2_TYPE
|
||||
@@ -733,7 +733,7 @@ typedef enum {
|
||||
|
||||
// Gamepad buttons
|
||||
typedef enum {
|
||||
GAMEPAD_BUTTON_UNKNOWN = 0, // Unknown button, just for error checking
|
||||
GAMEPAD_BUTTON_UNKNOWN = 0, // Unknown button, for error checking
|
||||
GAMEPAD_BUTTON_LEFT_FACE_UP, // Gamepad left DPAD up button
|
||||
GAMEPAD_BUTTON_LEFT_FACE_RIGHT, // Gamepad left DPAD right button
|
||||
GAMEPAD_BUTTON_LEFT_FACE_DOWN, // Gamepad left DPAD down button
|
||||
@@ -878,7 +878,7 @@ typedef enum {
|
||||
// NOTE 1: Filtering considers mipmaps if available in the texture
|
||||
// NOTE 2: Filter is accordingly set for minification and magnification
|
||||
typedef enum {
|
||||
TEXTURE_FILTER_POINT = 0, // No filter, just pixel approximation
|
||||
TEXTURE_FILTER_POINT = 0, // No filter, pixel approximation
|
||||
TEXTURE_FILTER_BILINEAR, // Linear filtering
|
||||
TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps)
|
||||
TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x
|
||||
|
||||
@@ -567,15 +567,9 @@ RMAPI Vector2 Vector2ClampValue(Vector2 v, float min, float max)
|
||||
{
|
||||
length = sqrtf(length);
|
||||
|
||||
float scale = 1; // By default, 1 as the neutral element.
|
||||
if (length < min)
|
||||
{
|
||||
scale = min/length;
|
||||
}
|
||||
else if (length > max)
|
||||
{
|
||||
scale = max/length;
|
||||
}
|
||||
float scale = 1; // By default, 1 as the neutral element
|
||||
if (length < min) scale = min/length;
|
||||
else if (length > max) scale = max/length;
|
||||
|
||||
result.x = v.x*scale;
|
||||
result.y = v.y*scale;
|
||||
@@ -1215,15 +1209,9 @@ RMAPI Vector3 Vector3ClampValue(Vector3 v, float min, float max)
|
||||
{
|
||||
length = sqrtf(length);
|
||||
|
||||
float scale = 1; // By default, 1 as the neutral element.
|
||||
if (length < min)
|
||||
{
|
||||
scale = min/length;
|
||||
}
|
||||
else if (length > max)
|
||||
{
|
||||
scale = max/length;
|
||||
}
|
||||
float scale = 1; // By default, 1 as the neutral element
|
||||
if (length < min) scale = min/length;
|
||||
else if (length > max) scale = max/length;
|
||||
|
||||
result.x = v.x*scale;
|
||||
result.y = v.y*scale;
|
||||
@@ -2574,8 +2562,8 @@ RMAPI void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle
|
||||
}
|
||||
else
|
||||
{
|
||||
// This occurs when the angle is zero.
|
||||
// Not a problem: just set an arbitrary normalized axis.
|
||||
// This occurs when the angle is zero
|
||||
// Not a problem, set an arbitrary normalized axis
|
||||
resAxis.x = 1.0f;
|
||||
}
|
||||
|
||||
@@ -2702,10 +2690,10 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio
|
||||
translation->y = mat.m13;
|
||||
translation->z = mat.m14;
|
||||
|
||||
// Matrix Columns - Rotation will be extracted into here.
|
||||
Vector3 matColumns[3] = { { mat.m0, mat.m4, mat.m8 },
|
||||
// Matrix Columns - Rotation will be extracted into here
|
||||
Vector3 matColumns[3] = {{ mat.m0, mat.m4, mat.m8 },
|
||||
{ mat.m1, mat.m5, mat.m9 },
|
||||
{ mat.m2, mat.m6, mat.m10 } };
|
||||
{ mat.m2, mat.m6, mat.m10 }};
|
||||
|
||||
// Shear Parameters XY, XZ, and YZ (extract and ignored)
|
||||
float shear[3] = { 0 };
|
||||
@@ -2756,7 +2744,7 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio
|
||||
shear[2] /= scl.z; // Correct YZ shear
|
||||
}
|
||||
|
||||
// matColumns are now orthonormal in O(3). Now ensure its in SO(3) by enforcing det = 1.
|
||||
// matColumns are now orthonormal in O(3). Now ensure its in SO(3) by enforcing det = 1
|
||||
if (Vector3DotProduct(matColumns[0], Vector3CrossProduct(matColumns[1], matColumns[2])) < 0)
|
||||
{
|
||||
scl = Vector3Negate(scl);
|
||||
|
||||
@@ -365,7 +365,7 @@ void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTa
|
||||
if (lockView)
|
||||
{
|
||||
// In these camera modes, clamp the Pitch angle
|
||||
// to allow only viewing straight up or down.
|
||||
// to allow only viewing straight up or down
|
||||
|
||||
// Clamp view up
|
||||
float maxAngleUp = Vector3Angle(up, targetPosition);
|
||||
@@ -460,7 +460,6 @@ void UpdateCamera(Camera *camera, int mode)
|
||||
if (mode == CAMERA_CUSTOM) {}
|
||||
else if (mode == CAMERA_ORBITAL)
|
||||
{
|
||||
// Orbital can just orbit
|
||||
Matrix rotation = MatrixRotate(GetCameraUp(camera), cameraOrbitalSpeed);
|
||||
Vector3 view = Vector3Subtract(camera->position, camera->target);
|
||||
view = Vector3Transform(view, rotation);
|
||||
|
||||
@@ -1841,7 +1841,7 @@ void TakeScreenshot(const char *fileName)
|
||||
// Setup window configuration flags (view FLAGS)
|
||||
// NOTE: This function is expected to be called before window creation,
|
||||
// because it sets up some flags for the window creation process
|
||||
// To configure window states after creation, just use SetWindowState()
|
||||
// To configure window states after creation, use SetWindowState()
|
||||
void SetConfigFlags(unsigned int flags)
|
||||
{
|
||||
if (CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetConfigFlags called after window initialization, Use \"SetWindowState\" to set flags instead");
|
||||
|
||||
12
src/rlgl.h
12
src/rlgl.h
@@ -43,7 +43,7 @@
|
||||
* #define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT
|
||||
* Enable debug context (only available on OpenGL 4.3)
|
||||
*
|
||||
* rlgl capabilities could be customized just defining some internal
|
||||
* rlgl capabilities could be customized defining some internal
|
||||
* values before library inclusion (default values listed):
|
||||
*
|
||||
* #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 8192 // Default internal render batch elements limits
|
||||
@@ -396,7 +396,7 @@ typedef struct rlVertexBuffer {
|
||||
|
||||
// Draw call type
|
||||
// NOTE: Only texture changes register a new draw, other state-change-related elements are not
|
||||
// used at this moment (vaoId, shaderId, matrices), raylib just forces a batch draw call if any
|
||||
// used at this moment (vaoId, shaderId, matrices), raylib forces a batch draw call if any
|
||||
// of those state-change happens (this is done in core module)
|
||||
typedef struct rlDrawCall {
|
||||
int mode; // Drawing mode: LINES, TRIANGLES, QUADS
|
||||
@@ -478,7 +478,7 @@ typedef enum {
|
||||
// NOTE 1: Filtering considers mipmaps if available in the texture
|
||||
// NOTE 2: Filter is accordingly set for minification and magnification
|
||||
typedef enum {
|
||||
RL_TEXTURE_FILTER_POINT = 0, // No filter, just pixel approximation
|
||||
RL_TEXTURE_FILTER_POINT = 0, // No filter, pixel approximation
|
||||
RL_TEXTURE_FILTER_BILINEAR, // Linear filtering
|
||||
RL_TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps)
|
||||
RL_TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x
|
||||
@@ -3356,7 +3356,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
|
||||
}
|
||||
|
||||
// Texture parameters configuration
|
||||
// NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used
|
||||
// NOTE: glTexParameteri does NOT affect texture uploading
|
||||
#if defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// NOTE: OpenGL ES 2.0 with no GL_OES_texture_npot support (i.e. WebGL) has limited NPOT support, so CLAMP_TO_EDGE must be used
|
||||
if (RLGL.ExtSupported.texNPOT)
|
||||
@@ -3741,7 +3741,7 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format)
|
||||
// Two possible Options:
|
||||
// 1 - Bind texture to color fbo attachment and glReadPixels()
|
||||
// 2 - Create an fbo, activate it, render quad with texture, glReadPixels()
|
||||
// Using Option 1, just need to care for texture format on retrieval
|
||||
// Using Option 1, care for texture format on retrieval
|
||||
// NOTE: This behaviour could be conditioned by graphic driver...
|
||||
unsigned int fboId = rlLoadFramebuffer();
|
||||
|
||||
@@ -4199,7 +4199,7 @@ unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode)
|
||||
if (fsCode != NULL) fragmentShaderId = rlCompileShader(fsCode, GL_FRAGMENT_SHADER);
|
||||
else fragmentShaderId = RLGL.State.defaultFShaderId;
|
||||
|
||||
// In case vertex and fragment shader are the default ones, no need to recompile, just assign the default shader program id
|
||||
// In case vertex and fragment shader are the default ones, no need to recompile, assign the default shader program id
|
||||
if ((vertexShaderId == RLGL.State.defaultVShaderId) && (fragmentShaderId == RLGL.State.defaultFShaderId)) id = RLGL.State.defaultShaderId;
|
||||
else if ((vertexShaderId > 0) && (fragmentShaderId > 0))
|
||||
{
|
||||
|
||||
112
src/rmodels.c
112
src/rmodels.c
@@ -792,13 +792,9 @@ void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int
|
||||
{
|
||||
for (int j = 0; j < slices; j++)
|
||||
{
|
||||
// Building up the rings from capCenter in the direction of the 'direction' vector computed earlier
|
||||
|
||||
// we build up the rings from capCenter in the direction of the 'direction' vector we computed earlier
|
||||
|
||||
// as we iterate through the rings they must be placed higher above the center, the height we need is sin(angle(i))
|
||||
// as we iterate through the rings they must get smaller by the cos(angle(i))
|
||||
|
||||
// compute the four vertices
|
||||
// Compute the four vertices
|
||||
float ringSin1 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
|
||||
float ringCos1 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
|
||||
Vector3 w1 = (Vector3){
|
||||
@@ -935,13 +931,9 @@ void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices
|
||||
{
|
||||
for (int j = 0; j < slices; j++)
|
||||
{
|
||||
// Building up the rings from capCenter in the direction of the 'direction' vector computed earlier
|
||||
|
||||
// we build up the rings from capCenter in the direction of the 'direction' vector we computed earlier
|
||||
|
||||
// as we iterate through the rings they must be placed higher above the center, the height we need is sin(angle(i))
|
||||
// as we iterate through the rings they must get smaller by the cos(angle(i))
|
||||
|
||||
// compute the four vertices
|
||||
// Compute the four vertices
|
||||
float ringSin1 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
|
||||
float ringCos1 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle*( i + 0 ));
|
||||
Vector3 w1 = (Vector3){
|
||||
@@ -1147,7 +1139,7 @@ Model LoadModel(const char *fileName)
|
||||
|
||||
// Load model from generated mesh
|
||||
// WARNING: A shallow copy of mesh is generated, passed by value,
|
||||
// as long as struct contains pointers to data and some values, we get a copy
|
||||
// as long as struct contains pointers to data and some values, get a copy
|
||||
// of mesh pointing to same data as original version... be careful!
|
||||
Model LoadModelFromMesh(Mesh mesh)
|
||||
{
|
||||
@@ -1194,7 +1186,7 @@ bool IsModelValid(Model model)
|
||||
if ((model.meshes[i].boneIndices != NULL) && (model.meshes[i].vboId[7] == 0)) { result = false; break; } // Vertex boneIndices buffer not uploaded to GPU
|
||||
if ((model.meshes[i].boneWeights != NULL) && (model.meshes[i].vboId[8] == 0)) { result = false; break; } // Vertex boneWeights buffer not uploaded to GPU
|
||||
|
||||
// NOTE: Some OpenGL versions do not support VAO, so we don't check it
|
||||
// NOTE: Some OpenGL versions do not support VAO, so avoid below check
|
||||
//if (model.meshes[i].vaoId == 0) { result = false; break }
|
||||
}
|
||||
|
||||
@@ -1211,7 +1203,7 @@ void UnloadModel(Model model)
|
||||
|
||||
// Unload materials maps
|
||||
// NOTE: As the user could be sharing shaders and textures between models,
|
||||
// we don't unload the material but just free its maps,
|
||||
// don't unload the material but free its maps,
|
||||
// the user is responsible for freeing models shaders and textures
|
||||
for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps);
|
||||
|
||||
@@ -1510,8 +1502,8 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
||||
}
|
||||
|
||||
// Get a copy of current matrices to work with,
|
||||
// just in case stereo render is required, and we need to modify them
|
||||
// NOTE: At this point the modelview matrix just contains the view matrix (camera)
|
||||
// in case stereo render is required, and they need to be modified
|
||||
// NOTE: At this point the modelview matrix contains the view matrix (camera)
|
||||
// That's because BeginMode3D() sets it and there is no model-drawing function
|
||||
// that modifies it, all use rlPushMatrix() and rlPopMatrix()
|
||||
Matrix matModel = MatrixIdentity();
|
||||
@@ -1729,8 +1721,8 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
|
||||
}
|
||||
|
||||
// Get a copy of current matrices to work with,
|
||||
// just in case stereo render is required, and we need to modify them
|
||||
// NOTE: At this point the modelview matrix just contains the view matrix (camera)
|
||||
// in case stereo render is required, and they need to be modified
|
||||
// NOTE: At this point the modelview matrix contains the view matrix (camera)
|
||||
// That's because BeginMode3D() sets it and there is no model-drawing function
|
||||
// that modifies it, all use rlPushMatrix() and rlPopMatrix()
|
||||
Matrix matModel = MatrixIdentity();
|
||||
@@ -1753,7 +1745,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
|
||||
|
||||
// This could alternatively use a static VBO and either glMapBuffer() or glBufferSubData()
|
||||
// It isn't clear which would be reliably faster in all cases and on all platforms,
|
||||
// anecdotally glMapBuffer() seems very slow (syncs) while glBufferSubData() seems
|
||||
// anecdotally glMapBuffer() seems quite slow (syncs) while glBufferSubData() seems
|
||||
// no faster, since all the transform matrices are transferred anyway
|
||||
instancesVboId = rlLoadVertexBuffer(instanceTransform, instances*sizeof(float16), false);
|
||||
|
||||
@@ -2508,7 +2500,7 @@ static void UpdateModelAnimationVertexBuffers(Model model)
|
||||
bufferUpdateRequired = true;
|
||||
|
||||
// Normals processing
|
||||
// NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
|
||||
// NOTE: Using meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
|
||||
if ((mesh.normals != NULL) && (mesh.animNormals != NULL ))
|
||||
{
|
||||
animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
|
||||
@@ -3375,7 +3367,7 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
|
||||
Vector2 *mapTexcoords = (Vector2 *)RL_MALLOC(maxTriangles*3*sizeof(Vector2));
|
||||
Vector3 *mapNormals = (Vector3 *)RL_MALLOC(maxTriangles*3*sizeof(Vector3));
|
||||
|
||||
// Define the 6 normals of the cube, we will combine them accordingly later...
|
||||
// Define the 6 normals of the cube, combined accordingly later
|
||||
Vector3 n1 = { 1.0f, 0.0f, 0.0f };
|
||||
Vector3 n2 = { -1.0f, 0.0f, 0.0f };
|
||||
Vector3 n3 = { 0.0f, 1.0f, 0.0f };
|
||||
@@ -3383,7 +3375,8 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
|
||||
Vector3 n5 = { 0.0f, 0.0f, -1.0f };
|
||||
Vector3 n6 = { 0.0f, 0.0f, 1.0f };
|
||||
|
||||
// NOTE: We use texture rectangles to define different textures for top-bottom-front-back-right-left (6)
|
||||
// NOTE: Using texture rectangles to define different
|
||||
// textures for top-bottom-front-back-right-left (6)
|
||||
typedef struct RectangleF {
|
||||
float x;
|
||||
float y;
|
||||
@@ -3402,7 +3395,7 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
|
||||
{
|
||||
for (int x = 0; x < cubicmap.width; x++)
|
||||
{
|
||||
// Define the 8 vertex of the cube, we will combine them accordingly later...
|
||||
// Define the 8 vertex of the cube, to be combined accordingly later
|
||||
Vector3 v1 = { w*(x - 0.5f), h2, h*(z - 0.5f) };
|
||||
Vector3 v2 = { w*(x - 0.5f), h2, h*(z + 0.5f) };
|
||||
Vector3 v3 = { w*(x + 0.5f), h2, h*(z + 0.5f) };
|
||||
@@ -3412,7 +3405,7 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
|
||||
Vector3 v7 = { w*(x - 0.5f), 0, h*(z + 0.5f) };
|
||||
Vector3 v8 = { w*(x + 0.5f), 0, h*(z + 0.5f) };
|
||||
|
||||
// We check pixel color to be WHITE -> draw full cube
|
||||
// Check pixel color to be WHITE -> draw full cube
|
||||
if (COLOR_EQUAL(pixels[z*cubicmap.width + x], WHITE))
|
||||
{
|
||||
// Define triangles and checking collateral cubes
|
||||
@@ -3589,7 +3582,7 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
|
||||
tcCounter += 6;
|
||||
}
|
||||
}
|
||||
// We check pixel color to be BLACK, we will only draw floor and roof
|
||||
// Check pixel color to be BLACK, in that case only drawing floor and roof
|
||||
else if (COLOR_EQUAL(pixels[z*cubicmap.width + x], BLACK))
|
||||
{
|
||||
// Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
|
||||
@@ -4106,8 +4099,8 @@ bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, floa
|
||||
{
|
||||
bool collision = false;
|
||||
|
||||
// Simple way to check for collision, just checking distance between two points
|
||||
// Unfortunately, sqrtf() is a costly operation, so we avoid it with following solution
|
||||
// Simple way to check for collision, checking distance between two points
|
||||
// Unfortunately, sqrtf() is a costly operation, so avoid it with following solution
|
||||
/*
|
||||
float dx = center1.x - center2.x; // X distance between centers
|
||||
float dy = center1.y - center2.y; // Y distance between centers
|
||||
@@ -4235,7 +4228,7 @@ RayCollision GetRayCollisionBox(Ray ray, BoundingBox box)
|
||||
// Get vector center point->hit point
|
||||
collision.normal = Vector3Subtract(collision.point, collision.normal);
|
||||
// Scale vector to unit cube
|
||||
// NOTE: We use an additional .01 to fix numerical errors
|
||||
// NOTE: Use an additional .01 to fix numerical errors
|
||||
collision.normal = Vector3Scale(collision.normal, 2.01f);
|
||||
collision.normal = Vector3Divide(collision.normal, Vector3Subtract(box.max, box.min));
|
||||
// The relevant elements of the vector are now slightly larger than 1.0f (or smaller than -1.0f)
|
||||
@@ -4476,7 +4469,7 @@ static Model LoadOBJ(const char *fileName)
|
||||
}
|
||||
else if ((lastMaterial != -1) && (objAttributes.material_ids[faceId] != lastMaterial))
|
||||
{
|
||||
meshIndex++; // If this is a new material, we need to allocate a new mesh
|
||||
meshIndex++; // If this is a new material, a new mesh is allocated
|
||||
}
|
||||
|
||||
lastMaterial = objAttributes.material_ids[faceId];
|
||||
@@ -4492,7 +4485,7 @@ static Model LoadOBJ(const char *fileName)
|
||||
model.materialCount = objMaterialCount;
|
||||
model.materials = (Material *)MemAlloc(sizeof(Material)*objMaterialCount);
|
||||
}
|
||||
else // We must allocate at least one material
|
||||
else // Allocate at least one material
|
||||
{
|
||||
model.materialCount = 1;
|
||||
model.materials = (Material *)MemAlloc(sizeof(Material)*1);
|
||||
@@ -4515,7 +4508,7 @@ static Model LoadOBJ(const char *fileName)
|
||||
// Walk all the faces
|
||||
for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)
|
||||
{
|
||||
bool newMesh = false; // Do we need a new mesh?
|
||||
bool newMesh = false; // Is a new mesh required?
|
||||
if (faceId >= nextShapeEnd)
|
||||
{
|
||||
// Try to find the last vert in the next shape
|
||||
@@ -4585,7 +4578,7 @@ static Model LoadOBJ(const char *fileName)
|
||||
// Walk all the faces
|
||||
for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)
|
||||
{
|
||||
bool newMesh = false; // Do we need a new mesh?
|
||||
bool newMesh = false; // Is a new mesh required?
|
||||
if (faceId >= nextShapeEnd)
|
||||
{
|
||||
// Try to find the last vert in the next shape
|
||||
@@ -4595,7 +4588,7 @@ static Model LoadOBJ(const char *fileName)
|
||||
newMesh = true;
|
||||
}
|
||||
|
||||
// If this is a new material, we need to allocate a new mesh
|
||||
// If this is a new material, a new mesh is allocated
|
||||
if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial) newMesh = true;
|
||||
lastMaterial = objAttributes.material_ids[faceId];
|
||||
|
||||
@@ -4841,7 +4834,7 @@ static Model LoadIQM(const char *fileName)
|
||||
model.meshes[i].indices = (unsigned short *)RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short));
|
||||
|
||||
#if !SUPPORT_GPU_SKINNING
|
||||
// Animated vertex data, what we actually process for rendering
|
||||
// Animated vertex data, processed for rendering
|
||||
// NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning)
|
||||
model.meshes[i].animVertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
|
||||
model.meshes[i].animNormals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
|
||||
@@ -4861,7 +4854,7 @@ static Model LoadIQM(const char *fileName)
|
||||
for (unsigned int i = imesh[m].first_triangle; i < (imesh[m].first_triangle + imesh[m].num_triangles); i++)
|
||||
{
|
||||
// IQM triangles indexes are stored in counter-clockwise, but raylib processes the index in linear order,
|
||||
// expecting they point to the counter-clockwise vertex triangle, so we need to reverse triangle indexes
|
||||
// expecting they point to the counter-clockwise vertex triangle, so triangle indexes need to be reversed
|
||||
// NOTE: raylib renders vertex data in counter-clockwise order (standard convention) by default
|
||||
model.meshes[m].indices[tcounter + 2] = tri[i].vertex[0] - imesh[m].first_vertex;
|
||||
model.meshes[m].indices[tcounter + 1] = tri[i].vertex[1] - imesh[m].first_vertex;
|
||||
@@ -5496,7 +5489,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
int primitivesCount = 0;
|
||||
bool dracoCompression = false;
|
||||
|
||||
// NOTE: We will load every primitive in the glTF as a separate raylib Mesh
|
||||
// NOTE: Load every primitive in the glTF as a separate raylib Mesh
|
||||
// Determine total number of meshes needed from the node hierarchy
|
||||
for (unsigned int i = 0; i < data->nodes_count; i++)
|
||||
{
|
||||
@@ -5528,7 +5521,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
model.meshCount = primitivesCount;
|
||||
model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
|
||||
|
||||
// NOTE: We keep an extra slot for default material, in case some mesh requires it
|
||||
// NOTE: Keep an extra slot for default material, in case some mesh requires it
|
||||
model.materialCount = (int)data->materials_count + 1;
|
||||
model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
|
||||
model.materials[0] = LoadMaterialDefault(); // Load default material (index: 0)
|
||||
@@ -5684,7 +5677,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
|
||||
for (unsigned int p = 0; p < mesh->primitives_count; p++)
|
||||
{
|
||||
// NOTE: We only support primitives defined by triangles
|
||||
// NOTE: Only support primitives defined by triangles
|
||||
// Other alternatives: points, lines, line_strip, triangle_strip
|
||||
if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue;
|
||||
|
||||
@@ -6067,7 +6060,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
float *temp = (float *)RL_MALLOC(attribute->count*4*sizeof(float));
|
||||
LOAD_ATTRIBUTE(attribute, 4, float, temp);
|
||||
|
||||
// Convert data to raylib color data type (4 bytes), we expect the color data normalized
|
||||
// Convert data to raylib color data type (4 bytes), color data must be normalized
|
||||
for (unsigned int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(temp[c]*255.0f);
|
||||
|
||||
RL_FREE(temp);
|
||||
@@ -6125,7 +6118,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
{
|
||||
// The primitive actually keeps the pointer to the corresponding material,
|
||||
// raylib instead assigns to the mesh the by its index, as loaded in model.materials array
|
||||
// To get the index, we check if material pointers match, and we assign the corresponding index,
|
||||
// To get the index, check if material pointers match, and assign the corresponding index,
|
||||
// skipping index 0, the default material
|
||||
if (&data->materials[m] == mesh->primitives[p].material)
|
||||
{
|
||||
@@ -6187,7 +6180,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
{
|
||||
bool hasJoints = false;
|
||||
|
||||
// NOTE: We only support primitives defined by triangles
|
||||
// NOTE: Only support primitives defined by triangles
|
||||
if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue;
|
||||
|
||||
for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++)
|
||||
@@ -6234,7 +6227,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
boneIdOverflowWarning = true;
|
||||
}
|
||||
|
||||
// Despite the possible overflow, we convert data to unsigned char
|
||||
// Despite the possible overflow, convert data to unsigned char
|
||||
model.meshes[meshIndex].boneIndices[b] = (unsigned char)temp[b];
|
||||
}
|
||||
|
||||
@@ -6284,8 +6277,7 @@ static Model LoadGLTF(const char *fileName)
|
||||
model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||
|
||||
// Load 4 components of float data type into mesh.boneWeights
|
||||
// for cgltf_attribute_type_weights we have:
|
||||
|
||||
// for cgltf_attribute_type_weights:
|
||||
// - data.meshes[0] (256 vertices)
|
||||
// - 256 values, provided as cgltf_type_vec4 of float (4 byte per joint, stride 16)
|
||||
LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].boneWeights)
|
||||
@@ -6296,9 +6288,9 @@ static Model LoadGLTF(const char *fileName)
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we are animated, and the mesh was not given any bone assignments, but is the child of a bone node
|
||||
// in this case we need to fully attach all the verts to the parent bone so it will animate with the bone
|
||||
if (data->skins_count > 0 && !hasJoints && node->parent != NULL && node->parent->mesh == NULL)
|
||||
// Check if animated, and the mesh was not given any bone assignments, but is the child of a bone node
|
||||
// in this case, all the verts need to be attached to the parent bone so it will animate with the bone
|
||||
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++)
|
||||
@@ -6435,7 +6427,7 @@ static bool GetPoseAtTimeGLTF(cgltf_interpolation_type interpolationType, cgltf_
|
||||
}
|
||||
else if (output->type == cgltf_type_vec4)
|
||||
{
|
||||
// Only v4 is for rotations, so we know it's a quaternion
|
||||
// Only v4 is for rotations, so it's a quaternion
|
||||
switch (interpolationType)
|
||||
{
|
||||
case cgltf_interpolation_type_step:
|
||||
@@ -6822,7 +6814,7 @@ static Model LoadM3D(const char *fileName)
|
||||
}
|
||||
else TRACELOG(LOG_INFO, "MODEL: [%s] M3D data loaded successfully: %i faces/%i materials", fileName, m3d->numface, m3d->nummaterial);
|
||||
|
||||
// no face? this is probably just a material library
|
||||
// Check if face is found, if not, probably just a material library
|
||||
if (!m3d->numface)
|
||||
{
|
||||
m3d_free(m3d);
|
||||
@@ -6841,12 +6833,12 @@ static Model LoadM3D(const char *fileName)
|
||||
TRACELOG(LOG_INFO, "MODEL: No materials, putting all meshes in a default material");
|
||||
}
|
||||
|
||||
// We always need a default material, so we add +1
|
||||
// A default material is always required, so adding +1
|
||||
model.materialCount++;
|
||||
|
||||
// Faces must be in non-decreasing materialid order. Verify that quickly, sorting them otherwise
|
||||
// WARNING: Sorting is not needed, valid M3D model files should already be sorted
|
||||
// Just keeping the sorting function for reference (Check PR #3363 #3385)
|
||||
// Keeping the sorting function for reference (Check PR #3363 #3385)
|
||||
/*
|
||||
for (a = 1; a < m3d->numface; a++)
|
||||
{
|
||||
@@ -6902,7 +6894,7 @@ static Model LoadM3D(const char *fileName)
|
||||
mi = m3d->face[i].materialid;
|
||||
|
||||
// Only allocate colors VertexBuffer if there's a color vertex in the model for this material batch
|
||||
// if all colors are fully transparent black for all verteces of this materal, then we assume no vertex colors
|
||||
// if all colors are fully transparent black for all verteces of this materal, then assuming no vertex colors
|
||||
for (j = i, l = vcolor = 0; (j < (int)m3d->numface) && (mi == m3d->face[j].materialid); j++, l++)
|
||||
{
|
||||
if (!m3d->vertex[m3d->face[j].vertex[0]].color ||
|
||||
@@ -6916,11 +6908,11 @@ static Model LoadM3D(const char *fileName)
|
||||
model.meshes[k].texcoords = (float *)RL_CALLOC(model.meshes[k].vertexCount*2, sizeof(float));
|
||||
model.meshes[k].normals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
|
||||
|
||||
// If no map is provided, or we have colors defined, we allocate storage for vertex colors
|
||||
// If no map is provided, or colors are defined, allocate storage for vertex colors
|
||||
// M3D specs only consider vertex colors if no material is provided, however raylib uses both and mixes the colors
|
||||
if ((mi == M3D_UNDEF) || vcolor) model.meshes[k].colors = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
|
||||
|
||||
// If no map is provided and we allocated vertex colors, set them to white
|
||||
// If no map is provided and vertex colors are allocated, set them to white
|
||||
if ((mi == M3D_UNDEF) && (model.meshes[k].colors != NULL))
|
||||
{
|
||||
for (int c = 0; c < model.meshes[k].vertexCount*4; c++) model.meshes[k].colors[c] = 255;
|
||||
@@ -6951,7 +6943,7 @@ static Model LoadM3D(const char *fileName)
|
||||
model.meshes[k].vertices[l*9 + 7] = m3d->vertex[m3d->face[i].vertex[2]].y*m3d->scale;
|
||||
model.meshes[k].vertices[l*9 + 8] = m3d->vertex[m3d->face[i].vertex[2]].z*m3d->scale;
|
||||
|
||||
// Without vertex color (full transparency), we use the default color
|
||||
// Without vertex color (full transparency), using the default color
|
||||
if (model.meshes[k].colors != NULL)
|
||||
{
|
||||
if (m3d->vertex[m3d->face[i].vertex[0]].color & 0xff000000)
|
||||
@@ -6992,7 +6984,7 @@ static Model LoadM3D(const char *fileName)
|
||||
{
|
||||
int skinid = m3d->vertex[m3d->face[i].vertex[n]].skinid;
|
||||
|
||||
// Check if there is a skin for this mesh, should be, just failsafe
|
||||
// Check if there is a skin for this mesh
|
||||
if ((skinid != M3D_UNDEF) && (skinid < (int)m3d->numskin))
|
||||
{
|
||||
for (j = 0; j < 4; j++)
|
||||
@@ -7003,8 +6995,8 @@ static Model LoadM3D(const char *fileName)
|
||||
}
|
||||
else
|
||||
{
|
||||
// raylib does not handle boneless meshes with skeletal animations, so
|
||||
// we put all vertices without a bone into a special "no bone" bone
|
||||
// Boneless meshes with skeletal animations are not supported, so
|
||||
// putting all vertices without a bone into a special "no bone" bone
|
||||
model.meshes[k].boneIndices[l*12 + n*4] = m3d->numbone;
|
||||
model.meshes[k].boneWeights[l*12 + n*4] = 1.0f;
|
||||
}
|
||||
@@ -7215,7 +7207,7 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCou
|
||||
bones[i].parent = -1;
|
||||
memcpy(bones[i].name, "NO BONE", 7);
|
||||
|
||||
// M3D stores frames at arbitrary intervals with sparse skeletons. We need full skeletons at
|
||||
// M3D stores frames at arbitrary intervals with sparse skeletons; Full skeletons is required at
|
||||
// regular intervals, so let the M3D SDK do the heavy lifting and calculate interpolated bones
|
||||
for (i = 0; i < animations[a].keyframeCount; i++)
|
||||
{
|
||||
|
||||
@@ -1946,7 +1946,7 @@ void DrawSplineBezierCubic(const Vector2 *points, int pointCount, float thick, C
|
||||
// Draw spline segment: Linear, 2 points
|
||||
void DrawSplineSegmentLinear(Vector2 p1, Vector2 p2, float thick, Color color)
|
||||
{
|
||||
// NOTE: For the linear spline no subdivisions are used, just a single quad
|
||||
// NOTE: For the linear spline no subdivisions are used, only a single quad
|
||||
|
||||
Vector2 delta = { p2.x - p1.x, p2.y - p1.y };
|
||||
float length = sqrtf(delta.x*delta.x + delta.y*delta.y);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* #define SUPPORT_FILEFORMAT_TTF
|
||||
* #define SUPPORT_FILEFORMAT_BDF
|
||||
* Selected desired fileformats to be supported for loading. Some of those formats are
|
||||
* supported by default, to remove support, just comment unrequired #define in this module
|
||||
* supported by default, to remove support, comment unrequired #define in this module
|
||||
*
|
||||
* #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
|
||||
* TextSplit() function static buffer max size
|
||||
@@ -157,7 +157,7 @@ extern void LoadFontDefault(void)
|
||||
#define BIT_CHECK(a,b) ((a) & (1u << (b)))
|
||||
|
||||
// Check to see if the font for an image has alreeady been allocated,
|
||||
// and if no need to upload, then just return
|
||||
// and if no need to upload, then return
|
||||
if (defaultFont.glyphs != NULL) return;
|
||||
|
||||
// NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* #define SUPPORT_FILEFORMAT_PVR
|
||||
* #define SUPPORT_FILEFORMAT_ASTC
|
||||
* Select desired fileformats to be supported for image data loading. Some of those formats are
|
||||
* supported by default, to remove support, just comment unrequired #define in this module
|
||||
* supported by default, to remove support, comment unrequired #define in this module
|
||||
*
|
||||
* #define SUPPORT_IMAGE_EXPORT
|
||||
* Support image export in multiple file formats
|
||||
@@ -1870,7 +1870,7 @@ void ImageToPOT(Image *image, Color fill)
|
||||
if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
|
||||
|
||||
// Calculate next power-of-two values
|
||||
// NOTE: Just add the required amount of pixels at the right and bottom sides of image...
|
||||
// NOTE: Add the required amount of pixels at the right and bottom sides of image...
|
||||
int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2)));
|
||||
int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2)));
|
||||
|
||||
@@ -2014,7 +2014,7 @@ void ImageAlphaMask(Image *image, Image alphaMask)
|
||||
Image mask = ImageCopy(alphaMask);
|
||||
if (mask.format != PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ImageFormat(&mask, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE);
|
||||
|
||||
// In case image is only grayscale, just add alpha channel
|
||||
// In case image is only grayscale, add alpha channel
|
||||
if (image->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE)
|
||||
{
|
||||
unsigned char *data = (unsigned char *)RL_MALLOC(image->width*image->height*2);
|
||||
@@ -2589,7 +2589,7 @@ void ImageFlipHorizontal(Image *image)
|
||||
// OPTION 1: Move pixels with memcpy()
|
||||
//memcpy(flippedData + (y*image->width + x)*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + (image->width - 1 - x))*bytesPerPixel, bytesPerPixel);
|
||||
|
||||
// OPTION 2: Just copy data pixel by pixel
|
||||
// OPTION 2: Copy data pixel by pixel
|
||||
for (int i = 0; i < bytesPerPixel; i++) flippedData[(y*image->width + x)*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + (image->width - 1 - x))*bytesPerPixel + i];
|
||||
}
|
||||
}
|
||||
@@ -4587,10 +4587,10 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2
|
||||
rlSetTexture(0);
|
||||
|
||||
// NOTE: Vertex position can be transformed using matrices
|
||||
// but the process is way more costly than just calculating
|
||||
// but the process is way more costly than calculating
|
||||
// the vertex positions manually, like done above
|
||||
// Old implementation is left here for educational purposes,
|
||||
// just in case someone wants to do some performance test
|
||||
// in case someone wants to do some performance test
|
||||
/*
|
||||
rlSetTexture(texture.id);
|
||||
rlPushMatrix();
|
||||
|
||||
Reference in New Issue
Block a user