Merge pull request #3 from kd7tck/feat/vulkan-backend-framework

feat: Add initial Vulkan backend framework and compile flag
This commit is contained in:
Joshua Reisenauer 2025-05-31 19:23:50 -07:00 committed by GitHub
commit 84c57c890d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 625 additions and 115 deletions

View file

@ -27,8 +27,18 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include(CompilerFlags)
# Registers build options that are exposed to cmake
option(SUPPORT_VULKAN "Enable Vulkan graphics backend" OFF)
include(CMakeOptions.txt)
if (SUPPORT_VULKAN)
find_package(Vulkan REQUIRED)
if (NOT Vulkan_FOUND)
message(FATAL_ERROR "Vulkan SDK not found, required for SUPPORT_VULKAN option.")
else()
message(STATUS "Vulkan SDK found: Headers at ${Vulkan_INCLUDE_DIRS}, Libraries at ${Vulkan_LIBRARIES}")
endif()
endif()
if (UNIX AND NOT APPLE AND NOT "${PLATFORM}" MATCHES "DRM")
if (NOT GLFW_BUILD_WAYLAND AND NOT GLFW_BUILD_X11)
MESSAGE(FATAL_ERROR "Cannot disable both Wayland and X11")

View file

@ -1,7 +1,14 @@
target_compile_definitions("raylib" PUBLIC "CF_VULKAN_=0")
# Adding compile definitions
target_compile_definitions("raylib" PUBLIC "${PLATFORM_CPP}")
target_compile_definitions("raylib" PUBLIC "${GRAPHICS}")
if (SUPPORT_VULKAN AND Vulkan_FOUND)
target_compile_definitions("raylib" PUBLIC "CF_VULKAN_=1")
target_compile_definitions("raylib" PUBLIC "GRAPHICS_API_VULKAN")
message(STATUS "Vulkan backend enabled via CF_VULKAN_ and GRAPHICS_API_VULKAN")
endif()
function(define_if target variable)
if(${${variable}})
message(STATUS "${variable}=${${variable}}")

View file

@ -7,133 +7,149 @@ if(POLICY CMP0072)
cmake_policy(SET CMP0072 NEW)
endif()
if (${PLATFORM} MATCHES "Desktop")
set(PLATFORM_CPP "PLATFORM_DESKTOP")
if (SUPPORT_VULKAN AND Vulkan_FOUND)
set(GRAPHICS "GRAPHICS_API_VULKAN")
message(STATUS "Vulkan graphics API selected. GRAPHICS set to GRAPHICS_API_VULKAN.")
# Any Vulkan-specific LIBS_PRIVATE additions can be handled here or in src/CMakeLists.txt
# For now, assuming Vulkan::Vulkan and Vulkan_LIBRARIES cover necessary linking.
else()
# ORIGINAL OPENGL-SPECIFIC LOGIC
if (${PLATFORM} MATCHES "Desktop")
set(PLATFORM_CPP "PLATFORM_DESKTOP")
if (APPLE)
# Need to force OpenGL 3.3 on OS X
# See: https://github.com/raysan5/raylib/issues/341
set(GRAPHICS "GRAPHICS_API_OPENGL_33")
find_library(OPENGL_LIBRARY OpenGL)
set(LIBS_PRIVATE ${OPENGL_LIBRARY})
link_libraries("${LIBS_PRIVATE}")
if (NOT CMAKE_SYSTEM STRLESS "Darwin-18.0.0")
add_definitions(-DGL_SILENCE_DEPRECATION)
MESSAGE(AUTHOR_WARNING "OpenGL is deprecated starting with macOS 10.14 (Mojave)!")
endif ()
elseif (WIN32)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
find_package(OpenGL QUIET)
set(LIBS_PRIVATE ${OPENGL_LIBRARIES} winmm)
elseif (UNIX)
find_library(pthread NAMES pthread)
find_package(OpenGL QUIET)
if ("${OPENGL_LIBRARIES}" STREQUAL "")
set(OPENGL_LIBRARIES "GL")
endif ()
if (APPLE)
# Need to force OpenGL 3.3 on OS X
# See: https://github.com/raysan5/raylib/issues/341
set(GRAPHICS "GRAPHICS_API_OPENGL_33")
find_library(OPENGL_LIBRARY OpenGL)
set(LIBS_PRIVATE ${OPENGL_LIBRARY})
link_libraries("${LIBS_PRIVATE}")
if (NOT CMAKE_SYSTEM STRLESS "Darwin-18.0.0")
add_definitions(-DGL_SILENCE_DEPRECATION)
MESSAGE(AUTHOR_WARNING "OpenGL is deprecated starting with macOS 10.14 (Mojave)!")
endif ()
elseif (WIN32)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
find_package(OpenGL QUIET)
set(LIBS_PRIVATE ${OPENGL_LIBRARIES} winmm)
elseif (UNIX)
find_library(pthread NAMES pthread)
find_package(OpenGL QUIET)
if ("${OPENGL_LIBRARIES}" STREQUAL "")
set(OPENGL_LIBRARIES "GL")
endif ()
if ("${CMAKE_SYSTEM_NAME}" MATCHES "(Net|Open)BSD")
find_library(OSS_LIBRARY ossaudio)
endif ()
if ("${CMAKE_SYSTEM_NAME}" MATCHES "(Net|Open)BSD")
find_library(OSS_LIBRARY ossaudio)
endif ()
set(LIBS_PRIVATE m pthread ${OPENGL_LIBRARIES} ${OSS_LIBRARY})
else ()
find_library(pthread NAMES pthread)
find_package(OpenGL QUIET)
if ("${OPENGL_LIBRARIES}" STREQUAL "")
set(OPENGL_LIBRARIES "GL")
endif ()
set(LIBS_PRIVATE m atomic pthread ${OPENGL_LIBRARIES} ${OSS_LIBRARY})
if ("${CMAKE_SYSTEM_NAME}" MATCHES "(Net|Open)BSD")
find_library(OSS_LIBRARY ossaudio)
set(LIBS_PRIVATE m pthread ${OPENGL_LIBRARIES} ${OSS_LIBRARY})
else ()
find_library(pthread NAMES pthread)
find_package(OpenGL QUIET)
if ("${OPENGL_LIBRARIES}" STREQUAL "")
set(OPENGL_LIBRARIES "GL")
endif ()
set(LIBS_PRIVATE m atomic pthread ${OPENGL_LIBRARIES} ${OSS_LIBRARY})
if ("${CMAKE_SYSTEM_NAME}" MATCHES "(Net|Open)BSD")
find_library(OSS_LIBRARY ossaudio)
set(LIBS_PRIVATE m pthread ${OPENGL_LIBRARIES} ${OSS_LIBRARY})
endif ()
if (NOT "${CMAKE_SYSTEM_NAME}" MATCHES "(Net|Open)BSD" AND USE_AUDIO)
set(LIBS_PRIVATE ${LIBS_PRIVATE} dl)
endif ()
endif ()
if (NOT "${CMAKE_SYSTEM_NAME}" MATCHES "(Net|Open)BSD" AND USE_AUDIO)
set(LIBS_PRIVATE ${LIBS_PRIVATE} dl)
elseif (${PLATFORM} MATCHES "Web")
set(PLATFORM_CPP "PLATFORM_WEB")
if(NOT GRAPHICS)
set(GRAPHICS "GRAPHICS_API_OPENGL_ES2")
endif()
set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
elseif (${PLATFORM} MATCHES "Android")
set(PLATFORM_CPP "PLATFORM_ANDROID")
set(GRAPHICS "GRAPHICS_API_OPENGL_ES2")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
list(APPEND raylib_sources ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
include_directories(${ANDROID_NDK}/sources/android/native_app_glue)
# NOTE: We remove '-Wl,--no-undefined' (set by default) as it conflicts with '-Wl,-undefined,dynamic_lookup' needed
# for compiling with the missing 'void main(void)' declaration in `android_main()`.
# We also remove other unnecessary or problematic flags.
string(REPLACE "-Wl,--no-undefined -Qunused-arguments" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
string(REPLACE "-static-libstdc++" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -u ANativeActivity_onCreate -Wl,-undefined,dynamic_lookup")
find_library(OPENGL_LIBRARY OpenGL)
set(LIBS_PRIVATE m log android EGL GLESv2 OpenSLES atomic c)
elseif ("${PLATFORM}" MATCHES "DRM")
set(PLATFORM_CPP "PLATFORM_DRM")
set(GRAPHICS "GRAPHICS_API_OPENGL_ES2")
add_definitions(-D_DEFAULT_SOURCE)
add_definitions(-DEGL_NO_X11)
add_definitions(-DPLATFORM_DRM)
find_library(GLESV2 GLESv2)
find_library(EGL EGL)
find_library(DRM drm)
find_library(GBM gbm)
if (NOT CMAKE_CROSSCOMPILING OR NOT CMAKE_SYSROOT)
include_directories(/usr/include/libdrm)
endif ()
set(LIBS_PRIVATE ${GLESV2} ${EGL} ${DRM} ${GBM} atomic pthread m dl)
elseif ("${PLATFORM}" MATCHES "SDL")
find_package(SDL2 REQUIRED)
set(PLATFORM_CPP "PLATFORM_DESKTOP_SDL")
set(LIBS_PRIVATE SDL2::SDL2)
# For SDL, if it's used with OpenGL, ensure GRAPHICS is set appropriately if not already.
# This might need adjustment if SDL can also host Vulkan. For now, assuming SDL is for OpenGL.
if(NOT GRAPHICS)
set(GRAPHICS "GRAPHICS_API_OPENGL_33") # Default for SDL on desktop, or could be ES for other platforms
endif()
endif ()
if (NOT ${OPENGL_VERSION} MATCHES "OFF")
set(SUGGESTED_GRAPHICS "${GRAPHICS}")
if (${OPENGL_VERSION} MATCHES "4.3")
set(GRAPHICS "GRAPHICS_API_OPENGL_43")
elseif (${OPENGL_VERSION} MATCHES "3.3")
set(GRAPHICS "GRAPHICS_API_OPENGL_33")
elseif (${OPENGL_VERSION} MATCHES "2.1")
set(GRAPHICS "GRAPHICS_API_OPENGL_21")
elseif (${OPENGL_VERSION} MATCHES "1.1")
set(GRAPHICS "GRAPHICS_API_OPENGL_11")
elseif (${OPENGL_VERSION} MATCHES "ES 2.0")
set(GRAPHICS "GRAPHICS_API_OPENGL_ES2")
elseif (${OPENGL_VERSION} MATCHES "ES 3.0")
set(GRAPHICS "GRAPHICS_API_OPENGL_ES3")
endif ()
if (NOT "${SUGGESTED_GRAPHICS}" STREQUAL "" AND NOT "${SUGGESTED_GRAPHICS}" STREQUAL "${GRAPHICS}")
message(WARNING "You are overriding the suggested GRAPHICS=${SUGGESTED_GRAPHICS} with ${GRAPHICS}! This may fail.")
endif ()
endif ()
elseif (${PLATFORM} MATCHES "Web")
set(PLATFORM_CPP "PLATFORM_WEB")
if(NOT GRAPHICS)
set(GRAPHICS "GRAPHICS_API_OPENGL_ES2")
endif()
set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
elseif (${PLATFORM} MATCHES "Android")
set(PLATFORM_CPP "PLATFORM_ANDROID")
set(GRAPHICS "GRAPHICS_API_OPENGL_ES2")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
list(APPEND raylib_sources ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
include_directories(${ANDROID_NDK}/sources/android/native_app_glue)
# NOTE: We remove '-Wl,--no-undefined' (set by default) as it conflicts with '-Wl,-undefined,dynamic_lookup' needed
# for compiling with the missing 'void main(void)' declaration in `android_main()`.
# We also remove other unnecessary or problematic flags.
string(REPLACE "-Wl,--no-undefined -Qunused-arguments" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
string(REPLACE "-static-libstdc++" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -u ANativeActivity_onCreate -Wl,-undefined,dynamic_lookup")
find_library(OPENGL_LIBRARY OpenGL)
set(LIBS_PRIVATE m log android EGL GLESv2 OpenSLES atomic c)
elseif ("${PLATFORM}" MATCHES "DRM")
set(PLATFORM_CPP "PLATFORM_DRM")
set(GRAPHICS "GRAPHICS_API_OPENGL_ES2")
add_definitions(-D_DEFAULT_SOURCE)
add_definitions(-DEGL_NO_X11)
add_definitions(-DPLATFORM_DRM)
find_library(GLESV2 GLESv2)
find_library(EGL EGL)
find_library(DRM drm)
find_library(GBM gbm)
if (NOT CMAKE_CROSSCOMPILING OR NOT CMAKE_SYSROOT)
include_directories(/usr/include/libdrm)
if (NOT GRAPHICS)
set(GRAPHICS "GRAPHICS_API_OPENGL_33") # Default OpenGL version if nothing else set it
endif ()
set(LIBS_PRIVATE ${GLESV2} ${EGL} ${DRM} ${GBM} atomic pthread m dl)
elseif ("${PLATFORM}" MATCHES "SDL")
find_package(SDL2 REQUIRED)
set(PLATFORM_CPP "PLATFORM_DESKTOP_SDL")
set(LIBS_PRIVATE SDL2::SDL2)
endif ()
if (NOT ${OPENGL_VERSION} MATCHES "OFF")
set(SUGGESTED_GRAPHICS "${GRAPHICS}")
if (${OPENGL_VERSION} MATCHES "4.3")
set(GRAPHICS "GRAPHICS_API_OPENGL_43")
elseif (${OPENGL_VERSION} MATCHES "3.3")
set(GRAPHICS "GRAPHICS_API_OPENGL_33")
elseif (${OPENGL_VERSION} MATCHES "2.1")
set(GRAPHICS "GRAPHICS_API_OPENGL_21")
elseif (${OPENGL_VERSION} MATCHES "1.1")
set(GRAPHICS "GRAPHICS_API_OPENGL_11")
elseif (${OPENGL_VERSION} MATCHES "ES 2.0")
set(GRAPHICS "GRAPHICS_API_OPENGL_ES2")
elseif (${OPENGL_VERSION} MATCHES "ES 3.0")
set(GRAPHICS "GRAPHICS_API_OPENGL_ES3")
endif ()
if (NOT "${SUGGESTED_GRAPHICS}" STREQUAL "" AND NOT "${SUGGESTED_GRAPHICS}" STREQUAL "${GRAPHICS}")
message(WARNING "You are overriding the suggested GRAPHICS=${SUGGESTED_GRAPHICS} with ${GRAPHICS}! This may fail.")
endif ()
endif ()
if (NOT GRAPHICS)
set(GRAPHICS "GRAPHICS_API_OPENGL_33")
endif ()
endif() # End of SUPPORT_VULKAN AND Vulkan_FOUND conditional
# Universal appends to LIBS_PRIVATE
set(LIBS_PRIVATE ${LIBS_PRIVATE} ${OPENAL_LIBRARY})
if (${PLATFORM} MATCHES "Desktop")
# This implies glfw is used for both Vulkan and OpenGL on Desktop.
# If GLFW is only for OpenGL, this should be in the else block.
# Given rcore_vulkan_glfw.c, it's likely needed for Vulkan too.
set(LIBS_PRIVATE ${LIBS_PRIVATE} glfw)
endif ()

View file

@ -39,6 +39,11 @@ set(raylib_sources
utils.c
)
if (SUPPORT_VULKAN AND Vulkan_FOUND)
list(APPEND raylib_sources rlvk.c)
message(STATUS "Vulkan source (rlvk.c) added to compilation.")
endif()
# <root>/cmake/GlfwImport.cmake handles the details around the inclusion of glfw
if (NOT ${PLATFORM} MATCHES "Web")
include(GlfwImport)
@ -49,6 +54,24 @@ endif ()
# Produces a variable LIBS_PRIVATE that will be used later
include(LibraryConfigurations)
if (SUPPORT_VULKAN AND Vulkan_FOUND)
if(TARGET Vulkan::Vulkan)
target_link_libraries(raylib PUBLIC Vulkan::Vulkan)
message(STATUS "Linking raylib with Vulkan::Vulkan target.")
elseif(Vulkan_LIBRARIES)
# For older CMake or non-imported target setups for Vulkan
target_link_libraries(raylib PUBLIC ${Vulkan_LIBRARIES})
message(STATUS "Linking raylib with Vulkan libraries: ${Vulkan_LIBRARIES}")
else()
message(WARNING "Vulkan support is enabled, but no Vulkan link target or libraries (Vulkan::Vulkan or Vulkan_LIBRARIES) were found/specified by find_package(Vulkan).")
endif()
# Ensure Vulkan include directories are available to the raylib target
if (Vulkan_INCLUDE_DIRS)
target_include_directories(raylib PUBLIC $<BUILD_INTERFACE:${Vulkan_INCLUDE_DIRS}>)
message(STATUS "Adding Vulkan include directories: ${Vulkan_INCLUDE_DIRS}")
endif()
endif()
if (SUPPORT_MODULE_RAUDIO)
MESSAGE(STATUS "Audio Backend: miniaudio")
else ()

View file

@ -54,6 +54,25 @@
#include "GLFW/glfw3.h" // GLFW3 library: Windows, OpenGL context and Input management
// NOTE: GLFW3 already includes gl.h (OpenGL) headers
#if defined(GRAPHICS_API_VULKAN)
#if defined(__APPLE__)
// MoltenVK requires a specific include order and defines
#define VK_USE_PLATFORM_MACOS_MVK
#define VK_USE_PLATFORM_METAL_EXT // If using newer MoltenVK/GLFW with direct Metal layer access
#elif defined(_WIN32)
#define VK_USE_PLATFORM_WIN32_KHR
#else // Assuming X11 or Wayland for other Linux/Unix via GLFW
// GLFW handles these includes mostly, but define for clarity if needed by MoltenVK headers
#if defined(GLFW_EXPOSE_NATIVE_X11) // This define might be set by glfw3native.h later
#define VK_USE_PLATFORM_XLIB_KHR
#endif
#if defined(GLFW_EXPOSE_NATIVE_WAYLAND) // This define might be set by glfw3native.h later
#define VK_USE_PLATFORM_WAYLAND_KHR
#endif
#endif
#include <vulkan/vulkan.h>
#endif
// Support retrieving native window handlers
#if defined(_WIN32)
typedef void *PVOID;
@ -108,6 +127,12 @@ static PlatformData platform = { 0 }; // Platform specific data
int InitPlatform(void); // Initialize platform (graphics, inputs and more)
void ClosePlatform(void); // Close platform
#if defined(GRAPHICS_API_VULKAN)
// Vulkan specific platform functions
static int InitPlatformVulkan(void);
static void ClosePlatformVulkan(void);
#endif
// Error callback event
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
@ -1317,6 +1342,181 @@ static void DeallocateWrapper(void* block, void* user)
}
// Initialize platform: graphics, inputs and more
#if defined(GRAPHICS_API_VULKAN)
// Initialize platform for Vulkan (GLFW STUB)
static int InitPlatformVulkan(void) {
TRACELOG(LOG_INFO, "PLATFORM: Initializing platform for Vulkan (GLFW STUB)");
glfwSetErrorCallback(ErrorCallback);
const GLFWallocator allocator = {
.allocate = AllocateWrapper,
.deallocate = DeallocateWrapper,
.reallocate = ReallocateWrapper,
.user = NULL,
};
glfwInitAllocator(&allocator);
#if defined(__APPLE__)
glfwInitHint(GLFW_COCOA_CHDIR_RESOURCES, GLFW_FALSE);
#endif
if (!glfwInit()) {
TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize GLFW for Vulkan");
return RL_FALSE;
}
if (!glfwVulkanSupported()) {
TRACELOG(LOG_FATAL, "PLATFORM: Vulkan not supported by GLFW or system drivers");
glfwTerminate();
return RL_FALSE;
}
TRACELOG(LOG_INFO, "PLATFORM: GLFW Vulkan support detected.");
glfwDefaultWindowHints();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); // Critical for Vulkan
// Common window hints from InitPlatform()
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) CORE.Window.fullscreen = true;
if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
else glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);
if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
else glfwWindowHint(GLFW_DECORATED, GLFW_TRUE);
if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
else glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // Cannot be set on creation
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; // Cannot be set on creation
if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE);
else glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE);
if ((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) glfwWindowHint(GLFW_FLOATING, GLFW_TRUE);
else glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
else glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_FALSE);
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE); // Keep old behavior for now
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) {
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
#if defined(__APPLE__)
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
#endif
} else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE);
if ((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE);
else glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_FALSE);
// MSAA hint is not relevant for Vulkan in this context
// Determine monitor for fullscreen or initial placement
GLFWmonitor *monitor = NULL;
if (CORE.Window.fullscreen) {
monitor = glfwGetPrimaryMonitor();
if (!monitor) {
TRACELOG(LOG_WARNING, "GLFW: Failed to get primary monitor for Vulkan fullscreen");
glfwTerminate();
return RL_FALSE;
}
SetDimensionsFromMonitor(monitor);
} else {
// For windowed mode, get current monitor to center on later
// This part is tricky because GetCurrentMonitor() needs a window handle.
// We'll get primary and center on that if no better option before window creation.
monitor = glfwGetPrimaryMonitor(); // Default to primary for initial setup
if (monitor) SetDimensionsFromMonitor(monitor);
else { TRACELOG(LOG_WARNING, "GLFW: Could not get primary monitor for initial Vulkan window setup."); }
}
// Create window
int creationWidth = (CORE.Window.screen.width > 0) ? CORE.Window.screen.width : 640;
int creationHeight = (CORE.Window.screen.height > 0) ? CORE.Window.screen.height : 480;
platform.handle = glfwCreateWindow(creationWidth, creationHeight, (CORE.Window.title != 0)? CORE.Window.title : " ", CORE.Window.fullscreen ? monitor : NULL, NULL);
CORE.Window.handle = platform.handle;
if (!CORE.Window.handle) {
TRACELOG(LOG_FATAL, "PLATFORM: Failed to create GLFW window for Vulkan");
glfwTerminate();
return RL_FALSE;
}
TRACELOG(LOG_INFO, "PLATFORM: GLFW window created for Vulkan");
vkInstanceHandle = (VkInstance)0x1;
vkSurfaceHandle = (VkSurfaceKHR)0x1;
TRACELOG(LOG_INFO, "PLATFORM: VkInstance and VkSurfaceKHR STUBBED as non-null for rlvkInit testing.");
// Setup GLFW callbacks
glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback);
glfwSetWindowPosCallback(platform.handle, WindowPosCallback);
glfwSetWindowMaximizeCallback(platform.handle, WindowMaximizeCallback);
glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback);
glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback);
glfwSetDropCallback(platform.handle, WindowDropCallback);
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) {
glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback);
}
glfwSetKeyCallback(platform.handle, KeyCallback);
glfwSetCharCallback(platform.handle, CharCallback);
glfwSetMouseButtonCallback(platform.handle, MouseButtonCallback);
glfwSetCursorPosCallback(platform.handle, MouseCursorPosCallback);
glfwSetScrollCallback(platform.handle, MouseScrollCallback);
glfwSetCursorEnterCallback(platform.handle, CursorEnterCallback);
glfwSetJoystickCallback(JoystickCallback);
glfwSetInputMode(platform.handle, GLFW_LOCK_KEY_MODS, GLFW_TRUE);
int fbWidth = CORE.Window.screen.width; // Fallback to screen width
int fbHeight = CORE.Window.screen.height; // Fallback to screen height
// For Vulkan with GLFW_NO_API, glfwGetFramebufferSize might still be relevant for HighDPI scenarios
// where window coords and pixel coords differ.
glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight);
CORE.Window.render.width = fbWidth;
CORE.Window.render.height = fbHeight;
CORE.Window.currentFbo.width = fbWidth;
CORE.Window.currentFbo.height = fbHeight;
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) {
#if !defined(__APPLE__)
if (CORE.Window.screen.width > 0 && CORE.Window.screen.height > 0) { // Avoid division by zero
CORE.Window.screenScale = MatrixScale((float)fbWidth/CORE.Window.screen.width, (float)fbHeight/CORE.Window.screen.height, 1.0f);
SetMouseScale((float)CORE.Window.screen.width/fbWidth, (float)CORE.Window.screen.height/fbHeight);
}
#endif
}
if (!CORE.Window.fullscreen && monitor) { // monitor might be null if primary couldn't be fetched
int monitorX = 0, monitorY = 0;
glfwGetMonitorPos(monitor, &monitorX, &monitorY);
int areaWidth = 0, areaHeight = 0;
glfwGetMonitorWorkarea(monitor, NULL, NULL, &areaWidth, &areaHeight);
int posX = monitorX + (areaWidth - CORE.Window.render.width)/2;
int posY = monitorY + (areaHeight - CORE.Window.render.height)/2;
if (posX < monitorX) posX = monitorX;
if (posY < monitorY) posY = monitorY;
SetWindowPosition(posX, posY);
}
CORE.Window.ready = RL_TRUE;
TRACELOG(LOG_INFO, "PLATFORM: Vulkan platform initialized successfully (GLFW STUBBED VkInstance/Surface)");
InitTimer();
CORE.Storage.basePath = GetWorkingDirectory();
return RL_TRUE;
}
static void ClosePlatformVulkan(void) {
TRACELOG(LOG_INFO, "PLATFORM: Closing Vulkan platform (GLFW STUB)");
#if defined(GRAPHICS_API_VULKAN)
vkSurfaceHandle = VK_NULL_HANDLE;
vkInstanceHandle = VK_NULL_HANDLE;
TRACELOG(LOG_INFO, "PLATFORM: VkInstance and VkSurfaceKHR STUBBED as NULL.");
#endif
if (CORE.Window.handle != NULL) {
glfwDestroyWindow(CORE.Window.handle);
CORE.Window.handle = NULL;
platform.handle = NULL;
}
glfwTerminate();
TRACELOG(LOG_INFO, "PLATFORM: Vulkan platform resources closed (GLFW STUBBED VkInstance/Surface)");
}
#endif // GRAPHICS_API_VULKAN
int InitPlatform(void)
{
glfwSetErrorCallback(ErrorCallback);

View file

@ -123,6 +123,16 @@
#define RAYMATH_IMPLEMENTATION
#include "raymath.h" // Vector2, Vector3, Quaternion and Matrix functionality
#if defined(GRAPHICS_API_VULKAN)
#include "rlvk.h" // If rlvk functions are called directly from rcore
// It's also possible that rlgl.h handles the dispatch via its own functions.
// The plan suggests InitPlatformVulkan will provide instance/surface to rlvkInit.
// Global/static VkInstance and VkSurfaceKHR to be set by platform layer for rlvkInit.
// This is a temporary approach for the subtask.
VkInstance vkInstanceHandle = VK_NULL_HANDLE;
VkSurfaceKHR vkSurfaceHandle = VK_NULL_HANDLE;
#endif
#if defined(SUPPORT_GESTURES_SYSTEM)
#define RGESTURES_IMPLEMENTATION
#include "rgestures.h" // Gestures detection functionality
@ -681,7 +691,13 @@ void InitWindow(int width, int height, const char *title)
// Initialize platform
//--------------------------------------------------------------
//int result = InitPlatform();
#if defined(GRAPHICS_API_VULKAN)
// InitPlatformVulkan() will be created in step 6 and should set vkInstanceHandle and vkSurfaceHandle
int result = InitPlatformVulkan();
#else
int result = InitPlatform();
#endif
if (result != 0)
{
@ -690,10 +706,39 @@ void InitWindow(int width, int height, const char *title)
}
//--------------------------------------------------------------
#if defined(GRAPHICS_API_VULKAN)
if (CORE.Window.ready) { // Assuming InitPlatformVulkan sets CORE.Window.ready on success
rlvkInit(vkInstanceHandle, vkSurfaceHandle, CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
if (rlvkIsReady()) {
isGpuReady = true;
TRACELOG(LOG_INFO, "RCORE: Vulkan backend initialized successfully via rlvkInit.");
} else {
TRACELOG(LOG_ERROR, "RCORE: Failed to initialize Vulkan backend via rlvkInit.");
CORE.Window.ready = false; // Ensure window is not marked as ready
// Potentially call ClosePlatformVulkan here if InitPlatformVulkan succeeded but rlvkInit failed
ClosePlatformVulkan();
return;
}
}
#endif
// Initialize rlgl default data (buffers and shaders)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
isGpuReady = true; // Flag to note GPU has been initialized successfully
#if !defined(GRAPHICS_API_VULKAN)
// If not using Vulkan (i.e., using OpenGL), and rlglInit() for OpenGL has completed,
// then the GPU is considered ready.
// This line was originally after rlglInit() before Vulkan changes.
isGpuReady = true;
#endif
// If GRAPHICS_API_VULKAN is defined, isGpuReady is set (or not) earlier,
// based on the success of rlvkInit().
// We can add a final check here if really needed, but the previous logic should suffice:
// else if (!isGpuReady && defined(GRAPHICS_API_VULKAN)) {
// TRACELOG(LOG_ERROR, "RCORE: GPU not ready after Vulkan initialization sequence (final check).");
// }
// Setup default viewport
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
@ -753,11 +798,21 @@ void CloseWindow(void)
UnloadFontDefault(); // WARNING: Module required: rtext
#endif
#if defined(GRAPHICS_API_VULKAN)
if (rlvkIsReady()) { // Check if it was successfully initialized
rlvkClose();
}
#endif
rlglClose(); // De-init rlgl
// De-initialize platform
//--------------------------------------------------------------
//ClosePlatform();
#if defined(GRAPHICS_API_VULKAN)
ClosePlatformVulkan();
#else
ClosePlatform();
#endif
//--------------------------------------------------------------
CORE.Window.ready = false;

View file

@ -826,6 +826,10 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
#if defined(RLGL_IMPLEMENTATION)
#if defined(GRAPHICS_API_VULKAN)
#include "rlvk.h" // Path relative to rcore.c or where rlgl.h implementation is
#endif
// Expose OpenGL functions from glad in raylib
#if defined(BUILD_LIBTYPE_SHARED)
#define GLAD_API_CALL_EXPORT
@ -1455,6 +1459,14 @@ void rlColor4f(float x, float y, float z, float w) { glColor4f(x, y, z, w); }
// Initialize drawing mode (how to organize vertex)
void rlBegin(int mode)
{
#if defined(GRAPHICS_API_VULKAN)
// In Vulkan, rlBegin equivalent would be part of starting a command buffer or render pass.
// For immediate mode emulation, this might involve setting up for a new batch.
// rlvkBeginDrawing() is the target. The 'mode' parameter might be used by rlvk to set pipeline state.
rlvkBeginDrawing();
// The original logic for rlBegin in OpenGL was to manage batching and draw call generation
// based on mode changes. Vulkan path might do similar for its own batching or just rely on rlvk.
#else
// Draw mode can be RL_LINES, RL_TRIANGLES and RL_QUADS
// NOTE: In all three cases, vertex are accumulated over default internal vertex buffer
if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode != mode)
@ -1483,15 +1495,22 @@ void rlBegin(int mode)
RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount = 0;
RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = RLGL.State.defaultTextureId;
}
#endif // GRAPHICS_API_VULKAN
}
// Finish vertex providing
void rlEnd(void)
{
#if defined(GRAPHICS_API_VULKAN)
// In Vulkan, rlEnd equivalent would be part of ending a command buffer or render pass.
// rlvkEndDrawing() is the target.
rlvkEndDrawing();
#else
// NOTE: Depth increment is dependant on rlOrtho(): z-near and z-far values,
// as well as depth buffer bit-depth (16bit or 24bit or 32bit)
// Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits)
RLGL.currentBatch->currentDepth += (1.0f/20000.0f);
#endif // GRAPHICS_API_VULKAN
}
// Define one vertex (position)
@ -2050,6 +2069,9 @@ bool rlIsStereoRenderEnabled(void)
// Clear color buffer with color
void rlClearColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
#if defined(GRAPHICS_API_VULKAN)
rlvkClearBackground(r, g, b, a); // Call the Vulkan equivalent
#else
// Color values clamp to 0.0f(0) and 1.0f(255)
float cr = (float)r/255;
float cg = (float)g/255;
@ -2057,6 +2079,7 @@ void rlClearColor(unsigned char r, unsigned char g, unsigned char b, unsigned ch
float ca = (float)a/255;
glClearColor(cr, cg, cb, ca);
#endif
}
// Clear used screen buffers (color and depth)
@ -2233,6 +2256,43 @@ static void GLAPIENTRY rlDebugMessageCallback(GLenum source, GLenum type, GLuint
// Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states
void rlglInit(int width, int height)
{
#if defined(GRAPHICS_API_VULKAN)
// Most Vulkan initialization is platform and rlvk specific.
// rlgl itself might initialize shared data structures here if any.
// For now, rlvkInit() is expected to be called from rcore.c's InitWindow.
// Load default batch for Vulkan if its structure is generic enough,
// or rlvk will handle its own batching system.
// The plan says: "Initialize rlgl default data (buffers and shaders)"
// This might mean setting up RLGL.State for Vulkan mode.
// Init default white texture (Vulkan specific)
// unsigned char pixels[4] = { 255, 255, 255, 255 };
// RLGL.State.defaultTextureId = rlvkLoadTexture(pixels, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1);
// if (RLGL.State.defaultTextureId != 0) TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Default texture loaded successfully (Vulkan)", RLGL.State.defaultTextureId);
// else TRACELOG(LOG_WARNING, "TEXTURE: Failed to load default texture (Vulkan)");
// Load default shader (Vulkan specific)
// rlLoadShaderDefault(); // This needs to be Vulkan aware
// RLGL.State.currentShaderId = RLGL.State.defaultShaderId;
// RLGL.State.currentShaderLocs = RLGL.State.defaultShaderLocs;
// For now, assume rlvkInit handles this, and rcore.c calls it.
// rlglInit under Vulkan might just set some state flags.
TRACELOG(LOG_INFO, "RLGL: rlglInit called for Vulkan. Expecting rlvkInit to be called from rcore.");
RLGL.State.currentMatrixMode = RL_MODELVIEW;
RLGL.State.currentMatrix = &RLGL.State.modelview;
RLGL.State.modelview = rlMatrixIdentity();
RLGL.State.projection = rlMatrixIdentity();
RLGL.State.transform = rlMatrixIdentity();
// Other RLGL.State initializations as needed.
// Store screen size into global variables
RLGL.State.framebufferWidth = width;
RLGL.State.framebufferHeight = height;
TRACELOG(RL_LOG_INFO, "RLGL: Default Vulkan state initialized successfully"); // This is a bit optimistic, more setup needed in rlvk
#else // This means !defined(GRAPHICS_API_VULKAN)
// Enable OpenGL debug context if required
#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) && defined(GRAPHICS_API_OPENGL_43)
if ((glDebugMessageCallback != NULL) && (glDebugMessageControl != NULL))
@ -2319,11 +2379,18 @@ void rlglInit(int width, int height)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black)
glClearDepth(1.0f); // Set clear depth value (default)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D)
#endif // GRAPHICS_API_VULKAN defined check
}
// Vertex Buffer Object deinitialization (memory free)
void rlglClose(void)
{
#if defined(GRAPHICS_API_VULKAN)
// rlvkClose(); // This will be called from rcore.c's CloseWindow
TRACELOG(LOG_INFO, "RLGL: rlglClose called for Vulkan. Expecting rlvkClose to be called from rcore.");
// Unload default batch if managed by rlgl for vulkan
// rlUnloadRenderBatch(RLGL.defaultBatch); // This needs to be Vulkan aware or not done here if rlvk handles it
#else // !defined(GRAPHICS_API_VULKAN)
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
rlUnloadRenderBatch(RLGL.defaultBatch);
@ -2332,6 +2399,7 @@ void rlglClose(void)
glDeleteTextures(1, &RLGL.State.defaultTextureId); // Unload default texture
TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture unloaded successfully", RLGL.State.defaultTextureId);
#endif
#endif // GRAPHICS_API_VULKAN defined check
}
// Load OpenGL extensions
@ -3173,6 +3241,11 @@ bool rlCheckRenderBatchLimit(int vCount)
// Convert image data to OpenGL texture (returns OpenGL valid Id)
unsigned int rlLoadTexture(const void *data, int width, int height, int format, int mipmapCount)
{
#if defined(GRAPHICS_API_VULKAN)
// return rlvkLoadTexture(data, width, height, format, mipmapCount); // Actual call to Vulkan backend
TRACELOG(LOG_DEBUG, "RLGL: rlLoadTexture called (Vulkan path - using stub)");
return 0; // Placeholder for Vulkan
#else
unsigned int id = 0;
glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding
@ -3322,6 +3395,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
else TRACELOG(RL_LOG_WARNING, "TEXTURE: Failed to load texture");
return id;
#endif // GRAPHICS_API_VULKAN
}
// Load depth texture/renderbuffer (to be attached to fbo)
@ -4064,6 +4138,11 @@ void rlUnloadVertexBuffer(unsigned int vboId)
// NOTE: If shader string is NULL, using default vertex/fragment shaders
unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode)
{
#if defined(GRAPHICS_API_VULKAN)
// return rlvkLoadShaderCode(vsCode, fsCode); // Actual call to Vulkan backend
TRACELOG(LOG_DEBUG, "RLGL: rlLoadShaderCode called (Vulkan path - using stub)");
return 0; // Placeholder for Vulkan
#else
unsigned int id = 0;
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
@ -4136,6 +4215,7 @@ unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode)
#endif
return id;
#endif // GRAPHICS_API_VULKAN
}
// Compile custom shader and return shader id
@ -4306,6 +4386,11 @@ int rlGetLocationAttrib(unsigned int shaderId, const char *attribName)
// Set shader value uniform
void rlSetUniform(int locIndex, const void *value, int uniformType, int count)
{
#if defined(GRAPHICS_API_VULKAN)
// rlvkSetUniform(locIndex, value, uniformType, count); // Actual call to Vulkan backend
TRACELOG(LOG_DEBUG, "RLGL: rlSetUniform called (Vulkan path - using stub for locIndex %d)", locIndex);
// No return value, placeholder action is just logging.
#else
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
switch (uniformType)
{
@ -4329,6 +4414,7 @@ void rlSetUniform(int locIndex, const void *value, int uniformType, int count)
// TODO: Support glUniform1uiv(), glUniform2uiv(), glUniform3uiv(), glUniform4uiv()
}
#endif
#endif // GRAPHICS_API_VULKAN
}
// Set shader value attribute

77
src/rlvk.c Normal file
View file

@ -0,0 +1,77 @@
#include "rlvk.h"
#include "utils.h" // For TRACELOG if needed
#include <stdio.h> // For printf in stubs
#include <stdlib.h> // For RL_MALLOC, RL_FREE if used
// Global or static variables for Vulkan state (minimal for stubs)
static bool rlvkReady = false;
void rlvkInit(VkInstance instance, VkSurfaceKHR surface, int width, int height) {
printf("rlvkInit called (STUB)\n");
// Minimal check or setup
if (instance != VK_NULL_HANDLE && surface != VK_NULL_HANDLE) {
rlvkReady = true;
TRACELOG(LOG_INFO, "RLVK: Vulkan backend initialized (stubbed).");
} else {
TRACELOG(LOG_ERROR, "RLVK: Failed to initialize Vulkan backend due to null instance or surface (stubbed).");
rlvkReady = false;
}
}
void rlvkClose(void) {
printf("rlvkClose called (STUB)\n");
rlvkReady = false;
TRACELOG(LOG_INFO, "RLVK: Vulkan backend closed (stubbed).");
}
bool rlvkIsReady(void) {
return rlvkReady;
}
void rlvkBeginDrawing(void) {
// printf("rlvkBeginDrawing called (STUB)\n");
}
void rlvkEndDrawing(void) {
// printf("rlvkEndDrawing called (STUB)\n");
}
void rlvkClearBackground(unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
// printf("rlvkClearBackground called (STUB) with color: %u, %u, %u, %u\n", r, g, b, a);
}
unsigned int rlvkLoadTexture(const void *data, int width, int height, int format, int mipmaps) {
printf("rlvkLoadTexture called (STUB)\n");
return 0; // Return a dummy ID
}
void rlvkUnloadTexture(unsigned int id) {
printf("rlvkUnloadTexture called (STUB) for ID: %u\n", id);
}
unsigned int rlvkLoadShaderCode(const char *vsCode, const char *fsCode) {
printf("rlvkLoadShaderCode called (STUB)\n");
return 0; // Return a dummy ID
}
void rlvkUnloadShaderProgram(unsigned int id) {
printf("rlvkUnloadShaderProgram called (STUB) for ID: %u\n", id);
}
int rlvkGetLocationUniform(unsigned int shaderId, const char *uniformName) {
// printf("rlvkGetLocationUniform called (STUB) for shader ID: %u, uniform: %s\n", shaderId, uniformName);
return -1;
}
int rlvkGetLocationAttrib(unsigned int shaderId, const char *attribName) {
// printf("rlvkGetLocationAttrib called (STUB) for shader ID: %u, attrib: %s\n", shaderId, attribName);
return -1;
}
void rlvkSetUniform(int locIndex, const void *value, int uniformType, int count) {
// printf("rlvkSetUniform called (STUB) for locIndex: %d\n", locIndex);
}
// ... other rlgl equivalent function stub implementations ...
// TRACELOG can be used for more detailed stub logging if utils.h is appropriately included and linked.
// For now, simple printf might be fine for basic stub verification.

36
src/rlvk.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef RLVK_H
#define RLVK_H
#include <vulkan/vulkan.h>
#ifdef __cplusplus
extern "C" {
#endif
// Initialization and Configuration
void rlvkInit(VkInstance instance, VkSurfaceKHR surface, int width, int height); // Simplified, may need more params
void rlvkClose(void);
bool rlvkIsReady(void);
// Drawing
void rlvkBeginDrawing(void);
void rlvkEndDrawing(void);
void rlvkClearBackground(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
// Basic Texture Management (Stubs)
unsigned int rlvkLoadTexture(const void *data, int width, int height, int format, int mipmaps);
void rlvkUnloadTexture(unsigned int id);
// Basic Shader Management (Stubs)
unsigned int rlvkLoadShaderCode(const char *vsCode, const char *fsCode);
void rlvkUnloadShaderProgram(unsigned int id);
int rlvkGetLocationUniform(unsigned int shaderId, const char *uniformName);
int rlvkGetLocationAttrib(unsigned int shaderId, const char *attribName);
void rlvkSetUniform(int locIndex, const void *value, int uniformType, int count);
// ... other rlgl equivalent function declarations as stubs ...
#ifdef __cplusplus
}
#endif
#endif // RLVK_H