Merge branch 'master' into flag-macros

This commit is contained in:
Ray 2025-10-01 18:39:48 +02:00 • committed by GitHub
commit fa4f7a203b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 8138 additions and 586 deletions

View file

@ -235,20 +235,22 @@ endif
# NOTE: By default use OpenGL 3.3 on desktop platforms
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
GRAPHICS ?= GRAPHICS_API_OPENGL_33
#GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1
#GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1
#GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3
#GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
#GRAPHICS = GRAPHICS_API_OPENGL_11_SOFTWARE # Uncomment to use software rendering
#GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1
#GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1
#GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3
#GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL)
GRAPHICS ?= GRAPHICS_API_OPENGL_33
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW)
GRAPHICS ?= GRAPHICS_API_OPENGL_33
#GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1
#GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1
#GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3
#GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
#GRAPHICS = GRAPHICS_API_OPENGL_11_SOFTWARE # Uncomment to use software rendering
#GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1
#GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1
#GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3
#GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
# On DRM OpenGL ES 2.0 must be used

4938
src/external/rlsw.h vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -63,18 +63,20 @@
#include "SDL.h"
#endif
#if defined(GRAPHICS_API_OPENGL_ES2)
// It seems it does not need to be included to work
//#include "SDL_opengles2.h"
#else
// SDL OpenGL functionality (if required, instead of internal renderer)
#ifdef USING_SDL3_PROJECT
#include "SDL3/SDL_opengl.h"
#elif USING_SDL2_PROJECT
#include "SDL2/SDL_opengl.h"
#else
#include "SDL_opengl.h"
#endif
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
#if defined(GRAPHICS_API_OPENGL_ES2)
// It seems it does not need to be included to work
//#include "SDL_opengles2.h"
#else
// SDL OpenGL functionality (if required, instead of internal renderer)
#ifdef USING_SDL3_PROJECT
#include "SDL3/SDL_opengl.h"
#elif USING_SDL2_PROJECT
#include "SDL2/SDL_opengl.h"
#else
#include "SDL_opengl.h"
#endif
#endif
#endif
//----------------------------------------------------------------------------------
@ -1220,7 +1222,14 @@ void DisableCursor(void)
// Swap back buffer with front buffer (screen drawing)
void SwapScreenBuffer(void)
{
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
// NOTE: We use a preprocessor condition here because `rlCopyFramebuffer` is only declared for software rendering
SDL_Surface *surface = SDL_GetWindowSurface(platform.window);
rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, surface->pixels);
SDL_UpdateWindowSurface(platform.window);
#else
SDL_GL_SwapWindow(platform.window);
#endif
}
//----------------------------------------------------------------------------------
@ -1568,13 +1577,15 @@ void PollInputEvents(void)
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
{
// Add character (codepoint) to the queue
#if defined(USING_VERSION_SDL3)
#if defined(USING_VERSION_SDL3)
size_t textLen = strlen(event.text.text);
unsigned int codepoint = (unsigned int)SDL_StepUTF8(&event.text.text, &textLen);
#else
#else
int codepointSize = 0;
int codepoint = GetCodepointNextSDL(event.text.text, &codepointSize);
#endif
#endif
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = codepoint;
CORE.Input.Keyboard.charPressedQueueCount++;
}
@ -1878,7 +1889,6 @@ int InitPlatform(void)
//----------------------------------------------------------------------------
unsigned int flags = 0;
FLAG_SET(flags, SDL_WINDOW_SHOWN);
FLAG_SET(flags, SDL_WINDOW_OPENGL);
FLAG_SET(flags, SDL_WINDOW_INPUT_FOCUS);
FLAG_SET(flags, SDL_WINDOW_MOUSE_FOCUS);
FLAG_SET(flags, SDL_WINDOW_MOUSE_CAPTURE); // Window has mouse captured
@ -1909,44 +1919,50 @@ int InitPlatform(void)
// NOTE: Some OpenGL context attributes must be set before window creation
// Check selection OpenGL version
if (rlGetVersion() == RL_OPENGL_21)
if (rlGetVersion() != RL_OPENGL_11_SOFTWARE)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
}
else if (rlGetVersion() == RL_OPENGL_33)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
}
else if (rlGetVersion() == RL_OPENGL_43)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); // Enable OpenGL Debug Context
#endif
}
else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
}
else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
}
// Add the flag telling the window to use an OpenGL context
flags |= SDL_WINDOW_OPENGL;
if (FLAG_CHECK(CORE.Window.flags, FLAG_MSAA_4X_HINT) > 0)
{
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
// Check selection OpenGL version
if (rlGetVersion() == RL_OPENGL_21)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
}
else if (rlGetVersion() == RL_OPENGL_33)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
}
else if (rlGetVersion() == RL_OPENGL_43)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); // Enable OpenGL Debug Context
#endif
}
else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
}
else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
}
if (FLAG_CHECK(CORE.Window.flags, FLAG_MSAA_4X_HINT) > 0)
{
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
}
}
// Init window
@ -1957,10 +1973,12 @@ int InitPlatform(void)
#endif
// Init OpenGL context
platform.glContext = SDL_GL_CreateContext(platform.window);
if (rlGetVersion() != RL_OPENGL_11_SOFTWARE)
{
platform.glContext = SDL_GL_CreateContext(platform.window);
}
// Check window and glContext have been initialized successfully
if ((platform.window != NULL) && (platform.glContext != NULL))
if ((platform.window != NULL) && ((rlGetVersion() == RL_OPENGL_11_SOFTWARE) || (platform.glContext != NULL)))
{
CORE.Window.ready = true;
@ -1981,8 +1999,14 @@ int InitPlatform(void)
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
if (FLAG_CHECK(CORE.Window.flags, FLAG_VSYNC_HINT) > 0) SDL_GL_SetSwapInterval(1);
else SDL_GL_SetSwapInterval(0);
if (platform.glContext != NULL)
{
SDL_GL_SetSwapInterval((FLAG_CHECK(CORE.Window.flags, FLAG_VSYNC_HINT) > 0)? 1 : 0);
// Load OpenGL extensions
// NOTE: GL procedures address loader is required to load extensions
rlLoadExtensions(SDL_GL_GetProcAddress);
}
}
else
{
@ -1990,9 +2014,6 @@ int InitPlatform(void)
return -1;
}
// Load OpenGL extensions
// NOTE: GL procedures address loader is required to load extensions
rlLoadExtensions(SDL_GL_GetProcAddress);
//----------------------------------------------------------------------------
// Initialize input events system
@ -2064,7 +2085,7 @@ int InitPlatform(void)
void ClosePlatform(void)
{
SDL_FreeCursor(platform.cursor); // Free cursor
SDL_GL_DeleteContext(platform.glContext); // Deinitialize OpenGL context
if (platform.glContext != NULL) SDL_GL_DeleteContext(platform.glContext); // Deinitialize OpenGL context
SDL_DestroyWindow(platform.window);
SDL_Quit(); // Deinitialize SDL internal global state
}

View file

@ -65,12 +65,17 @@
// so the enum KEY_F12 from raylib is used
#undef KEY_F12
#include <gbm.h> // Generic Buffer Management (native platform for EGL on DRM)
#include <xf86drm.h> // Direct Rendering Manager user-level library interface
#include <xf86drmMode.h> // Direct Rendering Manager mode setting (KMS) interface
#include "EGL/egl.h" // Native platform windowing system interface
#include "EGL/eglext.h" // EGL extensions
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
#include <gbm.h> // Generic Buffer Management (native platform for EGL on DRM)
#include "EGL/egl.h" // Native platform windowing system interface
#include "EGL/eglext.h" // EGL extensions
#else
#include <sys/mman.h> // For mmap when copying to the dumb buffer
#include <errno.h> // For the conversion of certain error messages
#endif
// NOTE: DRM cache enables triple buffered DRM caching
#if defined(SUPPORT_DRM_CACHE)
@ -103,15 +108,19 @@ typedef struct {
drmModeConnector *connector; // Direct Rendering Manager (DRM) mode connector
drmModeCrtc *crtc; // CRT Controller
int modeIndex; // Index of the used mode of connector->modes
uint32_t prevFB; // Previous DRM framebufer (during frame swapping)
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
struct gbm_device *gbmDevice; // GBM device
struct gbm_surface *gbmSurface; // GBM surface
struct gbm_bo *prevBO; // Previous GBM buffer object (during frame swapping)
uint32_t prevFB; // Previous GBM framebufer (during frame swapping)
EGLDisplay device; // Native display device (physical screen connection)
EGLSurface surface; // Surface to draw on, framebuffers (connected to context)
EGLContext context; // Graphic context, mode in which drawing can be done
EGLConfig config; // Graphic config
#else
uint32_t prevDumbHandle; // Handle to the previous dumb buffer (during frame swapping)
#endif
// Keyboard data
int defaultKeyboardMode; // Default keyboard mode
@ -780,6 +789,8 @@ void SwapScreenBuffer()
// Swap back buffer with front buffer (screen drawing)
void SwapScreenBuffer(void)
{
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
// Hardware rendering buffer swap with EGL
eglSwapBuffers(platform.device, platform.surface);
if (!platform.gbmSurface || (-1 == platform.fd) || !platform.connector || !platform.crtc) TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap");
@ -805,6 +816,196 @@ void SwapScreenBuffer(void)
if (platform.prevBO) gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO);
platform.prevBO = bo;
#else
// Software rendering buffer swap
if ((platform.fd == -1) || !platform.connector || (platform.modeIndex < 0))
{
TRACELOG(LOG_ERROR, "DISPLAY: DRM initialization failed to swap");
return;
}
// Get the software rendered color buffer
int bufferWidth = 0, bufferHeight = 0;
void *colorBuffer = swGetColorBuffer(&bufferWidth, &bufferHeight);
if (!colorBuffer)
{
TRACELOG(LOG_ERROR, "DISPLAY: Failed to get software color buffer");
return;
}
// Retrieving the dimensions of the display mode used
drmModeModeInfo *mode = &platform.connector->modes[platform.modeIndex];
uint32_t width = mode->hdisplay;
uint32_t height = mode->vdisplay;
// Dumb buffers use a fixed format based on bpp
#if SW_COLOR_BUFFER_BITS == 24
const uint32_t bpp = 32; // 32 bits per pixel (XRGB8888 format)
const uint32_t depth = 24; // Color depth, here only 24 bits, alpha is not used
#else
// REVIEW: Not sure how it will be interpreted (RGB or RGBA?)
const uint32_t bpp = SW_COLOR_BUFFER_BITS;
const uint32_t depth = SW_COLOR_BUFFER_BITS;
#endif
// Create a dumb buffer for software rendering
struct drm_mode_create_dumb creq = { 0 };
creq.width = width;
creq.height = height;
creq.bpp = bpp;
int result = drmIoctl(platform.fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
if (result < 0)
{
TRACELOG(LOG_ERROR, "DISPLAY: Failed to create dumb buffer: %s", strerror(errno));
return;
}
// Create framebuffer with the correct format
uint32_t fb = 0;
result = drmModeAddFB(platform.fd, width, height, depth, bpp, creq.pitch, creq.handle, &fb);
if (result != 0)
{
TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d (%s)", result, strerror(errno));
struct drm_mode_destroy_dumb dreq = { 0 };
dreq.handle = creq.handle;
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
return;
}
// Map the dumb buffer to copy our software rendered buffer
struct drm_mode_map_dumb mreq = { 0 };
mreq.handle = creq.handle;
result = drmIoctl(platform.fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
if (result != 0)
{
TRACELOG(LOG_ERROR, "DISPLAY: Failed to map dumb buffer: %s", strerror(errno));
drmModeRmFB(platform.fd, fb);
struct drm_mode_destroy_dumb dreq = { 0 };
dreq.handle = creq.handle;
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
return;
}
// Map the buffer into userspace
void *dumbBuffer = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, platform.fd, mreq.offset);
if (dumbBuffer == MAP_FAILED)
{
TRACELOG(LOG_ERROR, "DISPLAY: Failed to mmap dumb buffer: %s", strerror(errno));
drmModeRmFB(platform.fd, fb);
struct drm_mode_destroy_dumb dreq = { 0 };
dreq.handle = creq.handle;
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
return;
}
// Copy the software rendered buffer to the dumb buffer with scaling if needed
if (bufferWidth == width && bufferHeight == height)
{
// Direct copy if sizes match
swCopyFramebuffer(0, 0, bufferWidth, bufferHeight, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
}
else
{
// Scale the software buffer to match the display mode
swBlitFramebuffer(0, 0, width, height, 0, 0, bufferWidth, bufferHeight, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
}
// Unmap the buffer
munmap(dumbBuffer, creq.size);
// Find a CRTC compatible with the connector
uint32_t crtcId = 0;
if (platform.crtc) crtcId = platform.crtc->crtc_id;
else
{
// Find a CRTC that's compatible with this connector
drmModeRes *res = drmModeGetResources(platform.fd);
if (!res)
{
TRACELOG(LOG_ERROR, "DISPLAY: Failed to get DRM resources");
drmModeRmFB(platform.fd, fb);
struct drm_mode_destroy_dumb dreq = {0};
dreq.handle = creq.handle;
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
return;
}
// Check which CRTCs are compatible with this connector
drmModeEncoder *encoder = NULL;
if (platform.connector->encoder_id) encoder = drmModeGetEncoder(platform.fd, platform.connector->encoder_id);
if (encoder && encoder->crtc_id)
{
crtcId = encoder->crtc_id;
platform.crtc = drmModeGetCrtc(platform.fd, crtcId);
}
else
{
// Find a free CRTC
for (int i = 0; i < res->count_crtcs; i++)
{
drmModeCrtc *crtc = drmModeGetCrtc(platform.fd, res->crtcs[i]);
if (crtc && !crtc->buffer_id) // CRTC is free
{
crtcId = res->crtcs[i];
if (platform.crtc) drmModeFreeCrtc(platform.crtc);
platform.crtc = crtc;
break;
}
if (crtc) drmModeFreeCrtc(crtc);
}
}
if (encoder) drmModeFreeEncoder(encoder);
drmModeFreeResources(res);
if (!crtcId)
{
TRACELOG(LOG_ERROR, "DISPLAY: No compatible CRTC found");
drmModeRmFB(platform.fd, fb);
struct drm_mode_destroy_dumb dreq = {0};
dreq.handle = creq.handle;
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
return;
}
}
// Set CRTC with better error handling
result = drmModeSetCrtc(platform.fd, crtcId, fb, 0, 0, &platform.connector->connector_id, 1, mode);
if (result != 0)
{
TRACELOG(LOG_ERROR, "DISPLAY: drmModeSetCrtc() failed with result: %d (%s)", result, strerror(errno));
TRACELOG(LOG_ERROR, "DISPLAY: CRTC ID: %u, FB ID: %u, Connector ID: %u", crtcId, fb, platform.connector->connector_id);
TRACELOG(LOG_ERROR, "DISPLAY: Mode: %dx%d@%d", mode->hdisplay, mode->vdisplay, mode->vrefresh);
drmModeRmFB(platform.fd, fb);
struct drm_mode_destroy_dumb dreq = {0};
dreq.handle = creq.handle;
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
return;
}
// Clean up previous framebuffer
if (platform.prevFB)
{
result = drmModeRmFB(platform.fd, platform.prevFB);
if (result != 0) TRACELOG(LOG_WARNING, "DISPLAY: drmModeRmFB() failed with result: %d", result);
}
platform.prevFB = fb;
// Clean up previous dumb buffer
if (platform.prevDumbHandle)
{
struct drm_mode_destroy_dumb dreq = {0};
dreq.handle = platform.prevDumbHandle;
drmIoctl(platform.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
}
platform.prevDumbHandle = creq.handle;
#endif
}
#endif // SUPPORT_DRM_CACHE
@ -950,10 +1151,15 @@ int InitPlatform(void)
platform.connector = NULL;
platform.modeIndex = -1;
platform.crtc = NULL;
platform.prevFB = 0;
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
platform.gbmDevice = NULL;
platform.gbmSurface = NULL;
platform.prevBO = NULL;
platform.prevFB = 0;
#else
platform.prevDumbHandle = 0;
#endif
// Initialize graphic device: display/window and graphic context
//----------------------------------------------------------------------------
@ -965,11 +1171,12 @@ int InitPlatform(void)
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: Default graphic device DRM opened successfully");
#else
TRACELOG(LOG_WARNING, "DISPLAY: No graphic card set, trying platform-gpu-card");
platform.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4)
platform.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4)
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: platform-gpu-card opened successfully");
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
{
if (platform.fd != -1) close(platform.fd);
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open platform-gpu-card, trying card1");
platform.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card1 opened successfully");
@ -977,10 +1184,19 @@ int InitPlatform(void)
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
{
if (platform.fd != -1) close(platform.fd);
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card1, trying card0");
platform.fd = open("/dev/dri/card0", O_RDWR); // VideoCore IV (Raspberry Pi 1-3)
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card0 opened successfully");
}
if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
{
if (platform.fd != -1) close(platform.fd);
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card0, trying card2");
platform.fd = open("/dev/dri/card2", O_RDWR);
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card2 opened successfully");
}
#endif
if (platform.fd == -1)
@ -993,29 +1209,55 @@ int InitPlatform(void)
if (!res)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed get DRM resources");
close(platform.fd);
return -1;
}
TRACELOG(LOG_TRACE, "DISPLAY: Connectors found: %i", res->count_connectors);
// Connector detection
for (size_t i = 0; i < res->count_connectors; i++)
{
TRACELOG(LOG_TRACE, "DISPLAY: Connector index %i", i);
drmModeConnector *con = drmModeGetConnector(platform.fd, res->connectors[i]);
TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes);
if (!con)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get connector %i", i);
continue;
}
TRACELOG(LOG_TRACE, "DISPLAY: Connector %i modes detected: %i", i, con->count_modes);
TRACELOG(LOG_TRACE, "DISPLAY: Connector %i status: %s", i,
(con->connection == DRM_MODE_CONNECTED) ? "CONNECTED" :
(con->connection == DRM_MODE_DISCONNECTED) ? "DISCONNECTED" :
(con->connection == DRM_MODE_UNKNOWNCONNECTION) ? "UNKNOWN" : "OTHER");
// In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected
// This might be a hardware or software limitation like on Raspberry Pi Zero with composite output
if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->encoder_id))
// WARNING: Accept CONNECTED, UNKNOWN and even those without encoder_id connectors for software mode
if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->count_modes > 0))
{
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected");
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
// For hardware rendering, we need an encoder_id
if (con->encoder_id)
{
TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i connected with encoder", i);
platform.connector = con;
break;
}
else TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i connected but no encoder", i);
#else
// For software rendering, we can accept even without encoder_id
TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i suitable for software rendering", i);
platform.connector = con;
break;
#endif
}
else
if (!platform.connector)
{
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode NOT connected (deleting)");
TRACELOG(LOG_TRACE, "DISPLAY: DRM connector %i NOT suitable (deleting)", i);
drmModeFreeConnector(con);
}
}
@ -1024,14 +1266,18 @@ int InitPlatform(void)
{
TRACELOG(LOG_WARNING, "DISPLAY: No suitable DRM connector found");
drmModeFreeResources(res);
close(platform.fd);
return -1;
}
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
drmModeEncoder *enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id);
if (!enc)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder");
drmModeFreeConnector(platform.connector);
drmModeFreeResources(res);
close(platform.fd);
return -1;
}
@ -1040,7 +1286,9 @@ int InitPlatform(void)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc");
drmModeFreeEncoder(enc);
drmModeFreeConnector(platform.connector);
drmModeFreeResources(res);
close(platform.fd);
return -1;
}
@ -1055,7 +1303,9 @@ int InitPlatform(void)
{
TRACELOG(LOG_WARNING, "DISPLAY: No matching DRM connector mode found");
drmModeFreeEncoder(enc);
drmModeFreeConnector(platform.connector);
drmModeFreeResources(res);
close(platform.fd);
return -1;
}
@ -1064,7 +1314,7 @@ int InitPlatform(void)
}
const bool allowInterlaced = FLAG_CHECK(CORE.Window.flags. FLAG_INTERLACED_HINT);
const int fps = (CORE.Time.target > 0)? (1.0/CORE.Time.target) : 60;
const int fps = (CORE.Time.target > 0) ? (1.0/CORE.Time.target) : 60;
// Try to find an exact matching mode
platform.modeIndex = FindExactConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced);
@ -1083,7 +1333,9 @@ int InitPlatform(void)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable DRM connector mode");
drmModeFreeEncoder(enc);
drmModeFreeConnector(platform.connector);
drmModeFreeResources(res);
close(platform.fd);
return -1;
}
@ -1095,16 +1347,42 @@ int InitPlatform(void)
FLAG_CHECK(platform.connector->modes[platform.modeIndex].flags, DRM_MODE_FLAG_INTERLACE)? 'i' : 'p',
platform.connector->modes[platform.modeIndex].vrefresh);
drmModeFreeEncoder(enc);
enc = NULL;
#else
// For software rendering, the first available mode can be used
if (platform.connector->count_modes > 0)
{
platform.modeIndex = 0;
CORE.Window.display.width = platform.connector->modes[0].hdisplay;
CORE.Window.display.height = platform.connector->modes[0].vdisplay;
TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u) for software rendering",
platform.connector->modes[0].name,
platform.connector->modes[0].hdisplay,
platform.connector->modes[0].vdisplay,
(platform.connector->modes[0].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p',
platform.connector->modes[0].vrefresh);
}
else
{
TRACELOG(LOG_WARNING, "DISPLAY: No modes available for connector");
drmModeFreeConnector(platform.connector);
drmModeFreeResources(res);
close(platform.fd);
return -1;
}
#endif
// Use the width and height of the surface for render
CORE.Window.render.width = CORE.Window.screen.width;
CORE.Window.render.height = CORE.Window.screen.height;
drmModeFreeEncoder(enc);
enc = NULL;
drmModeFreeResources(res);
res = NULL;
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
// Hardware rendering initialization with EGL
platform.gbmDevice = gbm_create_device(platform.fd);
if (!platform.gbmDevice)
{
@ -1273,6 +1551,32 @@ int InitPlatform(void)
return -1;
}
// Load OpenGL extensions
// 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
// 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
// -> CORE.Window.screenScale
SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
// Setup window ready state for software rendering
CORE.Window.ready = true;
CORE.Window.render.width = CORE.Window.screen.width;
CORE.Window.render.height = CORE.Window.screen.height;
CORE.Window.currentFbo.width = CORE.Window.render.width;
CORE.Window.currentFbo.height = CORE.Window.render.height;
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully (Software Rendering)");
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
#endif
if (FLAG_CHECK(CORE.Window.flags, FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
// If graphic device is no properly initialized, we end program
@ -1285,12 +1589,8 @@ int InitPlatform(void)
FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // true
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // false
// Load OpenGL extensions
// NOTE: GL procedures address loader is required to load extensions
rlLoadExtensions(eglGetProcAddress);
//----------------------------------------------------------------------------
// Initialize timming system
// Initialize timing system
//----------------------------------------------------------------------------
// NOTE: timming system must be initialized before the input events system
InitTimer();
@ -1336,6 +1636,7 @@ void ClosePlatform(void)
platform.prevFB = 0;
}
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
if (platform.prevBO)
{
gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO);
@ -1353,6 +1654,7 @@ void ClosePlatform(void)
gbm_device_destroy(platform.gbmDevice);
platform.gbmDevice = NULL;
}
#endif
if (platform.crtc)
{
@ -1374,6 +1676,7 @@ void ClosePlatform(void)
platform.fd = -1;
}
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
// Close surface, context and display
if (platform.device != EGL_NO_DISPLAY)
{
@ -1392,6 +1695,7 @@ void ClosePlatform(void)
eglTerminate(platform.device);
platform.device = EGL_NO_DISPLAY;
}
#endif
CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called

View file

@ -1258,6 +1258,7 @@ RLAPI Rectangle GetShapesTextureRectangle(void); // Get texture source re
RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel using geometry [Can be slow, use with care]
RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel using geometry (Vector version) [Can be slow, use with care]
RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line
RLAPI void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int whiteSpaceSize, Color color); // Draw a dashed line
RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (using gl lines)
RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line (using triangles/quads)
RLAPI void DrawLineStrip(const Vector2 *points, int pointCount, Color color); // Draw lines sequence (using gl lines)

View file

@ -149,7 +149,8 @@
#endif
// Security check in case no GRAPHICS_API_OPENGL_* defined
#if !defined(GRAPHICS_API_OPENGL_11) && \
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) && \
!defined(GRAPHICS_API_OPENGL_11) && \
!defined(GRAPHICS_API_OPENGL_21) && \
!defined(GRAPHICS_API_OPENGL_33) && \
!defined(GRAPHICS_API_OPENGL_43) && \
@ -159,7 +160,7 @@
#endif
// Security check in case multiple GRAPHICS_API_OPENGL_* defined
#if defined(GRAPHICS_API_OPENGL_11)
#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
#if defined(GRAPHICS_API_OPENGL_21)
#undef GRAPHICS_API_OPENGL_21
#endif
@ -174,6 +175,11 @@
#endif
#endif
// Software implementation uses OpenGL 1.1 functionality
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
#define GRAPHICS_API_OPENGL_11
#endif
// OpenGL 2.1 uses most of OpenGL 3.3 Core functionality
// WARNING: Specific parts are checked with #if defines
#if defined(GRAPHICS_API_OPENGL_21)
@ -427,7 +433,8 @@ typedef struct rlRenderBatch {
// OpenGL version
typedef enum {
RL_OPENGL_11 = 1, // OpenGL 1.1
RL_OPENGL_11_SOFTWARE = 0, // Software rendering
RL_OPENGL_11, // OpenGL 1.1
RL_OPENGL_21, // OpenGL 2.1 (GLSL 120)
RL_OPENGL_33, // OpenGL 3.3 (GLSL 330)
RL_OPENGL_43, // OpenGL 4.3 (using GLSL 330)
@ -644,10 +651,8 @@ RLAPI void rlEnableVertexBufferElement(unsigned int id); // Enable vertex buffer
RLAPI void rlDisableVertexBufferElement(void); // Disable vertex buffer element (VBO element)
RLAPI void rlEnableVertexAttribute(unsigned int index); // Enable vertex attribute index
RLAPI void rlDisableVertexAttribute(unsigned int index); // Disable vertex attribute index
#if defined(GRAPHICS_API_OPENGL_11)
RLAPI void rlEnableStatePointer(int vertexAttribType, void *buffer); // Enable attribute state pointer
RLAPI void rlDisableStatePointer(int vertexAttribType); // Disable attribute state pointer
#endif
// Textures state
RLAPI void rlActiveTextureSlot(int slot); // Select and active a texture slot
@ -686,6 +691,8 @@ RLAPI void rlDisableScissorTest(void); // Disable scissor test
RLAPI void rlScissor(int x, int y, int width, int height); // Scissor test
RLAPI void rlEnablePointMode(void); // Enable point mode
RLAPI void rlDisablePointMode(void); // Disable point mode
RLAPI void rlSetPointSize(float size); // Set the point drawing size
RLAPI float rlGetPointSize(void); // Get the point drawing size
RLAPI void rlEnableWireMode(void); // Enable wire mode
RLAPI void rlDisableWireMode(void); // Disable wire mode
RLAPI void rlSetLineWidth(float width); // Set the line drawing width
@ -768,6 +775,10 @@ RLAPI unsigned int rlLoadFramebuffer(void); // Loa
RLAPI void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer
RLAPI bool rlFramebufferComplete(unsigned int id); // Verify framebuffer is complete
RLAPI void rlUnloadFramebuffer(unsigned int id); // Delete framebuffer from GPU
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
RLAPI void rlCopyFramebuffer(int x, int y, int width, int height, int format, void *pixels); // Copy framebuffer pixel data to internal buffer
RLAPI void rlResizeFramebuffer(int width, int height); // Resize internal framebuffer
#endif
// Shaders management
RLAPI unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings
@ -834,24 +845,32 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
#endif
#if defined(GRAPHICS_API_OPENGL_11)
#if defined(__APPLE__)
#include <OpenGL/gl.h> // OpenGL 1.1 library for OSX
#include <OpenGL/glext.h> // OpenGL extensions library
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
#define RLSW_IMPLEMENTATION
#define SW_MALLOC(sz) RL_MALLOC(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
#else
// APIENTRY for OpenGL function pointer declarations is required
#if !defined(APIENTRY)
#if defined(_WIN32)
#define APIENTRY __stdcall
#else
#define APIENTRY
#if defined(__APPLE__)
#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)
#if defined(_WIN32)
#define APIENTRY __stdcall
#else
#define APIENTRY
#endif
#endif
// WINGDIAPI definition. Some Windows OpenGL headers need it
#if !defined(WINGDIAPI) && defined(_WIN32)
#define WINGDIAPI __declspec(dllimport)
#endif
#endif
// WINGDIAPI definition. Some Windows OpenGL headers need it
#if !defined(WINGDIAPI) && defined(_WIN32)
#define WINGDIAPI __declspec(dllimport)
#endif
#include <GL/gl.h> // OpenGL 1.1 library
#include <GL/gl.h> // OpenGL 1.1 library
#endif
#endif
#endif
@ -2016,6 +2035,25 @@ float rlGetLineWidth(void)
return width;
}
// Set the point drawing size
void rlSetPointSize(float size)
{
#if defined(GRAPHICS_API_OPENGL_11)
glPointSize(size);
#endif
}
// Get the point drawing size
float rlGetPointSize(void)
{
float size = 1;
#if defined(GRAPHICS_API_OPENGL_11)
glGetFloatv(GL_POINT_SIZE, &size);
#endif
return size;
}
// Enable line aliasing
void rlEnableSmoothLines(void)
{
@ -2318,6 +2356,15 @@ void rlglInit(int width, int height)
glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation)
#endif
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
int result = swInit(width, height); // Initialize software renderer backend
if (result == 0)
{
TRACELOG(RL_LOG_ERROR, "RLSW: Software renderer initialization failed!");
exit(-1);
}
#endif
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Store screen size into global variables
RLGL.State.framebufferWidth = width;
@ -2339,11 +2386,15 @@ void rlglClose(void)
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
rlUnloadRenderBatch(RLGL.defaultBatch);
rlUnloadShaderDefault(); // Unload default shader
rlUnloadShaderDefault(); // Unload default shader
glDeleteTextures(1, &RLGL.State.defaultTextureId); // Unload default texture
TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture unloaded successfully", RLGL.State.defaultTextureId);
#endif
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
swClose(); // Unload sofware renderer resources
#endif
}
// Load OpenGL extensions
@ -2653,7 +2704,10 @@ void *rlGetProcAddress(const char *procName)
int rlGetVersion(void)
{
int glVersion = 0;
#if defined(GRAPHICS_API_OPENGL_11)
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
glVersion = RL_OPENGL_11_SOFTWARE;
#elif defined(GRAPHICS_API_OPENGL_11)
glVersion = RL_OPENGL_11;
#endif
#if defined(GRAPHICS_API_OPENGL_21)
@ -3694,6 +3748,22 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format)
return pixels;
}
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
// Copy framebuffer pixel data to internal buffer
void rlCopyFramebuffer(int x, int y, int width, int height, int format, void* pixels)
{
unsigned int glInternalFormat, glFormat, glType;
rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); // Get OpenGL texture format
swCopyFramebuffer(x, y, width, height, glFormat, glType, pixels);
}
// Resize internal framebuffer
void rlResizeFramebuffer(int width, int height)
{
swResizeFramebuffer(width, height);
}
#endif
// Read screen pixel data (color buffer)
unsigned char *rlReadScreenPixels(int width, int height)
{
@ -4003,10 +4073,10 @@ void rlDrawVertexArrayElementsInstanced(int offset, int count, const void *buffe
#endif
}
#if defined(GRAPHICS_API_OPENGL_11)
// Enable vertex state pointer
void rlEnableStatePointer(int vertexAttribType, void *buffer)
{
#if defined(GRAPHICS_API_OPENGL_11)
if (buffer != NULL) glEnableClientState(vertexAttribType);
switch (vertexAttribType)
{
@ -4017,14 +4087,16 @@ void rlEnableStatePointer(int vertexAttribType, void *buffer)
//case GL_INDEX_ARRAY: if (buffer != NULL) glIndexPointer(GL_SHORT, 0, buffer); break; // Indexed colors
default: break;
}
#endif
}
// Disable vertex state pointer
void rlDisableStatePointer(int vertexAttribType)
{
#if defined(GRAPHICS_API_OPENGL_11)
glDisableClientState(vertexAttribType);
}
#endif
}
// Load vertex array object (VAO)
unsigned int rlLoadVertexArray(void)
@ -5292,4 +5364,4 @@ static Matrix rlMatrixInvert(Matrix mat)
}
#endif
#endif // RLGL_IMPLEMENTATION
#endif // RLGL_IMPLEMENTATION

View file

@ -1293,10 +1293,19 @@ void UploadMesh(Mesh *mesh, bool dynamic)
rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION);
// Enable vertex attributes: texcoords (shader-location = 1)
mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic);
rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD);
if (mesh->texcoords != NULL)
{
mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic);
rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD);
}
else
{
float value[2] = { 0.0f, 0.0f };
rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, value, SHADER_ATTRIB_VEC2, 2);
rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD);
}
// WARNING: When setting default vertex attribute values, the values for each generic vertex attribute
// is part of current state, and it is maintained even if a different program object is used
@ -1420,7 +1429,7 @@ void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int
// Draw a 3d mesh with material and transform
void DrawMesh(Mesh mesh, Material material, Matrix transform)
{
#if defined(GRAPHICS_API_OPENGL_11)
#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
#define GL_VERTEX_ARRAY 0x8074
#define GL_NORMAL_ARRAY 0x8075
#define GL_COLOR_ARRAY 0x8076
@ -1431,12 +1440,12 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
if (mesh.animVertices) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animVertices);
else rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
if (mesh.texcoords) rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
if (mesh.animNormals) rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.animNormals);
else rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
else if (mesh.normals) rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
if (mesh.colors) rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
rlPushMatrix();
rlMultMatrixf(MatrixToFloat(transform));
@ -3836,6 +3845,7 @@ void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float
// Draw a model points
// WARNING: OpenGL ES 2.0 does not support point mode drawing
// TODO: gate these properly for non es 2.0 versions only
void DrawModelPoints(Model model, Vector3 position, float scale, Color tint)
{
rlEnablePointMode();
@ -4420,7 +4430,11 @@ static Model LoadOBJ(const char *fileName)
model.meshes[i].vertices = (float *)MemAlloc(sizeof(float)*vertexCount*3);
model.meshes[i].normals = (float *)MemAlloc(sizeof(float)*vertexCount*3);
model.meshes[i].texcoords = (float *)MemAlloc(sizeof(float)*vertexCount*2);
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
model.meshes[i].colors = (unsigned char *)MemAlloc(sizeof(unsigned char)*vertexCount*4);
#else
model.meshes[i].colors = NULL;
#endif
}
MemFree(localMeshVertexCounts);
@ -4474,8 +4488,18 @@ static Model LoadOBJ(const char *fileName)
for (int i = 0; i < 3; i++) model.meshes[meshIndex].vertices[localMeshVertexCount*3 + i] = objAttributes.vertices[vertIndex*3 + i];
for (int i = 0; i < 2; i++) model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + i] = objAttributes.texcoords[texcordIndex*2 + i];
if (objAttributes.normals != NULL && normalIndex != TINYOBJ_INVALID_INDEX && normalIndex >= 0)
if ((objAttributes.texcoords != NULL) && (texcordIndex != TINYOBJ_INVALID_INDEX) && (texcordIndex >= 0))
{
for (int i = 0; i < 2; i++) model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + i] = objAttributes.texcoords[texcordIndex*2 + i];
model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1] = 1.0f - model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1];
}
else
{
model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 0] = 0.0f;
model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1] = 0.0f;
}
if ((objAttributes.normals != NULL) && (normalIndex != TINYOBJ_INVALID_INDEX) && (normalIndex >= 0))
{
for (int i = 0; i < 3; i++) model.meshes[meshIndex].normals[localMeshVertexCount*3 + i] = objAttributes.normals[normalIndex*3 + i];
}
@ -4485,11 +4509,9 @@ static Model LoadOBJ(const char *fileName)
model.meshes[meshIndex].normals[localMeshVertexCount*3 + 1] = 1.0f;
model.meshes[meshIndex].normals[localMeshVertexCount*3 + 2] = 0.0f;
}
model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1] = 1.0f - model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1];
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
for (int i = 0; i < 4; i++) model.meshes[meshIndex].colors[localMeshVertexCount*4 + i] = 255;
#endif
faceVertIndex++;
localMeshVertexCount++;
}

View file

@ -182,6 +182,55 @@ void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color colo
rlEnd();
}
void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int whiteSpaceSize, Color color)
{
// Calculate the vector and length of the line
float dx = endPos.x - startPos.x;
float dy = endPos.y - startPos.y;
float lineLength = sqrtf(dx*dx + dy*dy);
// If the line is too short for dashing or dash size is invalid, draw a solid thick line
if (lineLength < (dashSize + whiteSpaceSize) || dashSize <= 0)
{
DrawLineV(startPos, endPos, color);
return;
}
// Calculate the normalized direction vector of the line
float invLineLength = 1 / lineLength;
float dirX = dx * invLineLength;
float dirY = dy * invLineLength;
Vector2 currentPos = startPos;
float distanceTraveled = 0;
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
while (distanceTraveled < lineLength)
{
// Calculate the end of the current dash
float dashEndDist = distanceTraveled + dashSize;
if (dashEndDist > lineLength)
{
dashEndDist = lineLength;
}
Vector2 dashEndPos = { startPos.x + dashEndDist * dirX, startPos.y + dashEndDist * dirY };
// Draw the dash segment
rlVertex2f(currentPos.x, currentPos.y);
rlVertex2f(dashEndPos.x, dashEndPos.y);
// Update the distance traveled and move the current position for the next dash
distanceTraveled = dashEndDist + whiteSpaceSize;
currentPos.x = startPos.x + distanceTraveled * dirX;
currentPos.y = startPos.y + distanceTraveled * dirY;
}
rlEnd();
}
// Draw a line (using gl lines)
void DrawLineV(Vector2 startPos, Vector2 endPos, Color color)
{

View file

@ -1452,7 +1452,7 @@ Rectangle GetGlyphAtlasRec(Font font, int codepoint)
char **LoadTextLines(const char *text, int *count)
{
int lineCount = 1;
int textSize = strlen(text);
int textSize = (int)strlen(text);
// Text pass to get required line count
for (int i = 0; i < textSize; i++)
@ -1679,7 +1679,7 @@ char *GetTextBetween(const char *text, const char *begin, const char *end)
if (beginIndex > -1)
{
int beginLen = strlen(begin);
int beginLen = (int)strlen(begin);
int endIndex = TextFindIndex(text + beginIndex + beginLen, end);
if (endIndex > -1)
@ -1758,15 +1758,15 @@ char *TextReplaceBetween(const char *text, const char *begin, const char *end, c
if (beginIndex > -1)
{
int beginLen = strlen(begin);
int beginLen = (int)strlen(begin);
int endIndex = TextFindIndex(text + beginIndex + beginLen, end);
if (endIndex > -1)
{
endIndex += (beginIndex + beginLen);
int textLen = strlen(text);
int replaceLen = (replacement == NULL)? 0 : strlen(replacement);
int textLen = (int)strlen(text);
int replaceLen = (replacement == NULL)? 0 : (int)strlen(replacement);
int toreplaceLen = endIndex - beginIndex - beginLen;
result = (char *)RL_CALLOC(textLen + replaceLen - toreplaceLen + 1, sizeof(char));

View file

@ -811,8 +811,8 @@ Image GenImageColor(int width, int height, Color color)
.data = pixels,
.width = width,
.height = height,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
.mipmaps = 1
.mipmaps = 1,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
};
return image;
@ -863,8 +863,8 @@ Image GenImageGradientLinear(int width, int height, int direction, Color start,
.data = pixels,
.width = width,
.height = height,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
.mipmaps = 1
.mipmaps = 1,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
};
return image;
@ -900,8 +900,8 @@ Image GenImageGradientRadial(int width, int height, float density, Color inner,
.data = pixels,
.width = width,
.height = height,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
.mipmaps = 1
.mipmaps = 1,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
};
return image;
@ -949,8 +949,8 @@ Image GenImageGradientSquare(int width, int height, float density, Color inner,
.data = pixels,
.width = width,
.height = height,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
.mipmaps = 1
.mipmaps = 1,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
};
return image;
@ -974,8 +974,8 @@ Image GenImageChecked(int width, int height, int checksX, int checksY, Color col
.data = pixels,
.width = width,
.height = height,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
.mipmaps = 1
.mipmaps = 1,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
};
return image;
@ -997,8 +997,8 @@ Image GenImageWhiteNoise(int width, int height, float factor)
.data = pixels,
.width = width,
.height = height,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
.mipmaps = 1
.mipmaps = 1,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
};
return image;
@ -1048,8 +1048,8 @@ Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float
.data = pixels,
.width = width,
.height = height,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
.mipmaps = 1
.mipmaps = 1,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
};
return image;
@ -1113,8 +1113,8 @@ Image GenImageCellular(int width, int height, int tileSize)
.data = pixels,
.width = width,
.height = height,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
.mipmaps = 1
.mipmaps = 1,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
};
return image;