From 116191fd8049b43a23d098ed72368389c0069314 Mon Sep 17 00:00:00 2001 From: Krzysztof Szenk Date: Sun, 15 Mar 2026 08:48:55 +0100 Subject: [PATCH 01/41] LibraryConfigurations.cmake: exchanged MATCHES -> STREQUAL in platform choosing if-statements (#5654) * RGFW also requires RGBA8 images as window icons, as raylib already reports in raylib.h * LibraryConfigurations.cmake: exchanged MATCHES -> STREQUAL in platform choosing if-statements --- cmake/LibraryConfigurations.cmake | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake index 2fe05827a..9e7efe792 100644 --- a/cmake/LibraryConfigurations.cmake +++ b/cmake/LibraryConfigurations.cmake @@ -9,7 +9,7 @@ endif() set(RAYLIB_DEPENDENCIES "include(CMakeFindDependencyMacro)") -if (${PLATFORM} MATCHES "Desktop") +if (${PLATFORM} STREQUAL "Desktop") set(PLATFORM_CPP "PLATFORM_DESKTOP") if (APPLE) @@ -67,14 +67,14 @@ if (${PLATFORM} MATCHES "Desktop") endif () endif () -elseif (${PLATFORM} MATCHES "Web") +elseif (${PLATFORM} STREQUAL "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") +elseif (${PLATFORM} STREQUAL "Android") set(PLATFORM_CPP "PLATFORM_ANDROID") set(GRAPHICS "GRAPHICS_API_OPENGL_ES2") set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -94,7 +94,7 @@ elseif (${PLATFORM} MATCHES "Android") set(LIBS_PRIVATE log android EGL GLESv2 OpenSLES atomic c) set(LIBS_PUBLIC m) -elseif ("${PLATFORM}" MATCHES "DRM") +elseif ("${PLATFORM}" STREQUAL "DRM") set(PLATFORM_CPP "PLATFORM_DRM") set(GRAPHICS "GRAPHICS_API_OPENGL_ES2") @@ -113,7 +113,7 @@ elseif ("${PLATFORM}" MATCHES "DRM") set(LIBS_PRIVATE ${GLESV2} ${EGL} ${DRM} ${GBM} atomic pthread dl) set(LIBS_PUBLIC m) -elseif ("${PLATFORM}" MATCHES "SDL") +elseif ("${PLATFORM}" STREQUAL "SDL") # First, check if SDL is included as a subdirectory if(TARGET SDL3::SDL3) message(STATUS "Using SDL3 from subdirectory") @@ -147,7 +147,7 @@ elseif ("${PLATFORM}" MATCHES "SDL") add_compile_definitions(USING_SDL2_PACKAGE) endif() endif() -elseif ("${PLATFORM}" MATCHES "RGFW") +elseif ("${PLATFORM}" STREQUAL "RGFW") set(PLATFORM_CPP "PLATFORM_DESKTOP_RGFW") if (APPLE) @@ -168,7 +168,7 @@ elseif ("${PLATFORM}" MATCHES "RGFW") set(LIBS_PRIVATE ${X11_LIBRARIES} ${OPENGL_LIBRARIES}) endif () -elseif ("${PLATFORM}" MATCHES "WebRGFW") +elseif ("${PLATFORM}" STREQUAL "WebRGFW") set(PLATFORM_CPP "PLATFORM_WEB_RGFW") set(GRAPHICS "GRAPHICS_API_OPENGL_ES2") set(CMAKE_STATIC_LIBRARY_SUFFIX ".a") From 8395374e3d34804fbe7da542edb1fdce43dbb3e8 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 15 Mar 2026 19:17:03 +0100 Subject: [PATCH 02/41] Update HISTORY.md --- HISTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 7f5539816..4fc5569d5 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -533,7 +533,7 @@ Some astonishing numbers for this release: - **+320** closed issues (for a TOTAL of **+2130**!) - **+1800** commits since previous RELEASE (for a TOTAL of **+9600**!) - **18** functions ADDED to raylib API (for a TOTAL of **599**!) - - **??** functions REVIEWED with fixes and improvements + - **+50** new examples to learn from (for a TOTAL of **212**!) - **+200** new contributors (for a TOTAL of **+840**!) Highlights for `raylib 6.0`: From fbec6b05938f39f5e00c4122b5700f66ff161eae Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 15 Mar 2026 19:17:47 +0100 Subject: [PATCH 03/41] ADDED: Most relevant changes for `raylib 6.0` --- CHANGELOG | 761 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 759 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9bfdbe484..1536d4e4c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,10 +17,767 @@ KEY CHANGES: - New File System API - New Text Management API - New tool: [rexm] raylib examples manager + - New examples: +50 new examples and format unification Detailed changes: -TODO... +[rcore] ADDED: Logging and file-system functionality from `utils` (#4551) by @raysan5 -WARNING- +[rcore] ADDED: Flags set/clear macros: FLAG_SET, FLAG_CLEAR, FLAG_IS_SET (#5169) by @raysan5 +[rcore] ADDED: Warnings in case of no platform backend defined by @raysan5 +[rcore] ADDED: `ComputeSHA256()` (#5264) by @iamahuman1395 +[rcore] ADDED: `GetKeyName()` (#4544) by @lecongsebastien +[rcore] REMOVED: GIF recording option, added example by @raysan5 -WARNING- +[rcore] REMOVED: `CORE.Window.fullscreen` variable, using available flag instead by @raysan5 +[rcore] REMOVED: `SetupFramebuffer()`, most platforms do not need it any more by @raysan5 +[rcore] REMOVED: `TRACELOGD()` macro, hardly ever used by @raysan5 +[rcore] RENAMED: Shader location SHADER_LOC_VERTEX_INSTANCETRANSFORMS (#5592) by @CrackedPixel +[rcore] REVIEWED: Gamepads database on latest `SDL2 2.32.8` and `SDL3 3.3.6` #5403 by @raysan5 +[rcore] REVIEWED: Alt-Tab not working in borderless fullscreen (#3865, #4655) by @veins1 +[rcore] REVIEWED: Automation system, saving to memory buffer and binary file (#5476) by @belan2470 +[rcore] REVIEWED: Check if `shader.locs` is not NULL before try to access (#5622) by @maiconpintoabreu +[rcore] REVIEWED: Content scaling on macOS (#5186) by @mchcopl +[rcore] REVIEWED: `GetRandomValue()`, fix modulo bias (#5392) by @Marcos-D +[rcore] REVIEWED: Controller not available after window init (#5358) by @sergii +[rcore] REVIEWED: Cursor lock/unlock inconsistent behaviour (#5323) by @tacf +[rcore] REVIEWED: Description of `RestoreWindow()` by @johnnymarler +[rcore] REVIEWED: Touch position register on automation event handling (#5470) by @belan2470 +[rcore] REVIEWED: FLAG_IS_SET to check if all bits in the flag are set in the value (#5441) by @vushu +[rcore] REVIEWED: Fix for BI_ALPHABITFIELDS for clipbaord image narrow support (#5586) by @crisserpl2 +[rcore] REVIEWED: Flags checks, fixes #5597 by @raysan5 +[rcore] REVIEWED: Fullscreen request #5601 by @raysan5 +[rcore] REVIEWED: HighDPI content scaling on changing monitors with different DPI #5335 #5356 by @raysan5 +[rcore] REVIEWED: HighDPI content scaling on macOS by @raysan5 +[rcore] REVIEWED: Implement `FLAG_WINDOW_ALWAYS_RUN` on Android (#5414) by @caszuu +[rcore] REVIEWED: Init main framebuffer using render size (should be same as currentFbo) by @raysan5 +[rcore] REVIEWED: Platform code formatting and organization by @raysan5 +[rcore] REVIEWED: Replace #pragma message with TRACELOG inside the clipboard image function (#5596) by @maiconpintoabreu +[rcore] REVIEWED: Requested window flags application after window initialization by @raysan5 +[rcore] REVIEWED: Setting some flags disabled fullscreen (#4618, 4619) by @veins1 +[rcore] REVIEWED: Some flags for window/context creation attributes by @raysan5 +[rcore] REVIEWED: Support window flags with initialization issues (#4837) by @Andersama +[rcore] REVIEWED: Swap `TraceLog()` to `TRACELOG` macro (#5226) by @iamahuman1395 +[rcore] REVIEWED: Swap local variable `isCursorHidden` to use new method `IsCursorHidden()` by @maiconpintoabreu +[rcore] REVIEWED: Touch `pointCount` reduction (#4661) by @maiconpintoabreu +[rcore] REVIEWED: Unscale the window size on resize if we are doing automatic HighDPI scaling by @Jeffm2501 +[rcore] REVIEWED: Use `FLAG_*` macros where possible (#5169) by @iamahuman1395 +[rcore] REVIEWED: Wayland checks, using compilation flags when possible #5564 by @raysan5 +[rcore] REVIEWED: `InitWindow()`, issues due to unchecked result of `InitPlatform()` (#4803) by @sleeptightAnsiC +[rcore] REVIEWED: `InitWindow()`, fixed issue when using an empty window title (#5526) by @CrackedPixel +[rcore] REVIEWED: `GetRenderWidth()`, and `GetRenderHeight()`, return the FBO size if one is active by @Jeffm2501 +[rcore] REVIEWED: `GetWindowPosition()`, return internal value by @raysan5 +[rcore] REVIEWED: `ToggleBorderlessFullscreen()`, not hiding taskbar (#5383) by @xenomustache +[rcore] REVIEWED: `IsMouseButton*()`, random key codes return unexpected results (#5516) by @jasoncnm +[rcore] REVIEWED: `IsGamepadButton*()`, for consistency with key and mouse equivalents by @raysan5 +[rcore] REVIEWED: `SetGamepadVibration()`, TRACELOG message (#4615) by @Asdqwe +[rcore] REVIEWED: `MAX_GAMEPAD_AXES` for consistency #4960 by @raysan5 +[rcore] REVIEWED: `MAX_GAMEPAD_NAME_LENGTH` #4695 by @raysan5 +[rcore] REVIEWED: `LoadRandomSequence()`, using `GetRandomValue()` #5393 by @raysan5 +[rcore] REVIEWED: `LoadShaderFromMemory()`, use default locations for default shader #4641 by @raysan5 +[rcore] REVIEWED: `ComputeSHA1()`, computation on messages longer than 31 bytes (#5397) by @me +[rcore] REVIEWED: `ComputeSHA256()` by @raysan5 +[rcore] REVIEWED: `DecodeDataBase64()`, decoding error when input string is invalid (#5170) by @zet23t +[rcore] REVIEWED: `DecodeDataBase64()`, follow convention: by @raysan5 +[rcore] REVIEWED: `DecompressData()`, fixed buffer copying by @raysan5 +[rcore] REVIEWED: `GetClipboardImage()`, make symbol available on all platforms by @raysan5 +[rcore] REVIEWED: `GetRandomValue()`, explained the new approach to get more uniform random values range by @raysan5 +[rcore] REVIEWED: `FileExists()`, using macro by @raysan5 +[rcore] REVIEWED: `IsFileExtension()`, to avoid other modules dependency #5071 by @raysan5 +[rcore] REVIEWED: `LoadDirectoryFilesEx()`, count files if not recursive (#5496) by @katanya04 +[rcore] REVIEWED: `LoadDirectoryFilesEx()`, minor tweak #5569 by @raysan5 +[rcore] REVIEWED: `UnloadDirectoryFiles`, added NULL check by @Bigfoot71 +[rcore] REVIEWED: `ScanDirectoryFiles*()`, #4833 by @raysan5 +[rcore] REVIEWED: `ScanDirectoryFilesRecursively()`, fix issues by @mlorenc +[rcore] REVIEWED: `ScanDirectoryFilesRecursively()`, makes `path` static by @Bigfoot71 +[rcore] REVIEWED: `SaveFileText()`, const input text by @raysan5 +[rcore] REVIEWED: `TakeScreenshot()`, avoid path filtering by @raysan5 +[rcore] REVIEWED: `TakeScreenshot()`, only scale the screenshot by the DPI scale if required by @Jeffm2501 +[rcore] REDESIGNED: Fullscreen modes, use current display resolution by @raysan5 -WARNING- +[rcore] REDESIGNED: `EncodeDataBase64()`/`DecodeDataBase64()`, use NULL terminated strings by @raysan5 -WARNING- +[rcore][GLFW] ADDED: Clipboard image support for linux (#5603) by @maiconpintoabreu +[rcore][GLFW] REVIEWED: Fix `IsWindowFocused()` inverted logic (#5333) by @iamahuman1395 +[rcore][GLFW] REVIEWED: Fullscreen modes on Linux (X11 over XWayland) by @raysan5 +[rcore][GLFW] REVIEWED: Make sure that GLFW uses RL_*ALLOC macros (#4777) by @sleeptightAnsiC +[rcore][GLFW] REVIEWED: Set correct default axes for gamepads that are not connected (#5444) by @LeapersEdge +[rcore][GLFW] REVIEWED: Window initialization on HighDPI monitor (Windows) #5549 by @raysan5 +[rcore][GLFW] REVIEWED: Window scaling on Wayland with GLFW 3.4+ (#5564) by @0xPD33 +[rcore][GLFW] REVIEWED: Window scaling with HighDPI on macOS #5059 by @raysan5 +[rcore][GLFW] REVIEWED: `InitPlatform()`, crash caused by `glfwCreateWindow()` (#4804) by @sleeptightAnsiC +[rcore][GLFW] REVIEWED: `InitPlatform()`, code simplification by @raysan5 +[rcore][GLFW] REVIEWED: `GetWindowHandle()`, return correct handle under Linux X11 by @Didas72 +[rcore][GLFW] REVIEWED: `WindowSizeCallback()` by @raysan5 +[rcore][GLFW] REVIEWED: `CORE.Window.eventWaiting` and `FLAG_WINDOW_ALWAYS_RUN` handling (#4642) by @Asdqwe +[rcore][GLFW] REVIEWED: `GetGamepadButtonPressed()`, return GAMEPAD_BUTTON_*_TRIGGER_2 if pressed (#4742) by @whaleymar +[rcore][GLFW] REVIEWED: Update `mappings.h` using `GenerateMappings.cmake` by @sleeptightAnsiC +[rcore][RGFW] ADDED: New backend option: `PLATFORM_WEB_RGFW` and update RGFW (#4480) by @colleagueRiley +[rcore][RGFW] REVIEWED: Added missing Right Control key by @M374LX +[rcore][RGFW] REVIEWED: Changed `RGFW_window_eventWait` timeout to -1 by @doggymangc +[rcore][RGFW] REVIEWED: Duplicate entries reemoved from `keyMappingRGFW` (#5242) by @iamahuman1395 +[rcore][RGFW] REVIEWED: Fix Escape always closing the window by @M374LX +[rcore][RGFW] REVIEWED: Forward declare the windows stuff, prevents failures in GCC (#5269) by @Jeffm2501 +[rcore][RGFW] REVIEWED: Requires RGBA8 images as window icons (#5431) by @crisserpl2 +[rcore][RGFW] REVIEWED: Window width calculation by adding wOffset (#5457) by @qubitxr +[rcore][RGFW] REVIEWED: `SetGamepadVibration()` implementation (#4612) by @JupiterRider +[rcore][SDL] REVIEWED: `FLAG_WINDOW_ALWAYS_RUN` implementation (#4598) by @Asdqwe +[rcore][SDL] REVIEWED: First touch position is overwritten with mouse position by @zet23t +[rcore][SDL] REVIEWED: Avoid `rtext` module dependency #4959 by @raysan5 +[rcore][SDL] REVIEWED: Fix crash when `strncpy()` tries to copy using NULL pointer (#5359) by @MikiZX1 +[rcore][SDL] REVIEWED: Fix gamepad detection (#5176) by @brccabral +[rcore][SDL] REVIEWED: Fix maximizing, minimizing and restoring windows for SDL2 (#4607) by @Asdqwe +[rcore][SDL] REVIEWED: Fix show, hide, focus and unfocus window/flags states for SDL2 (#4610) by @Asdqwe +[rcore][SDL] REVIEWED: Fix text input (characters) (#5574) by @TheKodeToad +[rcore][SDL] REVIEWED: Gamepad event handling by adding joystick instance id tracking (#4724) by @Asdqwe +[rcore][SDL] REVIEWED: RGB order on SDL3 #3568 by @raysan5 +[rcore][SDL] REVIEWED: `SetGamepadMappings()` (#5548) by @arleyuti +[rcore][SDL] REVIEWED: Handle monitor ID correctly on SDL3 (#5290) by @sleeptightAnsiC +[rcore][Web] ADDED: Clipboard image implementation for web (#5614) by @maiconpintoabreu +[rcore][Web] ADDED: `GetWindowScaleDPI()`, implementation for PLATFORM_WEB (#4526) by @Asdqwe +[rcore][Web] ADDED: `IsWindowHidden()` (#4789) by @marionauta +[rcore][Web] REVIEWED: Fix reversed window blur/focus logic for web (#5590) by @aceiii +[rcore][Web] REVIEWED: Fix undeclared canvas variable error (#5507) by @vdemcak +[rcore][Web] REVIEWED: Replaced hardcoded canvas id references with module variable (#4735) by @zet23t +[rcore][Web] REVIEWED: Store canvas name id at platform initialization by @raysan5 +[rcore][Web] REVIEWED: Support software renderer on Web, blitting framebuffer data directly to a 2d canvas by @raysan5 +[rcore][Web] REVIEWED: Using `Module` provided canvas id for event binding (#4690) by @zet23t +[rcore][Web] REVIEWED: Using `EmscriptenKeyboardCallback()` to consume key events by @moros1138 +[rcore][Web] REVIEWED: `IsWindowFocused()` (#4640) by @marionauta +[rcore][Web] REVIEWED: `GetApplicationDirectory()` for Wasm, returning root VFS (#5495) by @git +[rcore][Win32] ADDED: `rcore_desktop_win32`, new native Win32 platform backend (#4869) by @johnnymarler +[rcore][Win32] REDESIGNED: New native Win32 platform backend, simplification and formating by @raysan5 +[rcore][Win32] REVIEWED: New Win32 platform backend to accomodate `rlsw` Software Renderer by @raysan5 +[rcore][Win32] REVIEWED: Fix window width calculation by adding wOffset (#5480) by @crisserpl2 +[rcore][Win32] REVIEWED: Implemented `SetWindowMaxSize()`, `SetWindowMinSize()` and `SetWindowSize()` (#5536) by @mikeemm +[rcore][Win32] REVIEWED: Remove `-fno-stack-protector` and add `requestFullscreen` on exported methods by @emilhakimov415 +[rcore][Win32] REVIEWED: VSync flag not being applied (#5521) by @mikeemm +[rcore][Win32] REVIEWED: Window minimizing/maximizing functionality (#5524) by @mikeemm +[rcore][Android] REVIEWED: Content scaling functionality for HighDPI (#4769) by @Bigfoot71 +[rcore][Android] REVIEWED: `SetWindowState()` (#5424) by @caszuu +[rcore][Android] REVIEWED: `GetCurrentMonitor()` implementation (#5204) by @guntzjonas +[rcore][Android] REVIEWED: `android_fopen()` mechanims, after removing `utils` module dependency by @raysan5 +[rcore][Android] REVIEWED: `fopen()` wrapping mechanism, to use --wrap=fopen on build systems (#5624) by @ghera +[rcore][Android] REVIEWED: `LoadMusicStream()` due to missing fopen redirect (#5589) by @ghera +[rcore][Android] REVIEWED: Fallback on dirent filename when all route fails (#5484) by @lucas150670 +[rcore][Android] REVIEWED: Gesture system not reporting GESTURE_NONE (#5452) by @padmadevd +[rcore][Android] REVIEWED: Keyboard input detected as gamepad on some devices (#5439) by @decruz +[rcore][Android] REVIEWED: Replaced `android_fopen()` with linker `--wrap=fopen` (#5605) by @ghera +[rcore][DRM] ADDED: Support asynchronous page-flipping and framebuffer caching by @rob-bits -WARNING- +[rcore][DRM] REVIEWED: Compiler flag SUPPORT_DRM_CACHE, to enable triple buffered DRM caching by @rob-bits +[rcore][DRM] REVIEWED: Backspace key in RPI SSH keyboard by @matthijs +[rcore][DRM] REVIEWED: Check if video mode is valid and rename to match with other methods (#5235) by @maiconpintoabreu +[rcore][DRM] REVIEWED: Disable touch position simulation from mouse movement for touchscreen devices (#5279) by @MULTidll +[rcore][DRM] REVIEWED: Fix resources memory leak (#5494) by @matthewkennedy +[rcore][DRM] REVIEWED: Platform initialization messages by @raysan5 +[rcore][DRM] REVIEWED: Use `eglGetPlatformDisplayEXT()` for Mali compatibility (#5446) by @decruz +[rcore][DRM] REVIEWED: `FindNearestConnectorMode()`, prefer mode with smallest number of unused pixels (#5158) by @maiphi +[rcore][DRM] REVIEWED: `eglGetPlatformDisplay()` usage by @raysan5 +[rcore][DRM] REVIEWED: Improved touch input handling and multitouch support (#5447) by @MULTidll +[rcore][DRM] REVIEWED: DRM cache buffers support #4988 by @raysan5 +[rlgl] ADDED: Software Rendering Support (#4832) by @Bigfoot71 +[rlgl] ADDED: `rlGetProcAddress()` (#5062) by @danilwhale +[rlgl] ADDED: `rlUnloadShader()` (#5631) by @raysan5 +[rlgl] REMOVED: `RLGL_RENDER_TEXTURES_HINT`, enabled by default and no complaints of anyone having issues #5479 by @raysan5 +[rlgl] REVIEWED: Allow tint colors in GL_LINE (wires) and GL_POINT (points) draw modes on OpenGL 1.1 clean (#5207) by @lanur622 +[rlgl] REVIEWED: Attribute name and location, for consistency by @raysan5 +[rlgl] REVIEWED: Behavior for texture in OpenGL 1.1 draw states (#5328) by @lanur622 +[rlgl] REVIEWED: Better default values for normals and tangents (VBOs) (#4763) by @Bigfoot71 +[rlgl] REVIEWED: Clean up Matrix handling and rl* functions to follow convention (#5505) by @nathanmburg +[rlgl] REVIEWED: Delete shader object in case compilation fails by @raysan5 +[rlgl] REVIEWED: Fixed shader tangents to be vec4 by @Sir-Irk +[rlgl] REVIEWED: Increased depth size and clip distances to avoid z-fighting issues by @raysan5 +[rlgl] REVIEWED: Issues compiling for OpenGL 1.1 #5088 by @raysan5 +[rlgl] REVIEWED: Make sure ShaderUniformDataType matches rlShaderUniformDataType (#4577) by @RicoP +[rlgl] REVIEWED: Potential issue with animated normals on OpenGL 1.1 by @raysan5 +[rlgl] REVIEWED: Using define for buffers size by @raysan5 +[rlgl] REVIEWED: Warning log macro (#5043) by @vinnyhorgan +[rlgl] REVIEWED: Preserve texture on mode switching (#4364) by @Destructor17 +[rlgl] REVIEWED: Proposed fix for default near/far clipping range (#4906) by @Bigfoot71 +[rlgl] REVIEWED: `rlLoadTexture()`, max mipmap levels to use #5400 by @raysan5 +[rlgl] REVIEWED: `rlLoadTexture()`, uncomplete texture do to issue on mipmap loading #5416 by @raysan5 +[rlgl] REVIEWED: `rlLoadTextureDepth()`, address inconsistencies with WebGL 2.0 for sized depth formats #5500 by @raysan5 +[rlgl] REVIEWED: `rlReadScreenPixels()`, optimizations (#4667) by @pope +[rlgl] REVIEWED: `rlSetTexture()` not overriding default mode (#5200) by @maiconpintoabreu +[rlgl] REVIEWED: `rlActiveDrawBuffers`, fix for OpenGL ES 3.0 (#4605) by @Bigfoot71 +[rlgl] REVIEWED: `rlGetPixelDataSize()`, correct compressed data size calculation per blocks #5416 by @raysan5 +[rlgl] REVIEWED: `instranceTransform` shader location index #4538 (#4579) by @meadiode +[rlgl] REVIEWED: `SetShaderValueTexture()`, updatee comments (#4703) by @pejorativefox +[rlgl] REDESIGNED: Avoid program crash if GPU data is tried to be loaded before `InitWindow()` #4751 by @raysan5 -WARNING- +[rlgl] REDESIGNED: Shader loading API function names for more consistency #5631 by @raysan5 -WARNING- +[rlsw] ADDED: `swGetColorBuffer()` for convenience by @raysan5 +[rlsw] REVIEWED: Completeness of `glDraw*()` functions (#5304) by @Bigfoot71 +[rlsw] REVIEWED: Fix axis aligned quad detection (#5314) by @Bigfoot71 +[rlsw] REVIEWED: Fix clipping issue on software render (#5342) by @Bigfoot71 +[rlsw] REVIEWED: Make sure SSE is being used when compiling with MSVC by @raysan5 +[rlsw] REVIEWED: SIMD instrinsics must be explicitly enabled by developer, only SSE supported at the moment #5316 by @raysan5 +[rlsw] REVIEWED: Segmentation fault when trying to render a model (#5622) by @maiconpintoabreu +[rlsw] REVIEWED: Simplify framebuffer logic and add blit/copy fast path (#5312) by @Bigfoot71 +[rlsw] REVIEWED: Review depth formats and fix depth writing (#5317) by @Bigfoot71 +[rlsw] REVIEWED: Smarter texture management (#5296) by @Bigfoot71 +[rlsw] REVIEWED: Subpixel correction (#5300) by @Bigfoot71 +[rlsw] REVIEWED: C++ support (#5291) by @alexgb0 +[rshapes] ADDED: `DrawLineDashed()` (#5222) by @luis605 +[rshapes] ADDED: `DrawEllipseV()` and `DrawEllipseLinesV()` (#4963) by @meowstr +[rshapes] REVIEWED: `DrawLine()`, fix pixel offset issue on drawing (#4666) by @Bigfoot71 +[rshapes] REVIEWED: `DrawRectangleGradientEx()`, incorrect parameter names (#4980) by @vincent +[rshapes] REVIEWED: `DrawRectangleLines`, fix pixel offset issue (#4669) by @Bigfoot71 +[rshapes] REVIEWED: `DrawRectangleRounded()`, allow to draw rectangles with a size < 1 (#4683) by @tea +[rshapes] REVIEWED: `CheckCollisionLines()`, formating and follow raylib conventions by @raysan5 +[rshapes] REVIEWED: `DrawCircleSector*()`, optimization to prevent division by zero (#4843) by @theundergroundsorcerer +[rshapes] REVIEWED: `CheckCollisionLines()`, properly detect collision if one line is almost vertical (#5510, #5531) by @bielern +[rtextures] REVIEWED: Cubemap mipmap loading improvements (#4721) by @Not-Nik +[rtextures] REVIEWED: Setting mipmaps MAX_LEVEL based on actual mipcount input (#4622) by @JettMonstersGoBoom +[rtextures] REVIEWED: TCC compilation due to `emmintrin.h` not found (#4707) by @sleeptightAnsiC +[rtextures] REVIEWED: `Image`, initialization align to avoid issues with some platforms (#5214) by @psxdev +[rtextures] REVIEWED: `LoadImageDataNormalized()`, missing increments of k (#4745) by @henrikglass +[rtextures] REVIEWED: `LoadImageFromScreen()`, use the render size instead of screen size (#5192) by @JeffM2501 +[rtextures] REVIEWED: `GenImageFontAtlas()`, fix memory corruption in reallocation (#5602) by @creeperblin +[rtextures] REVIEWED: `GenImageFontAtlas()`, no need for the conservative approach flag by @raysan5 +[rtextures] REVIEWED: `GenImageFontAtlas()`, scale image to fit all characters, in case it fails size estimation #5542 by @raysan5 +[rtextures] REVIEWED: `GetImageColor()` (#5560) by @raysan5 +[rtextures] REVIEWED: `ExportImage()` by @raysan5 +[rtextures] REVIEWED: `HalfToFloat()` and `FloatToHalf()` dereferencing issues with an union (#4729) by @Asdqwe +[rtextures] REVIEWED: `ImageClearBackground()` and `ImageDrawRectangleRec()` optimizations (#5363) by @ChocolateChipKookie +[rtextures] REVIEWED: `ImageColorReplace()`, alpha issue replacement (#5047) by @RomainPlmg +[rtextures] REVIEWED: `ImageDrawLineEx(), to be able to draw even numbered thicknesses (#5042) by @Sir-Irk +[rtextures] REVIEWED: `ImageBlurGaussian()`, fix integer overflow in cast (#5037) by @garrisonhh +[rtext] ADDED: `LoadTextLines()`/`UnloadTextLines()` by @raysan5 +[rtext] ADDED: `MeasureTextCodepoints()` for direct measurement of codepoints (#5623) by @creeperblin +[rtext] RENAMED: Variable names for consistency, `textLength` (length in bytes) vs `textSize` (measure in pixels) by @raysan5 +[rtext] REVIEWED: Support default font loading with no GPU enabled, to be used with Image API +[rtext] REVIEWED: Default font alpha on Big Endian systems (#4624) by @Fancy2209 +[rtext] REVIEWED: Font atlas image generation, added some comments #5141 by @raysan5 +[rtext] REVIEWED: Multiply security checks to avoid crashes on wrongly provided string data (#4751) by @raysan5 +[rtext] REVIEWED: Potential security concerns while copying unbounded text data between strings by @raysan5 +[rtext] REVIEWED: Properly clean up the default font on unload, it may be reused if the window is created again by @Jeffm2501 +[rtext] REVIEWED: Remove some `const` from text buffer return values by @raysan5 +[rtext] REVIEWED: Some security vulnerabilities in font loading (#5433, #5434, #5436, #5450) by @oneafter +[rtext] REVIEWED: Use `const` for codepoints arrays passed to function #5159 by @raysan5 +[rtext] REVIEWED: Use `strstr()` instead of `TextFindIndex()` (#4764) by @brabissimoooooo +[rtext] REVIEWED: `LoadFont()`, improve load message (#5050) by @katanya04 +[rtext] REVIEWED: `LoadFont*()`, provide more detailed info on glyphs failing to pack (#5141) by @raysan5 +[rtext] REVIEWED: `LoadCodepoints()`, local variable shadowing `codepoints` (#5430) by @KiviTK +[rtext] REVIEWED: `LoadCodepoints()`, comment explaining functionality (#4787) by @loftafi +[rtext] REVIEWED: `LoadFontFromImage()`, limit pixel scanning to image dimensions (#5626) by @joe +[rtext] REVIEWED: `LoadFontDataBDF()` #5346 by @raysan5 +[rtext] REVIEWED: `LoadTextLines()` by @raysan5 +[rtext] REVIEWED: `ExportFontAsCode()` #5497 by @raysan5 +[rtext] REVIEWED: `ExportFontAsCode()` not checking `isGpuReady` #4894 by @raysan5 +[rtext] REVIEWED: `GetCodepointCount()`, misuse of cast (#4741) by @sleeptightAnsiC +[rtext] REVIEWED: `GenImageFontAtlas()`, memory corruption and invalid size calculation (#5602) by @konakona418 +[rtext] REVIEWED: `TextInsert()`, fix bug on insertion (#5644) by @CrackedPixel +[rtext] REVIEWED: `TextJoin()`, convert `const char **` to `char**` by @raysan5 +[rtext] REVIEWED: `TextReplace()` and `TextLength()`, avoid using `strcpy()` by @raysan5 +[rtext] REVIEWED: `TextReplace()` by @raysan5 +[rtext] REVIEWED: `TextReplace()`, improvements (#5511) by @belan2470 +[rtext] REVIEWED: `TextReplaceBetween()` by @raysan5 +[rtext] REVIEWED: `TextSubtext(), fixes (#4759) by @veins1 +[rtext] REVIEWED: `TextToPascal()`, fix issue by @raysan5 +[rtext] REVIEWED: `TextToFloat()`, remove removed inaccurate comment (#4596) by @hexmaster111 +[rtext] REDESIGNED: `LoadFontData()`, added input parameter by @raysan5 -WARNING- +[rmodels] ADDED: Support CPU animation in OpenGL 1.1 (#4925) by @JeffM2501 +[rmodels] RENAMED: Skinning shader variables (new default naming) by @raysan5 +[rmodels] REVIEWED: glTF animation framerate calculation (#4472, #5445) by @TheLazyIndianTechie +[rmodels] REVIEWED: Assign meshes without bone weights to the bone they are attached to so they animate by @Jeffm2501 +[rmodels] REVIEWED: Out of bound memory read in `Material.maps` (#5534) by @Sumethh +[rmodels] REVIEWED: Segfaults with animation system (#4635) by @JettMonstersGoBoom +[rmodels] REVIEWED: Transform the vertex normals by the animated matrix (#4646) by @Jeffm2501 +[rmodels] REVIEWED: Use the animated verts and normals in OpenGL 1.1 if they exist by @Jeffm2501 +[rmodels] REVIEWED: GLTF bone weight assignments for meshes parented to armature (#4923) by @JeffM2501 +[rmodels] REVIEWED: `LoadOBJ()`, avoid fatal errors on OBJ model loading by @raysan5 +[rmodels] REVIEWED: `LoadOBJ()`, don't upload meshes, `LoadModel()` will upload them (#5083) by @JeffM2501 +[rmodels] REVIEWED: `LoadOBJ()`, loading crash when there are no normals present (#5079) by @zet23t +[rmodels] REVIEWED: `LoadGLFT()`, avoid loading attributes already loaded (#4996) by @raysan5 +[rmodels] REVIEWED: `LoadGLTF()`, anim correctly inherits world transform (#5206) by @ArmanOmmid +[rmodels] REVIEWED: `LoadGLTF()`, fix memory leak when model has no bones (#5629) by @vberdugo +[rmodels] REVIEWED: `LoadGLTF()`, fixing offset for processing tangents (#5015) by @Sir-Irk +[rmodels] REVIEWED: `LoadGLTF()`, log warning about draco compression not supported #5567 by @raysan5 +[rmodels] REVIEWED: `LoadGLTF()`, separate roughness and metallic channels on load (#4739) by @Not-Nik +[rmodels] REVIEWED: `LoadGLTF()`, support 16 bit vec3 values (#5388) by @Jeffm2501 +[rmodels] REVIEWED: `LoadGLTF()`, fixed NULL pointer dereference (#4564) by @CalebHeydon +[rmodels] REVIEWED: `LoadIQM()` and `LoadModelAnimationsIQM()`, fix memory leaks (#4649) by @peter15914 +[rmodels] REVIEWED: `LoadM3D()`, don't require a M3d animation only file to have a mesh (#5475) by @Jeffm2501 +[rmodels] REVIEWED: `LoadImageFromCgltfImage()`, fix crash when NULL is passed (#4563) by @CalebHeydon +[rmodels] REVIEWED: `LoadImageFromCgltfImage()`, fix NULL pointer dereference (#4557) by @CalebHeydon +[rmodels] REVIEWED: `LoadModelAnimationsGLTF()`, properly load 1 frame animations (#5561) by @arlez80 +[rmodels] REVIEWED: `LoadModelAnimationsGLTF()`, anim correctly inherits world transform (#5206) by @ArmanOmmid +[rmodels] REVIEWED: `UploadMesh()`, improve default normal and tangent values (#4763) by @Bigfoot71 +[rmodels] REVIEWED: `GenMeshTangents()`, improvements (#4937) by @Bigfoot71 +[rmodels] REVIEWED: `UpdateModelAnimation()` optimization (#5244) by @Arrangemonk +[rmodels] REVIEWED: `UpdateModelAnimationBones()`, break on first mesh found and formating by @raysan5 +[rmodels] REVIEWED: `UpdateModelAnimationBones()`, fix normal transform (#4634) by @Bigfoot71 +[rmodels] REVIEWED: `UpdateModelAnimationBones()`, optimizations (#4602) by @Kirandeep-Singh-Khehra +[rmodels] REVIEWED: `UpdateModelAnimationBones()`, bones animation scale (#4896) by @mUnicorn +[rmodels] REVIEWED: `DrawBillboardPro()`, flipped texture source rectangle draw correctly (#5276) by @aixiansheng +[rmodels] REVIEWED: `DrawMesh()`, OpenGL11 fixes added texture consistency check (#5328) by @meisei4 +[rmodels] REVIEWED: `DrawMeshInstanced()`, breaking if instanceTransform was unused (#5469) by @al13n321 +[rmodels] REVIEWED: `DrawSphereEx()`, normals support (#4926) by @karl-zylinski +[rmodels] REVIEWED: `ExportMesh()`, improve OBJ vertex data precision and lower memory usage (#4496) by @mikeemm +[raudio] REVIEWED: Fix a glitch at the end of a sound (#5578) by @mackron +[raudio] REVIEWED: Improvements to device configuration (#5577) by @mackron +[raudio] REVIEWED: Initialize sound alias properties as if it was a new sound (#5123) by @JeffM2501 +[raudio] REVIEWED: Music stopping some frames too early by @veins1 +[raudio] REVIEWED: Remove usage of `ma_data_converter_get_required_input_frame_count()` (#5568) by @mackron +[raudio] REVIEWED: Better computation of the default audio stream buffer size (#4898) by @JeffM2501 +[raudio] REVIEWED: Documentation for audio stream processor, number of channels (#4753) by @goto40 +[raudio] REVIEWED: `LoadWAV()`, fixed buffer overflow when loading WAV files (#4539) by @CalebHeydon +[raudio] REVIEWED: `LoadMusicStream()`, issues in Android due to missing fopen redirect (#5589) by @ghera +[raudio] REVIEWED: `LoadMusicStreamFromMemory()` for QOA, reduced the number of allocs and memcpy (#5108) by @lassade +[raudio] REVIEWED: `UnloadMusicStream()`, properly close FLAC (#5133) by @rossberg +[raudio] REVIEWED: `UpdateMusicStream()`, prevent to run without music playing (#5046) by @maiconpintoabreu +[raudio] REVIEWED: `WaveFormat()`, fixed memory leak on early-return (#4779) by @deckarep +[raudio] REVIEWED: `WaveFormat()`, freeing memory issue (#5481) by @MarcosTypeAP +[raudio] REVIEWED: `GetMusicTimePlayed()`, fix music shorter than buffer size (#5048) by @veins1 +[raudio] REVIEWED: `GetMusicTimePlayed()`, returns incorrect time after restart (#4914) by @Servall4 +[raudio] REDESIGNED: `SetSoundPan()` and `SetMusicPan()` ranges from [-1.0..1.0] (#5350) by @raysan5 -WARNING- +[raymath] ADDED: `MatrixUnit()` and `MatrixMultiplyValue()` (#5613) by @lamweilun +[raymath] ADDED: `MatrixCompose()` (#5324) by @EDBCREPO +[raymath] ADDED: `Vector2CrossProduct()` (#4520) by @uwiwiow +[raymath] REVIEWED: Fix C++ operator overloads (#4535) by @ListeriaM +[raymath] REVIEWED: Vector2Angle(), detailed documentation (#4556) by @mrjonjonjon +[raymath] REVIEWED: Wrap float3 and float16 for consistency with other types (#5540) by @n-s-kiselev +[raymath] REVIEWED: `HalfToFloat()`, fix mantissa hex value by @backspaceoverload +[raymath] REVIEWED: `MatrixCompose()` by @raysan5 +[raymath] REVIEWED: `MatrixDeterminant()` #4780 by @raysan5 +[raymath] REVIEWED: `MatrixDecompose()` removes shear (#5201) by @ArmanOmmid +[raymath] REVIEWED: `MatrixMultiply()` intrinsics support: SSE (#5427) by @mcdubhghlas +[raymath] REVIEWED: `QuaternionFromVector3ToVector3()` (#5508) by @The4codeblocks +[rcamera] REVIEWED: `Camera3D.fovy` description (#5164) by @0stamina +[rcamera] REVIEWED: Camera move up and right work with Z up cameras (#5458) by @Jeffm2501 +[rcamera] REVIEWED: Camera pan speed (#5554) by @CrackedPixel +[rcamera] REVIEWED: Fix camera initial position (#4657) by @Asdqwe +[rcamera] REVIEWED: Clamp camera pitch (#5137) by @feive7 + +[build][CI] ADDED: ARM64 with Visual Studio (#4781) by @Peter0x44 +[build][CI] ADDED: `update_examples.yml` by @raysan5 +[build][CI] RENAMED: GitHub Actions files, clearer naming by @raysan5 +[build][CI] REVIEWED: Linux workflow to run on `ubuntu-latest` by @raysan5 +[build][CI] REVIEWED: Remove double zip and misleading zip type (#5512) by @maiconpintoabreu +[build][CI] REVIEWED: `update_examples.yml` workflow (#5130) by @iamahuman1395 +[build][Script] REVIEWED: `build_example_web.bat` by @raysan5 +[build][Make] ADDED: ARM64 support to Linux builds by @quaylynrimer11 +[build][Make] REVIEWED: Use `libraylib.web.a` naming on PLATFORM_WEB by @raysan5 -WARNING- +[build][Make] REVIEWED: Only include rglfw.c for glfw platform by @johnnymarler +[build][Make] REVIEWED: Fix template to support `libraylib.web.a` (#5620) by @skazu0611 +[build][Make] REVIEWED: Avoid using != assignment (#5464) by @sleeptightAnsiC +[build][Make] REVIEWED: Improve support for `PLATFORM_DESKTOP_WIN32` (#5311) by @GithubPrankster +[build][Make] REVIEWED: Latest NDK version compiling errors on Android (#5389) by @Sethbones +[build][Make] REVIEWED: Makefile to support software renderer by @raysan5 +[build][Make] REVIEWED: Properly detect if ABI is Android by @lumenkeyes +[build][Make] REVIEWED: Remove path override/change for linux (#5641) by @CrackedPixel +[build][Make] REVIEWED: Renamed `PLATFORM_DESKTOP_SDL3` to `USING_VERSION_SDL3` #5175 by @raysan5 +[build][Make] REVIEWED: Tag to locate examples list: `#EXAMPLES_LIST_*` by @raysan5 +[build][Make] REVIEWED: Undefine _GNU_SOURCE for rglfw building (#4732) by @Peter0x44 +[build][Make] REVIEWED: `-sASSERTIONS` usage by linker #4717 by @raysan5 +[build][Make] REVIEWED: `Makefile.Web` per-example target generation including used resources by @raysan5 +[build][Make] REVIEWED: android-libc.txt generation by @lumenkeyes +[build][Make] REVIEWED: examples Makefile PLATFORM define (#4582) by @Asdqwe +[build][VS2022] ADDED: Filters and platform files in MSVC for ease of editing (#4644) by @Jeffm2501 +[build][VS2022] REVIEWED: Default raylib resource file .rc for projects by @raysan5 +[build][VS2022] REVIEWED: Fix MSVC warnings (#5619) by @Jeffm2501 +[build][VS2022] REVIEWED: MSVC warnings (#5595) by @Jeffm2501 +[build][VS2022] REVIEWED: Fixed VS2022 broken build by @alexander_nichols +[build][VSCode] REVIEWED: Makefile for `PLATFORM_WEB` (#5620) by @takenoko-pm +[build][CMake] ADDED: Support for SDL3, reviewed SDL2 package cheking by @kariem2k +[build][CMake] ADDED: emscripten build options (#5180) by @brccabral +[build][CMake] ADDED: QNX EGL 2.0 library configuration (#5499) by @jscaffidi +[build][CMake] REVIEWED: Android configuration issues (#4671) by @Bigfoot71 +[build][CMake] REVIEWED: Definition to use SDL3 (#5175) by @brccabral +[build][CMake] REVIEWED: X11 libraries as glfw make private (#5625) by @maiconpintoabreu +[build][CMake] REVIEWED: Don't build examples using audio if audio is disabled (#4652) by @Peter0x44 +[build][CMake] REVIEWED: Export automatically raylib definitions and compile/link options (#5179) by @brccabral +[build][CMake] REVIEWED: Expose RGFW platform backend (#5386) by @Sethbones +[build][CMake] REVIEWED: Set PLATFORM to Web by default when configuring web builds with emcmake (#4748) by @gilzoide +[build][CMake] REVIEWED: Set correct description for verbose option by @brccabral +[build][CMake] REVIEWED: Set version to 3.12 (#4547) by @zyperpl +[build][CMake] REVIEWED: Update `LibraryConfigurations.cmake (#5617) by @m0391n +[build][CMake] REVIEWED: Use STATIC lib ON by default (#4799) by @brccabral +[build][CMake] REVIEWED: Using addCMacro instead of defineCMacro (#4620) by @Joonsey +[build][CMake] REVIEWED: Web compilation system (#5181) by @brccabral +[build][CMake] REVIEWED: Set `libm` as public so it can be linked by consumer (#5193) by @brccabral +[build][Cmake] REVIEWED: Expose PLATFORM_WEB_RGFW (#5579) by @crisserpl2 +[build][Zig] ADDED: Android target to build by @lumenkeyes +[build][Zig] REVIEWED: Link EGL for Android by @lumenkeyes +[build][Zig] REVIEWED: Approach to build for web with zig-build (#5157) by @haxsam +[build][Zig] REVIEWED: Fix build accessing env vars (#5490) by @iisakki +[build][Zig] REVIEWED: Fix emscripten building by @johnnymarler +[build][Zig] REVIWED: Move examples/build.zig into main build.zig by @johnnymarler +[build][Zig] REVIEWED: Fix raygui inclusion in windows crosscompilation (#4489) by @kimierik +[build][Zig] REVIEWED: Issue on emscripten run if the user has not installed emsdk by @emilhakimov415 +[build][Zig] REVIEWED: Make X11 the default display backend instead of choosing at runtime (#5168) by @Not-Nik +[build][Zig] REVIEWED: Using `addLibrary()` and set root modules manually by @myQwil +[build][Zig] REVIEWED: `build.zig.zon`, use the new zig v0.14 version (#4819) by @zewenn +[build][Zig] REVIEWED: `build.zig.zon`, update hashes (#4826) by @david +[build][Zig] REVIEWED: Improve build system (#4531) by @haxsam +[build][Zig] REVIEWED: Properly generate Android triple by @lumenkeyes +[build][Zig] REVIEWED: XCode-frameworks dependency for latest zig (#4675) by @mobiuscog + +[examples] ADDED: Missing examples VS2022 projects by @raysan5 +[examples] ADDED: Missing glsl120 shaders by @raysan5 +[examples] ADDED: Missing resources on some examples by @raysan5 +[examples] ADDED: `core_3d_fps_controller` by @agnis16 +[examples] ADDED: `core_clipboard_text` (#5231) by @robinsaviary +[examples] ADDED: `core_delta_time` (#5216) by @robinsaviary +[examples] ADDED: `core_directory_files` (#5230) by @hugo +[examples] ADDED: `core_highdpi_testbed` by @raysan5 +[examples] ADDED: `core_highdpi_demo` example by @johnnymarler +[examples] ADDED: `core_input_actions` (#5211) by @JettMonstersGoBoom +[examples] ADDED: `core_keyboard_testbed` by @raysan5 +[examples] ADDED: `core_monitor_change` (#5215) by @maiconpintoabreu +[examples] ADDED: `core_render_texture` by @raysan5 +[examples] ADDED: `core_text_file_loading` (#5278) by @NimComPoo-04 +[examples] ADDED: `core_undo_redo` by @raysan5 +[examples] ADDED: `core_viewport_scaling` (#5313) by @agnis16 +[examples] ADDED: `core_compute_hash` by @raysan5 +[examples] ADDED: `shapes_ball_physics` (#5372) by @davidbuzatto +[examples] ADDED: `shapes_bullet_hell` (#5218) by @zerohorsepower +[examples] ADDED: `shapes_clock_of_clocks` (#5263) by @themushroompirates +[examples] ADDED: `shapes_clock_of_clocks` by @hmz-rhl +[examples] ADDED: `shapes_dashed_line` (#5222) by @luis605 +[examples] ADDED: `shapes_double_pendulum` by @joecheong2006 +[examples] ADDED: `shapes_hilbert_curve` (#5454) by @hmz-rhl +[examples] ADDED: `shapes_kaleidoscope` (#5233) by @hugo +[examples] ADDED: `shapes_lines_drawing` (#5283) by @robinsaviary +[examples] ADDED: `shapes_math_angle_rotation` (#5236) by @krispysnacc +[examples] ADDED: `shapes_math_sine_cosine` (#5257) by @Jopestpe +[examples] ADDED: `shapes_mouse_trail` (#5246) by @balamurugan +[examples] ADDED: `shapes_particles` (#5260) by @JordSant +[examples] ADDED: `shapes_penrose_tile` (#5376) by @davidbuzatto +[examples] ADDED: `shapes_pie_chart` (#5227) by @GideonSerf +[examples] ADDED: `shapes_recursive_tree` (#5229) by @Jopestpe +[examples] ADDED: `shapes_rlgl_color_wheel` example (#5355) by @robinsaviary +[examples] ADDED: `shapes_rlgl_triangle` example (#5353) by @robinsaviary +[examples] ADDED: `shapes_starfield` (#5255) by @themushroompirates +[examples] ADDED: `shapes_triangle_strip` (#5240) by @Jopestpe +[examples] ADDED: `text_inline_styling` by @raysan5 +[examples] ADDED: `text_strings_management` (#5379) by @davidbuzatto +[examples] ADDED: `text_words_alignment` (#5254) by @themushroompirates +[examples] ADDED: `textured_clipboard_image` (#5604) by @maiconpintoabreu +[examples] ADDED: `textures_cellular_automata` (#5395) by @JordSant +[examples] ADDED: `textures_frame_buffer_rendering` (#5468) by @jackboakes +[examples] ADDED: `textures_magnifying_glass` (#5587) by @dgamebillda +[examples] ADDED: `textures_screen_buffer` (#5357) by @agnis16 +[examples] ADDED: `textures_sprite_stacking` example (#5345) by @robinsaviary +[examples] ADDED: `models_animation_timing` by @raysan5 +[examples] ADDED: `models_directional_billboard` (#5351) by @robinsaviary +[examples] ADDED: `models_animation_bone_blending` (#5543) by @dmitrii-brand +[examples] ADDED: `models_basic_voxel` (#5212) by @timlittle88 +[examples] ADDED: `models_decals` (#5298) by @themushroompirates +[examples] ADDED: `models_geometry_textures_cube` (#5221) by @Jopestpe +[examples] ADDED: `models_tesseract` by @raysan5 +[examples] ADDED: `shaders_render_depth_texture` by @luis605 +[examples] ADDED: `shaders_ascii_rendering` (#5213) by @maiconpintoabreu +[examples] ADDED: `shaders_color_correction` (#5307) by @JordSant +[examples] ADDED: `shaders_game_of_life` (#5394) by @JordSant +[examples] ADDED: `shaders_mandelbrot_set` (#5282) by @JordSant +[examples] ADDED: `shaders_normalmap` by @Sir-Irk +[examples] ADDED: `shaders_rounded_rectangle` (#4719) by @anstropleuton +[examples] ADDED: `shaders_view_depth` (luis605) +[examples] ADDED: `audio_sound_positionning` by @Bigfoot71 +[examples] REMOVED: `core_gamepad_info` by @raysan5 +[examples] REMOVED: `core_loading_thread` by @raysan5 +[examples] RENAMED: Sprite fonts resource directory by @raysan5 +[examples] RENAMED: `core_3d_fps_controller` to `core_3d_camera_fps` by @raysan5 +[examples] RENAMED: `core_high_dpi` to `core_highdpi_demo` by @raysan5 +[examples] RENAMED: `core_input_gestures_web` to `core_input_gestures_testbed` by @raysan5 +[examples] RENAMED: `shapes_draw_circle_sector` to `shapes_circle_sector_drawing` by @raysan5 +[examples] RENAMED: `shapes_draw_rectangle_rounded` to `shapes_rounded_rectangle_drawing` by @raysan5 +[examples] RENAMED: `shapes_draw_ring` to `shapes_ring_drawing` by @raysan5 +[examples] RENAMED: `shapes_easings_ball_anim` to `shapes_easings_ball` by @raysan5 +[examples] RENAMED: `shapes_easings_box_anim` to `shapes_easings_box` by @raysan5 +[examples] RENAMED: `shapes_easings_rectangle_array` to `shapes_easings_rectangles` by @raysan5 +[examples] RENAMED: `text_draw_3d` to `text_3d_drawing` by @raysan5 +[examples] RENAMED: `text_raylib_fonts` -> `text_sprite_fonts` by @raysan5 +[examples] RENAMED: `text_unicode` to `text_unicode_emojis` by @raysan5 +[examples] RENAMED: `textures_draw_tiled` to `textures_tiled_drawing` by @raysan5 +[examples] RENAMED: `textures_polygon` to `textures_polygon_drawing` by @raysan5 +[examples] RENAMED: `textures_sprite_anim` to `textures_sprite_animation` by @raysan5 +[examples] RENAMED: `models_animation` to `models_animation_playing` by @raysan5 +[examples] RENAMED: `models_billboard` to `models_billboard_rendering` by @raysan5 +[examples] RENAMED: `models_cubicmap` to `models_cubicmap_rendering` by @raysan5 +[examples] RENAMED: `models_draw_cube_texture` to `models_textured_cube` by @raysan5 +[examples] RENAMED: `models_geometry_textures_cube` to `models_rotating_cube` by @raysan5 +[examples] RENAMED: `models_gpu_skinning` to `models_animation_gpu_skinning` by @raysan5 +[examples] RENAMED: `models_heightmap` to `models_heightmap_rendering` by @raysan5 +[examples] RENAMED: `models_skybox` to `models_skybox_rendering` by @raysan5 +[examples] RENAMED: `shaders_deferred_render` to `shaders_deferred_rendering` by @raysan5 +[examples] RENAMED: `shaders_eratosthenes` to `shaders_eratosthenes_sieve` by @raysan5 +[examples] RENAMED: `shaders_fog` to `shaders_fog_rendering` by @raysan5 +[examples] RENAMED: `shaders_hybrid_render` to `shaders_hybrid_rendering` by @raysan5 +[examples] RENAMED: `shaders_lightmap` to `shaders_lightmap_rendering` by @raysan5 +[examples] RENAMED: `shaders_normal_map` to `shaders_normalmap_rendering` by @raysan5 +[examples] RENAMED: `shaders_raymarching` to `shaders_raymarching_rendering` by @raysan5 +[examples] RENAMED: `shaders_shadowmap` to `shaders_shadowmap_rendering` by @raysan5 +[examples] RENAMED: `shaders_spotlight` to `shaders_spotlight_rendering` by @raysan5 +[examples] RENAMED: `shaders_texture_drawing` to `shaders_texture_rendering` by @raysan5 +[examples] RENAMED: `shaders_view_depth` to `shaders_depth_rendering` by @raysan5 +[examples] RENAMED: `shaders_write_depth` to `shaders_depth_writing` by @raysan5 +[examples] RENAMED: `shaders_normalmap` to `shaders_normal_map` by @raysan5 +[examples] RENAMED: `audio_fft_spectrum_visualizer` to `audio_spectrum_visualizer` by @raysan5 +[examples] REVIEWED: All examples header section comments, for better organization and consistency by @raysan5 +[examples] REVIEWED: All examples MSVC warnings and non-working examples by @Jeffm2501 +[examples] REVIEWED: Moved some examples out of `others` category, removing category by @raysan5 +[examples] REVIEWED: Shaders formating to follow raylib code conventions by @raysan5 +[examples] REVIEWED: `examples_template`, adding info about new rexm tool by @raysan5 +[examples] REVIEWED: `core_2d_camera_mouse_zoom` by @raysan5 +[examples] REVIEWED: `core_3d_camera_fps` by @raysan5 +[examples] REVIEWED: `core_3d_fps_controller` by @agnis16 +[examples] REVIEWED: `core_3d_fps_controller` by @raysan5 +[examples] REVIEWED: `core_clipboard_text` by @raysan5 +[examples] REVIEWED: `core_custom_frame_control`, to work properly on web by @PanicTitan +[examples] REVIEWED: `core_custom_frame_control`, avoid divide by 0 by @johnnymarler +[examples] REVIEWED: `core_delta_time` by @raysan5 +[examples] REVIEWED: `core_directory_files` by @raysan5 +[examples] REVIEWED: `core_highdpi_testbed` by @raysan5 +[examples] REVIEWED: `core_input_actions` by @raysan5 +[examples] REVIEWED: `core_input_gamepad, fix hardcoded gamepad 0 by @lepasona +[examples] REVIEWED: `core_input_gamepad` by @raysan5 +[examples] REVIEWED: `core_input_gestures_testbed` by @raysan5 +[examples] REVIEWED: `core_monitor_detector` by @raysan5 +[examples] REVIEWED: `core_random_sequence` by @raysan5 +[examples] REVIEWED: `core_render_texture` by @raysan5 +[examples] REVIEWED: `core_text_file_loading` (#5339) by @cs24b016 +[examples] REVIEWED: `core_undo_redo` by @raysan5 +[examples] REVIEWED: `core_viewport_scaling` by @raysan5 +[examples] REVIEWED: `core_window_flags` by @raysan5 +[examples] REVIEWED: `core_window_flags`, add borderless windowed toggle by @johnnymarler +[examples] REVIEWED: `core_window_flags`, prevent immediate window restore from minimize by @johnnymarler +[examples] REVIEWED: `core_window_letterbox` by @raysan5 +[examples] REVIEWED: `core_input_gamepad`, vibration test button (#5362) by @sergii +[examples] REVIEWED: `core_directory_files` (#5343) by @hugo +[examples] REVIEWED: `core_input_virtual_controls` (#4584) by @danilwhale +[examples] REVIEWED: `shapes_bouncing_ball`, added gravity (#5217) by @Jopestpe +[examples] REVIEWED: `shapes_kaleidoscope` rewind, forward and reset buttons (#5369) by @hugo +[examples] REVIEWED: `shapes_digital_clock` by @raysan5 +[examples] REVIEWED: `shapes_bullet_hell` by @raysan5 +[examples] REVIEWED: `shapes_double_pendulum` by @raysan5 +[examples] REVIEWED: `shapes_easings_testbed` by @raysan5 +[examples] REVIEWED: `shapes_hilbert_curve` #5454 by @raysan5 +[examples] REVIEWED: `shapes_hilbert_curve` by @raysan5 +[examples] REVIEWED: `shapes_lines_drawing` by @raysan5 +[examples] REVIEWED: `shapes_penrose_tile` by @raysan5 +[examples] REVIEWED: `shapes_penrose_tile` formating by @raysan5 +[examples] REVIEWED: `shapes_pie_chart` by @raysan5 +[examples] REVIEWED: `shapes_rlgl_triangle` by @raysan5 +[examples] REVIEWED: `shapes_triangle_strip`, fix array size and simplify loop (#5280) by @Jopestpe +[examples] REVIEWED: `text_draw_3d` by @zeankey +[examples] REVIEWED: `text_font_sdf` by @raysan5 +[examples] REVIEWED: `text_inline_styling` by @raysan5 +[examples] REVIEWED: `text_raylib_fonts` by @raysan5 +[examples] REVIEWED: `text_unicode_ranges` by @raysan5 +[examples] REVIEWED: `text_words_alignment` (#5411) by @lucarandrianirina2507 +[examples] REVIEWED: `text_draw_3d`, fix text size by @zeankey +[examples] REVIEWED: `textures_bunnymark`, replaced bunny image #5344 by @raysan5 +[examples] REVIEWED: `textures_clipboard_image` by @raysan5 +[examples] REVIEWED: `textures_framebuffer_rendering` by @raysan5 +[examples] REVIEWED: `textures_image_kernel` by @raysan5 +[examples] REVIEWED: `textures_screen_buffer` by @raysan5 +[examples] REVIEWED: `textures_sprite_stacking` by @raysan5 +[examples] REVIEWED: `textures_textured_curve` (#5463) by @Jeffm2501 +[examples] REVIEWED: `textures_bunnymark` by @raysan5 +[examples] REVIEWED: `models_first_person_maze` (#5478) by @pauldahacker +[examples] REVIEWED: `models_decals`, fixed unload crash, added buttons (#5306) by @themushroompirates +[examples] REVIEWED: `models_animation_bone_blending` by @raysan5 +[examples] REVIEWED: `models_basic_voxel` by @raysan5 +[examples] REVIEWED: `models_basic_voxel`, fix raycasting logic (#5643) by @SardineMilk +[examples] REVIEWED: `models_basic_voxel`, replaced `GetRenderWidth()` by `GetScreenWidth()` (#5635) by @SardineMilk +[examples] REVIEWED: `models_decals` by @raysan5 +[examples] REVIEWED: `models_first_person_maze` by @raysan5 +[examples] REVIEWED: `models_loading_vox` by @raysan5 +[examples] REVIEWED: `models_mesh_picking` by @raysan5 +[examples] REVIEWED: `models_point_rendering` by @raysan5 +[examples] REVIEWED: `models_rlgl_solar_system` by @raysan5 +[examples] REVIEWED: `models_skybox_rendering` by @raysan5 +[examples] REVIEWED: `models_textures_tiling` shaders by @raysan5 +[examples] REVIEWED: `models_animation_blending` by @raysan5 +[examples] REVIEWED: `shaders_ascii_rendering` (#5219) by @maiconpintoabreu +[examples] REVIEWED: `shaders_ascii_rendering` by @raysan5 +[examples] REVIEWED: `shaders_basic_pbr`, to work on web (#4516) by @afanolovcic +[examples] REVIEWED: `shaders_color_correction` by @raysan5 +[examples] REVIEWED: `shaders_defered_render` for OpenGL ES 3.0 (#4617) by @Bigfoot71 +[examples] REVIEWED: `shaders_deferred_render` (#4676) by @veins1 +[examples] REVIEWED: `shaders_deferred_render` by @raysan5 +[examples] REVIEWED: `shaders_deferred_rendering` by @raysan5 +[examples] REVIEWED: `shaders_game_of_life` by @raysan5 +[examples] REVIEWED: `shaders_game_of_life` for web (#5399) by @JordSant +[examples] REVIEWED: `shaders_hybrid_rendering`, shaders issues by @raysan5 +[examples] REVIEWED: `shaders_julia_set` by @raysan5 +[examples] REVIEWED: `shaders_mandelbrot_set` (#5310) by @JordSant +[examples] REVIEWED: `shaders_mandelbrot_set` for WebGL (#5286) by @JordSant +[examples] REVIEWED: `shaders_mesh_instancing` by @raysan5 +[examples] REVIEWED: `shaders_multi_sample2d` by @raysan5 +[examples] REVIEWED: `shaders_normal_map` by @raysan5 +[examples] REVIEWED: `shaders_normalmap_rendering` by @raysan5 +[examples] REVIEWED: `shaders_normalmap` #5032 by @raysan5 +[examples] REVIEWED: `shaders_normalmap` by @raysan5 +[examples] REVIEWED: `shaders_rounded_rectangle` by @raysan5 +[examples] REVIEWED: `shaders_shadowmap_rendering` by @raysan5 +[examples] REVIEWED: `shaders_shadowmap_rendering` example by @raysan5 +[examples] REVIEWED: `shaders_spotlight` by @raysan5 +[examples] REVIEWED: `shaders_texture_drawing` by @raysan5 +[examples] REVIEWED: `shaders_cel_shading` by @raysan5 +[examples] REVIEWED: `shaders_cel_shading`, cel-shading and outline using inverted hull (#5615) by @galexeev +[examples] REVIEWED: `audio_fft_spectrum_visualizer`, not working on web by @raysan5 +[examples] REVIEWED: `audio_music_stream` by @raysan5 +[examples] REVIEWED: `audio_sound_multi` by @raysan5 +[examples] REVIEWED: `audio_sound_positioning` by @dabbott +[examples] REVIEWED: `rlgl_compute_shader` by @raysan5 +[examples] REVIEWED: `raylib_opengl_interop`, remove unnecessary defines (#5618) by @m0391n +[examples] REVIEWED: `raylib_opengl_interop` single header library not having it's implementation loaded (#5498) by @jscaffidi +[examples] REVIEWED: Example shader `depth_render.fs` by @raysan5 +[examples] REVIEWED: Example shader `depth_write.fs` by @raysan5 +[examples] REVIEWED: Example shader `normalmap.fs` by @raysan5 +[examples] REVIEWED: Example shader `palette_switch.fs` (#5205) by @benjaminsmallarz +[examples] REVIEWED: Example shader `write_depth.fs` for glsl120 by @maiconpintoabreu +[examples] REDESIGNED: `core_clipboard_text`, based on #5248 by @raysan5 +[examples] REDESIGNED: `shapes_digital_clock` by @raysan5 +[examples] REDESIGNED: `shapes_kaleidoscope`, store lines #5361 by @raysan5 +[examples] REDESIGNED: `text_unicode_ranges` by @raysan5 +[examples] REDESIGNED: `models_animation_blending` by @raysan5 +[examples] REDESIGNED: `audio_raw_stream`, remove callback usage (#5637) by @dan-hoang + +[bindings] ADDED: Common Lisp binding by @colin +[bindings] ADDED: D Object Oriented wrapper (#4550) by @RealDoigt +[bindings] ADDED: Dart binding (#5585) by @FinnDemonCat +[bindings] ADDED: Deno binding for 5.5 (#5462) by @JJLDonley +[bindings] ADDED: Jai binding (#4565) by @ahmedqarmout2 +[bindings] ADDED: Raylib-cs.BleedingEdge (#4999) by @danilwhale +[bindings] ADDED: SwiftForth language binding (#5319) by @dave +[bindings] ADDED: Wave language (#5539) by @youngjae681 +[bindings] ADDED: c3-lang for raylib 5.5 (#4555) by @afanolovcic +[bindings] ADDED: chicken scheme (#5449) by @meowstr +[bindings] ADDED: elle bindings (#5370) by @acquitefx +[bindings] ADDED: raylib-ada (#5150) by @artem.v.ageev +[bindings] ADDED: uiua bindings (#4993) by @marcosgrzesiak +[bindings] ADDED: Ring language (#5421) by @SabeDoesThings +[bindings] ADDED: ReiLua, Lua binding (#4589) by @legendaryredfox +[bindings] ADDED: Matte bindings (#4586) by @legendaryredfox +[bindings] UPDATED: Nim wrapper version (#4638) by @planetis-m +[bindings] UPDATED: Raylib.nelua version (#4698) by @AuzFox +[bindings] UPDATED: Fennel binding (#4585) by @0riginaln0 +[bindings] UPDATED: Jaylib to 5.5 (#4546) by @glowiak +[bindings] UPDATED: Ruby binding (#4639) by @BotRandomness +[bindings] UPDATED: V language binding (#4691) by @mobiuscog +[bindings] UPDATED: `racket-raylib` version by @eutro +[bindings] UPDATED: fortran-raylib to 5.5 (#4518) by @interkosmos +[bindings] UPDATED: raylib-beef (#4514) by @Jannis.v.hagen +[bindings] UPDATED: raylib-cpp to 5.5 (#4511) by @RobLoach +[bindings] UPDATED: raylib-cs binding link (#4746) by @Rgebee +[bindings] UPDATED: raylib-d to 5.5 (#4506) by @schveiguy +[bindings] UPDATED: raylib-lua (#4567) by @legendaryredfox +[bindings] UPDATED: raylib-py to 5.5 (#4519) by @jorgegomes83 +[bindings] UPDATED: raylib-python-cffi to 5.0 (#4512) by @villares +[bindings] UPDATED: raylib-python-cffi to 5.5 (#4517) by @villares +[bindings] UPDATED: raylib-zig by @Not-Nik +[bindings] UPDATED: Multiple bindings (#4504, #4559, #4633, #4920, #5538, #5546) +[bindings] REMOVED: Broken repo links from bindings (#4572) by @legendaryredfox +[bindings] UPDATED: Factor bindings to 5.5 (#5648) by @ArnautDaniel +[bindings] UPDATED: Raylib-cs to 5.5 (#4628) by @JupiterRider +[bindings] UPDATED: raylib-go to 5.5 (#4566) by @JupiterRider +[bindings] UPDATED: racket-raylib (#4884) by @eutro +[bindings] UPDATED: raylib-odin binding license (#5647) by @jtorrestx +[bindings] UPDATED: raylib-zig (#5103) by @Not-Nik +[bindings] UPDATED: keybindings versions (#4570) by @legendaryredfox +[bindings] UPDATED: Common Lisp binding (#5014) by @fosskers +[bindings] REMOVED: raylib-v7 binding (#5090) by @Auios + +[rlparser] RENAMED: `raylib_parser` to `rlparser` by @raysan5 +[rlparser] REVIEWED: Command-line info by @raysan5 +[rexm] ADDED: Automated-testing system by @raysan5 +[rexm] ADDED: Build check warnings logs by @raysan5 +[rexm] ADDED: Command `update` to validate and update required files by @raysan5 +[rexm] ADDED: Example automated-testing by @raysan5 +[rexm] ADDED: Examples validation by @raysan5 +[rexm] ADDED: Implemented examples commands for automatic testing by @raysan5 +[rexm] ADDED: Implemented file rename requirements by @raysan5 +[rexm] ADDED: More detailed log info by @raysan5 +[rexm] ADDED: Read examples years created/reviewed info by @raysan5 +[rexm] ADDED: Resources scanning from examples for automated copying by @raysan5 +[rexm] ADDED: Security checks to verify examples categories provided by @raysan5 +[rexm] ADDED: Support example removal by @raysan5 +[rexm] ADDED: TestLog option for logs processing (without rebuilding) by @raysan5 +[rexm] ADDED: Web metadata validation and update by @raysan5 +[rexm] ADDED: Web platform logs automated reports by @raysan5 +[rexm] ADDED: `LoadExamplesData()` to support filtering and sorting by @raysan5 +[rexm] ADDED: `RemoveVSProjectFromSolution()` by @raysan5 +[rexm] ADDED: `AddVSProjectToSolution()` by @raysan5 +[rexm] ADDED: Examples buildind command by @raysan5 +[rexm] ADDED: Legend info on report generation by @raysan5 +[rexm] ADDED: `UpdateSourceMetadata()` by @raysan5 +[rexm] ADDED: Allow building web examples locally on Windows platform by @raysan5 +[rexm] ADDED: Generate second report with examples with issues by @raysan5 +[rexm] ADDED: Automatic validation and update of examples by @raysan5 +[rexm] ADDED: Automatically fix not found VS2022 project / solution by @raysan5 +[rexm] ADDED: Check example exists (compilation worked) before trying to run it by @raysan5 +[rexm] ADDED: Copy examples web-build files to `raylib.com` by @raysan5 +[rexm] ADDED: Remove duplicate entries on examples list on `update` process by @raysan5 +[rexm] ADDED: Automatic validation and update by @raysan5 +[rexm] ADDED: Example building, using default examples `Makefile`/`Makefile.Web` by @raysan5 +[rexm] ADDED: Rebuild to support full categories by @raysan5 +[rexm] ADDED: Support building full example collection and categories by @raysan5 +[rexm] ADDED: Support examples data `validation` and **report generation** by @raysan5 +[rexm] ADDED: Support paths customization with environment variables by @raysan5 +[rexm] ADDED: Support testing running on `PLATFORM_DRM` by @raysan5 +[rexm] REVIEWED: Fixed some issues, improved `make` call defining base path by @raysan5 +[rexm] REVIEWED: Avoid external tool for UUIDv4 generation, implement custom function by @raysan5 +[rexm] REVIEWED: Avoid updating metadata from `others` examples by @raysan5 +[rexm] REVIEWED: Allow external path definition for VS solution file by @raysan5 +[rexm] REVIEWED: Reports moved to reports directory by @raysan5 +[rexm] REVIEWED: Automated testing for Web by @raysan5 +[rexm] REVIEWED: Examples header info inconsistencies by @raysan5 +[rexm] REVIEWED: Get example info from example header when added, to be added to collection by @raysan5 +[rexm] REVIEWED: Makefile and default paths (#5224) by @Teeto44 +[rexm] REVIEWED: Testing report generation by @raysan5 +[rexm] REVIEWED: Update `nextCatIndex` (#5616) by @CrackedPixel +[rexm] REVIEWED: Added variable assignment to rename option (#5077) by @lpow100 +[rexm] REVIEWED: Ran examples testing for macos (#5366) by @MaeBrooks +[remx] REVIEWED: Add check for category on new name (#5093) by @maiconpintoabreu +[remx] REVIEWED: Add warning for missing new name (#5092) by @maiconpintoabreu +[rexm] REVIEWED: Add compiled rexm to gitignore (#5086) by @maiconpintoabreu +[rexm] REVIEWED: Update examples status report when examples Updated by @raysan5 +[rexm] REVIEWED: `ScanExampleResources()` avoid resources to be saved by the program by @raysan5 +[rexm] REVIEWED: `UpdateSourceMetadata()` and `TextReplaceBetween()` by @raysan5 +[rexm] REVIEWED: `examples.js` example addition working by @raysan5 +[rexm] REVIEWED: `add` command logic for existing examplee addition by @raysan5 +[rexm] REVIEWED: Replace example name on project file by @raysan5 +[rexm] REVIEWED: Report issues if logs can not be loaded by @raysan5 +[rexm] REVIEWED: VS project adding to solution by @raysan5 +[rexm] REVIEWED: `UpdateSourceMetadata()` by @raysan5 +[rexm] REVIEWED: Example renaming on `examples.js` by @raysan5 +[rexm] REVIEWED: Examples source code headers metadata by @raysan5 +[rexm] REVIEWED: `README.md` generation improvements by @raysan5 +[rexm] REVIEWED: Store example resource paths by @raysan5 +[rexm] REVIEWED: `Makefile.Web` before trying to rebuild new example for web by @raysan5 +[rexm] REVIEWED: Using `Makefile.Web` for specific web versions generation by @raysan5 + +[external] REVIEWED: `jar_mod.h`, buffer overflow on memcpy by @LoneAuios +[external] REVIEWED: `sdefl` and `sinfl` issues (#5367) by @raysan5 +[external] REVIEWED: `sinfl_bsr()`, improvements by @RicoP +[external] REVIEWED: `rl_gputex.h`, make it usable standalone by @raysan5 +[external] REVIEWED: `rl_gputex.h,, fix the swizzling in `rl_load_dds_from_memory()` (#5422) by @msmith-codes +[external]`REVIEWED: `rl_gputex.h,, decouple logging and memory allocation from raylib by @sleeptightAnsiC +[external] REVIEWED: `stb_truetype`, fix composite glyph scaling logic (#4811) by @ashishbhattarai +[external] UPDATED: dr_libs (#5020) by @Emil2010 +[external] UPDATED: miniaudio to v0.11.22 (#4983) by @M374LX +[external] UPDATED: miniaudio to v0.11.23 (#5234) by @pyrokn8 +[external] UPDATED: miniaudio to v0.11.24 (#5506) by @vdemcak +[external] UPDATED: raygui to 5.0-dev for examples by @raysan5 +[external] UPDATED: RGFW to 1.5 (#4688) by @ColleagueRiley +[external] UPDATED: RGFW to 1.6 (#4795) by @colleagueRiley +[external] UPDATED: RGFW to 1.7 (#4965) by @M374LX +[external] UPDATED: RGFW to 1.7.5-dev (#4976) by @M374LX +[external] UPDATED: RGFW to 2.0.0 (#5582) by @CrackedPixel + +[misc] ADDED: SECURITY.md for security reporting policies by @raysan5 +[misc] ADDED: `examples/examples_list`, to be used by `rexm` or other tools by @raysan5 +[misc] ADDED: `fix_win32_compatibility.h`, utility header to avoid `windows.h` inclusion conflicts by @Jeffm2501 +[misc] RENAMED: Move and rename `raylib_parser` to `tools/rlparser` by @raysan5 -WARNING- +[misc] REVIEWED: Avoid `realloc()` usage, security improvement by @raysan5 +[misc] REVIEWED: Prioritize `calloc()` calls than `malloc()` on some cases by @raysan5 +[misc] REVIEWED: Code comments using imperative format by @raysan5 +[misc] REVIEWED: Webpage reference comments start with `REF:`, more consistent with `TODO:` and `NOTE:` comments by @raysan5 +[misc] REVIEWED: CONVENTIONS.md, added additional conventions by @raysan5 +[misc] REVIEWED: ROADMAP.md with potential future improvements by @raysan5 +[misc] REVIEWED: Comments formating, using imperative mode by @raysan5 +[misc] REVIEWED: Multiple examples inconsistencies on heeaders and overall structure to follow template by @raysan5 +[misc] REVIEWED: Code gardening: cleaning, reviewed comments, warnings, variables names... by @raysan5, @JeffM2501, @maiconpintoabreu, @CrackedPixel ------------------------------------------------------------------------- Release: raylib 5.5 (18 November 2024) @@ -458,7 +1215,7 @@ Detailed changes: [bindings] UPDATED: Python raylib-py v5.0.0beta1 (#3557) by @jorgegomes83 [bindings] UPDATED: raylib-d binding (#3561) by @schveiguy [bindings] UPDATED: Janet (#3553) by @Dmitry Matveyev -[bindings] UPDATED: Raylib.nelua (#3552) by @guy.smith764 +[bindings] UPDATED: Raylib.nelua (#3552) by @AuzFox [bindings] UPDATED: raylib-cpp to 5.0 (#3551) by @RobLoach [bindings] UPDATED: Pascal binding (#3548) by @Gunko Vadim [external] UPDATED: stb_truetype.h to latest version by @raysan5 From fd017c0b2d40505c0d8257d82ca4f7d77cdbaea5 Mon Sep 17 00:00:00 2001 From: Thomas Anderson <5776225+CrackedPixel@users.noreply.github.com> Date: Sun, 15 Mar 2026 14:25:31 -0500 Subject: [PATCH 04/41] fixed issue with mouse modes (#5659) --- src/platforms/rcore_desktop_rgfw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index 935b3fbb2..b091215ed 100755 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -1096,7 +1096,7 @@ void HideCursor(void) // Enables cursor (unlock cursor) void EnableCursor(void) { - RGFW_window_captureMouse(platform.window, false); + RGFW_window_captureRawMouse(platform.window, false); // Set cursor position in the middle SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); @@ -1108,7 +1108,7 @@ void EnableCursor(void) // Disables cursor (lock cursor) void DisableCursor(void) { - RGFW_window_captureMouse(platform.window, true); + RGFW_window_captureRawMouse(platform.window, true); HideCursor(); CORE.Input.Mouse.cursorLocked = true; From 29280971beac11a8f6ccd9bdf947fcdf0260671a Mon Sep 17 00:00:00 2001 From: Soma Mizobuchi <34585795+somamizobuchi@users.noreply.github.com> Date: Sun, 15 Mar 2026 15:31:18 -0400 Subject: [PATCH 05/41] rcore_platform_sdl: Fix `GetTime()` resolution for sdl (#5653) `SDL_GetTicks()` only has millisecond resolution so switched to `SLD_GetPerformanceCounter()` combined with `SDL_GetPerformanceFrequency()` which should allow more granular timing Fix: remove intermediate variable Remove second cast --- src/platforms/rcore_desktop_sdl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 9dbd0b873..11c83c72c 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -1276,9 +1276,7 @@ void SwapScreenBuffer(void) // Get elapsed time measure in seconds double GetTime(void) { - unsigned int ms = SDL_GetTicks(); // Elapsed time in milliseconds since SDL_Init() - double time = (double)ms/1000; - return time; + return (double)SDL_GetPerformanceCounter() / SDL_GetPerformanceFrequency(); } // Open URL with default system browser (if available) From 1d9e24eb58c8016addc2b8d0a2fb857e0b592913 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 15 Mar 2026 20:39:57 +0100 Subject: [PATCH 06/41] REVIEWED: `GetTime()`, make it consistent between platforms, consider window initialization base time --- src/platforms/rcore_desktop_glfw.c | 1 + src/platforms/rcore_desktop_rgfw.c | 7 ++++--- src/platforms/rcore_desktop_sdl.c | 12 ++++++++---- src/platforms/rcore_desktop_win32.c | 5 ++++- src/platforms/rcore_template.c | 1 - src/platforms/rcore_web.c | 1 + src/platforms/rcore_web_emscripten.c | 9 +-------- 7 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 1975a7bfe..9b6881d40 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1179,6 +1179,7 @@ void SwapScreenBuffer(void) double GetTime(void) { double time = glfwGetTime(); // Elapsed time since glfwInit() + return time; } diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index b091215ed..b92775592 100755 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -174,7 +174,6 @@ extern "C" { // Types and Structures Definition //---------------------------------------------------------------------------------- typedef struct { - double startTime; RGFW_window *window; // Native display device (physical screen connection) RGFW_monitor *monitor; mg_gamepads minigamepad; @@ -1127,7 +1126,9 @@ void SwapScreenBuffer(void) // Get elapsed time measure in seconds since InitTimer() double GetTime(void) { - return get_time_seconds() - platform.startTime; + double time = get_time_seconds() - CORE.Time.base; + + return time; } // Open URL with default system browser (if available) @@ -1628,7 +1629,7 @@ int InitPlatform(void) RGFW_setGlobalHints_OpenGL(hints); platform.window = RGFW_createWindow((CORE.Window.title != 0)? CORE.Window.title : " ", 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, flags | RGFW_windowOpenGL); - platform.startTime = get_time_seconds(); + CORE.Time.base = get_time_seconds(); #ifndef PLATFORM_WEB_RGFW i32 screenSizeWidth; diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 11c83c72c..5cd93ebd7 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -1276,7 +1276,9 @@ void SwapScreenBuffer(void) // Get elapsed time measure in seconds double GetTime(void) { - return (double)SDL_GetPerformanceCounter() / SDL_GetPerformanceFrequency(); + double time = (double)(SDL_GetPerformanceCounter()/SDL_GetPerformanceFrequency()) - CORE.Time.base; + + return time; } // Open URL with default system browser (if available) @@ -2122,12 +2124,14 @@ int InitPlatform(void) // Initialize timing system //---------------------------------------------------------------------------- - // NOTE: No need to call InitTimer(), let SDL manage it internally - CORE.Time.previous = GetTime(); // Get time as double - + // Get base time from window initialization + CORE.Time.base = (double)(SDL_GetPerformanceCounter()/SDL_GetPerformanceFrequency()); + #if defined(_WIN32) && SUPPORT_WINMM_HIGHRES_TIMER && !SUPPORT_BUSY_WAIT_LOOP SDL_SetHint(SDL_HINT_TIMER_RESOLUTION, "1"); // SDL equivalent of timeBeginPeriod() and timeEndPeriod() #endif + + // NOTE: No need to call InitTimer(), let SDL manage it internally //---------------------------------------------------------------------------- // Initialize storage system diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index a56a7f090..1cf8826aa 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -1238,9 +1238,12 @@ void SwapScreenBuffer(void) // Get elapsed time measure in seconds double GetTime(void) { + double time = 0.0; LARGE_INTEGER now = { 0 }; QueryPerformanceCounter(&now); - return (double)(now.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart; + time = (double)(now.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart; + + return time; } // Open URL with default system browser (if available) diff --git a/src/platforms/rcore_template.c b/src/platforms/rcore_template.c index 40a1922e7..368dd3e77 100644 --- a/src/platforms/rcore_template.c +++ b/src/platforms/rcore_template.c @@ -341,7 +341,6 @@ void SwapScreenBuffer(void) double GetTime(void) { double time = 0.0; - struct timespec ts = { 0 }; clock_gettime(CLOCK_MONOTONIC, &ts); unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index ae847d8c9..62b2afda9 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -986,6 +986,7 @@ void SwapScreenBuffer(void) double GetTime(void) { double time = glfwGetTime(); // Elapsed time since glfwInit() + return time; } diff --git a/src/platforms/rcore_web_emscripten.c b/src/platforms/rcore_web_emscripten.c index df3234217..60b647f60 100644 --- a/src/platforms/rcore_web_emscripten.c +++ b/src/platforms/rcore_web_emscripten.c @@ -962,14 +962,7 @@ void SwapScreenBuffer(void) // Get elapsed time measure in seconds since InitTimer() double GetTime(void) { - double time = 0.0; - /* - struct timespec ts = { 0 }; - clock_gettime(CLOCK_MONOTONIC, &ts); - unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; - time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer() - */ - time = emscripten_get_now()*1000.0; + double time = emscripten_get_now()*1000.0; return time; } From 26f329a5e7a33689f91619ce396f0cb2e86d25f7 Mon Sep 17 00:00:00 2001 From: Thomas Anderson <5776225+CrackedPixel@users.noreply.github.com> Date: Sun, 15 Mar 2026 14:40:26 -0500 Subject: [PATCH 07/41] fixed copy paste error in makefiles (#5660) --- examples/Makefile | 2 +- src/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index 899d040e3..5ae40af6f 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -95,7 +95,7 @@ USE_EXTERNAL_GLFW ?= FALSE GLFW_LINUX_ENABLE_WAYLAND ?= FALSE GLFW_LINUX_ENABLE_X11 ?= TRUE -# Enable support for X11 by default on Linux when using GLFW +# Enable support for X11 by default on Linux when using RGFW # NOTE: Wayland is disabled by default, only enable if you are sure RGFW_LINUX_ENABLE_WAYLAND ?= FALSE RGFW_LINUX_ENABLE_X11 ?= TRUE diff --git a/src/Makefile b/src/Makefile index e53514701..9826ddf8e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -122,7 +122,7 @@ USE_EXTERNAL_GLFW ?= FALSE GLFW_LINUX_ENABLE_WAYLAND ?= FALSE GLFW_LINUX_ENABLE_X11 ?= TRUE -# Enable support for X11 by default on Linux when using GLFW +# Enable support for X11 by default on Linux when using RGFW # NOTE: Wayland is disabled by default, only enable if you are sure RGFW_LINUX_ENABLE_WAYLAND ?= FALSE RGFW_LINUX_ENABLE_X11 ?= TRUE From dfc3f58a06d080b7db50efc92eea152c7470a546 Mon Sep 17 00:00:00 2001 From: Thomas Anderson <5776225+CrackedPixel@users.noreply.github.com> Date: Sun, 15 Mar 2026 17:26:29 -0500 Subject: [PATCH 08/41] fixed web platform resize events (#5662) --- src/platforms/rcore_desktop_rgfw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index b92775592..87ad7d7c4 100755 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -1332,7 +1332,7 @@ void PollInputEvents(void) CORE.Window.currentFbo.width = CORE.Window.render.width; CORE.Window.currentFbo.height = CORE.Window.render.height; #elif defined(PLATFORM_WEB_RGFW) - return; + // do nothing but prevent other behavior #else SetupViewport(platform.window->w, platform.window->h); From ceeaf57a8bc041c5e90e512797bb076fceacb2e2 Mon Sep 17 00:00:00 2001 From: Maicon Santana Date: Mon, 16 Mar 2026 08:24:33 +0000 Subject: [PATCH 09/41] [CHANGELOG] fix github name (#5663) Just for consistency, changing @Ray to @raysan5 --- CHANGELOG | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1536d4e4c..192fe9207 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -894,9 +894,9 @@ Detailed changes: [rlgl] ADDED: Vertex normals for RLGL immediate drawing mode (#3866) by @bohonghuang -WARNING- [rlgl] ADDED: `rlCullDistance*()` variables and getters (#3912) by @KotzaBoss [rlgl] ADDED: `rlSetClipPlanes()` function (#3912) by @KotzaBoss -[rlgl] ADDED: `isGpuReady` flag, allow font loading with no GPU acceleration by @Ray -WARNING- +[rlgl] ADDED: `isGpuReady` flag, allow font loading with no GPU acceleration by @raysan5 -WARNING- [rlgl] REVIEWED: Changed RLGL_VERSION from 4.5 to 5.0 (#3914) by @rsteinke1111 -[rlgl] REVIEWED: Shader load failing returns 0, instead of fallback by @Ray -WARNING- +[rlgl] REVIEWED: Shader load failing returns 0, instead of fallback by @raysan5 -WARNING- [rlgl] REVIEWED: Standalone mode default flags (#4334) by @Asdqwe [rlgl] REVIEWED: Fix hardcoded index values in vboID array (#4312) by @JettMonstersGoBoom [rlgl] REVIEWED: GLint64 did not exist before OpenGL 3.2 (#4284) by @Tchan0 @@ -960,7 +960,7 @@ Detailed changes: [rtextures] ADDED: `ImageFromChannel()` (#4105) by @brccabral [rtextures] ADDED: `ImageDrawLineEx()` (#4097) by @Bigfoot71 [rtextures] ADDED: `ImageDrawTriangle()` (#4094) by @Bigfoot71 -[rtextures] REMOVED: SVG files loading and drawing, moving it to raylib-extras by @Ray -WARNING- +[rtextures] REMOVED: SVG files loading and drawing, moving it to raylib-extras by @raysan5 -WARNING- [rtextures] REVIEWED: `LoadImage()`, added support for 3-channel QOI images (#4384) by @R-YaTian [rtextures] REVIEWED: `LoadImageRaw()` #3926 by @raysan5 [rtextures] REVIEWED: `LoadImageColors()`, advance k in loop (#4120) by @brccabral @@ -988,7 +988,7 @@ Detailed changes: [rtext] ADDED: `TextToCamel()` (#4033) by @IoIxD [rtext] ADDED: `TextToSnake()` (#4033) by @IoIxD [rtext] ADDED: `TextToFloat()` (#3627) by @Benjamin Schmid Ties -[rtext] REDESIGNED: `SetTextLineSpacing()` by @Ray -WARNING- +[rtext] REDESIGNED: `SetTextLineSpacing()` by @raysan5 -WARNING- [rtext] REVIEWED: `LoadFontDataBDF()` name and formating by @raysan5 [rtext] REVIEWED: `LoadFontDefault()`, initialize glyphs and recs to zero #4319 by @raysan5 [rtext] REVIEWED: `LoadFontEx()`, avoid default font fallback (#4077) by @Peter0x44 -WARNING- @@ -996,7 +996,7 @@ Detailed changes: [rtext] REVIEWED: `LoadBMFont()`, issue on not glyph data initialized by @raysan5 [rtext] REVIEWED: `LoadFontFromMemory()`, use strncpy() to fix buffer overflow (#3795) by @Mingjie Shen [rtext] REVIEWED: `LoadCodepoints()` returning a freed ptr when count is 0 (#4089) by @Alice Nyaa -[rtext] REVIEWED: `LoadFontData()` avoid fallback glyphs by @Ray -WARNING- +[rtext] REVIEWED: `LoadFontData()` avoid fallback glyphs by @raysan5 -WARNING- [rtext] REVIEWED: `LoadFontData()`, load image only if glyph has been found in font by @raysan5 [rtext] REVIEWED: `ExportFontAsCode()`, fix C++ compiler errors (#4013) by @DarkAssassin23 [rtext] REVIEWED: `MeasureTextEx()` height calculation (#3770) by @Marrony Neris From 4a16dc9b0971f15aae2b6b55c96dd63db427b407 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 16 Mar 2026 17:01:26 +0100 Subject: [PATCH 10/41] Update build_webassembly.yml --- .github/workflows/build_webassembly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_webassembly.yml b/.github/workflows/build_webassembly.yml index d79b12b1c..2a126ff46 100644 --- a/.github/workflows/build_webassembly.yml +++ b/.github/workflows/build_webassembly.yml @@ -29,7 +29,7 @@ jobs: - name: Setup emsdk uses: mymindstorm/setup-emsdk@v14 with: - version: 3.1.71 + version: 5.0.3 actions-cache-folder: 'emsdk-cache' - name: Setup Release Version From e2aed43410705ae8d00c53e7e83113fa977ff6b5 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 16 Mar 2026 17:03:02 +0100 Subject: [PATCH 11/41] Update examples version to latest `raylib 6.0` --- examples/Makefile | 7 +- examples/Makefile.Web | 23 +- examples/README.md | 75 +-- examples/audio/audio_spectrum_visualizer.c | 2 +- examples/core/core_clipboard_text.c | 2 +- examples/core/core_compute_hash.c | 2 +- examples/core/core_delta_time.c | 2 +- examples/core/core_highdpi_testbed.c | 2 +- examples/core/core_input_gestures_testbed.c | 2 +- examples/core/core_render_texture.c | 2 +- examples/core/core_screen_recording.c | 2 +- examples/examples_list.txt | 69 ++- .../models/models_animation_blend_custom.c | 2 +- examples/models/models_animation_blending.c | 2 +- examples/models/models_animation_timing.c | 2 +- examples/models/models_decals.c | 2 +- .../models/models_directional_billboard.c | 2 +- examples/models/models_rotating_cube.c | 2 +- examples/models/models_tesseract_view.c | 2 +- examples/shaders/shaders_depth_rendering.c | 2 +- examples/shapes/shapes_ball_physics.c | 2 +- examples/shapes/shapes_clock_of_clocks.c | 2 +- examples/shapes/shapes_lines_drawing.c | 2 +- examples/shapes/shapes_math_angle_rotation.c | 2 +- examples/shapes/shapes_math_sine_cosine.c | 2 +- examples/shapes/shapes_penrose_tile.c | 2 +- examples/shapes/shapes_recursive_tree.c | 2 +- examples/shapes/shapes_rlgl_color_wheel.c | 2 +- examples/shapes/shapes_rlgl_triangle.c | 2 +- examples/shapes/shapes_starfield_effect.c | 2 +- examples/shapes/shapes_triangle_strip.c | 2 +- examples/text/text_inline_styling.c | 2 +- examples/text/text_strings_management.c | 2 +- examples/text/text_words_alignment.c | 2 +- examples/textures/textures_clipboard_image.c | 2 +- examples/textures/textures_sprite_stacking.c | 2 +- .../examples/shaders_cel_shading.vcxproj | 569 ++++++++++++++++++ .../examples/textures_clipboard_image.vcxproj | 569 ++++++++++++++++++ .../textures_magnifying_glass.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 81 +++ tools/rexm/reports/examples_validation.md | 5 +- 41 files changed, 1925 insertions(+), 106 deletions(-) create mode 100644 projects/VS2022/examples/shaders_cel_shading.vcxproj create mode 100644 projects/VS2022/examples/textures_clipboard_image.vcxproj create mode 100644 projects/VS2022/examples/textures_magnifying_glass.vcxproj diff --git a/examples/Makefile b/examples/Makefile index 5ae40af6f..95719672c 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -169,8 +169,8 @@ ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_R EMSDK_PATH ?= C:/raylib/emsdk EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten CLANG_PATH = $(EMSDK_PATH)/upstream/bin - PYTHON_PATH = $(EMSDK_PATH)/python/3.9.2-nuget_64bit - NODE_PATH = $(EMSDK_PATH)/node/20.18.0_64bit/bin + PYTHON_PATH = $(EMSDK_PATH)/python/3.13.3_64bit + NODE_PATH = $(EMSDK_PATH)/node/22.16.0_64bit/bin export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH):$$(PATH) endif endif @@ -622,6 +622,7 @@ TEXTURES = \ textures/textures_blend_modes \ textures/textures_bunnymark \ textures/textures_cellular_automata \ + textures/textures_clipboard_image \ textures/textures_fog_of_war \ textures/textures_framebuffer_rendering \ textures/textures_gif_player \ @@ -634,6 +635,7 @@ TEXTURES = \ textures/textures_image_rotate \ textures/textures_image_text \ textures/textures_logo_raylib \ + textures/textures_magnifying_glass \ textures/textures_mouse_painting \ textures/textures_npatch_drawing \ textures/textures_particles_blending \ @@ -703,6 +705,7 @@ SHADERS = \ shaders/shaders_ascii_rendering \ shaders/shaders_basic_lighting \ shaders/shaders_basic_pbr \ + shaders/shaders_cel_shading \ shaders/shaders_color_correction \ shaders/shaders_custom_uniform \ shaders/shaders_deferred_rendering \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 648e5eef4..4bf635a22 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -168,8 +168,8 @@ ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_R EMSDK_PATH ?= C:/raylib/emsdk EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten CLANG_PATH = $(EMSDK_PATH)/upstream/bin - PYTHON_PATH = $(EMSDK_PATH)/python/3.9.2-nuget_64bit - NODE_PATH = $(EMSDK_PATH)/node/20.18.0_64bit/bin + PYTHON_PATH = $(EMSDK_PATH)/python/3.13.3_64bit + NODE_PATH = $(EMSDK_PATH)/node/22.16.0_64bit/bin export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH):$$(PATH) endif endif @@ -596,6 +596,7 @@ TEXTURES = \ textures/textures_blend_modes \ textures/textures_bunnymark \ textures/textures_cellular_automata \ + textures/textures_clipboard_image \ textures/textures_fog_of_war \ textures/textures_framebuffer_rendering \ textures/textures_gif_player \ @@ -608,6 +609,7 @@ TEXTURES = \ textures/textures_image_rotate \ textures/textures_image_text \ textures/textures_logo_raylib \ + textures/textures_magnifying_glass \ textures/textures_mouse_painting \ textures/textures_npatch_drawing \ textures/textures_particles_blending \ @@ -677,6 +679,7 @@ SHADERS = \ shaders/shaders_ascii_rendering \ shaders/shaders_basic_lighting \ shaders/shaders_basic_pbr \ + shaders/shaders_cel_shading \ shaders/shaders_color_correction \ shaders/shaders_custom_uniform \ shaders/shaders_deferred_rendering \ @@ -1023,6 +1026,9 @@ textures/textures_bunnymark: textures/textures_bunnymark.c textures/textures_cellular_automata: textures/textures_cellular_automata.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +textures/textures_clipboard_image: textures/textures_clipboard_image.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + textures/textures_fog_of_war: textures/textures_fog_of_war.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) @@ -1071,6 +1077,11 @@ textures/textures_logo_raylib: textures/textures_logo_raylib.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file textures/resources/raylib_logo.png@resources/raylib_logo.png +textures/textures_magnifying_glass: textures/textures_magnifying_glass.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ + --preload-file textures/resources/raybunny.png@resources/raybunny.png \ + --preload-file textures/resources/parrots.png@resources/parrots.png + textures/textures_mouse_painting: textures/textures_mouse_painting.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) @@ -1365,6 +1376,14 @@ shaders/shaders_basic_pbr: shaders/shaders_basic_pbr.c --preload-file shaders/resources/road_mra.png@resources/road_mra.png \ --preload-file shaders/resources/road_n.png@resources/road_n.png +shaders/shaders_cel_shading: shaders/shaders_cel_shading.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ + --preload-file shaders/resources/models/old_car_new.glb@resources/models/old_car_new.glb \ + --preload-file shaders/resources/shaders/glsl100/cel.vs@resources/shaders/glsl100/cel.vs \ + --preload-file shaders/resources/shaders/glsl100/cel.fs@resources/shaders/glsl100/cel.fs \ + --preload-file shaders/resources/shaders/glsl100/outline_hull.vs@resources/shaders/glsl100/outline_hull.vs \ + --preload-file shaders/resources/shaders/glsl100/outline_hull.fs@resources/shaders/glsl100/outline_hull.fs + shaders/shaders_color_correction: shaders/shaders_color_correction.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file shaders/resources/parrots.png@resources/parrots.png \ diff --git a/examples/README.md b/examples/README.md index a4e65b9f5..17719be00 100644 --- a/examples/README.md +++ b/examples/README.md @@ -17,7 +17,7 @@ You may find it easier to use than other toolchains, especially when it comes to - `zig build [module]` to compile all examples for a module (e.g. `zig build core`) - `zig build [example]` to compile _and run_ a particular example (e.g. `zig build core_basic_window`) -## EXAMPLES COLLECTION [TOTAL: 208] +## EXAMPLES COLLECTION [TOTAL: 211] ### category: core [49] @@ -26,14 +26,14 @@ Examples using raylib [core](../src/rcore.c) module platform functionality: wind | example | image | difficulty
level | version
created | last version
updated | original
developer | |-----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------| | [core_basic_window](core/core_basic_window.c) | core_basic_window | ⭐☆☆☆ | 1.0 | 1.0 | [Ramon Santamaria](https://github.com/raysan5) | -| [core_delta_time](core/core_delta_time.c) | core_delta_time | ⭐☆☆☆ | 5.5 | 5.6-dev | [Robin](https://github.com/RobinsAviary) | +| [core_delta_time](core/core_delta_time.c) | core_delta_time | ⭐☆☆☆ | 5.5 | 6.0 | [Robin](https://github.com/RobinsAviary) | | [core_input_keys](core/core_input_keys.c) | core_input_keys | ⭐☆☆☆ | 1.0 | 1.0 | [Ramon Santamaria](https://github.com/raysan5) | | [core_input_mouse](core/core_input_mouse.c) | core_input_mouse | ⭐☆☆☆ | 1.0 | 5.5 | [Ramon Santamaria](https://github.com/raysan5) | | [core_input_mouse_wheel](core/core_input_mouse_wheel.c) | core_input_mouse_wheel | ⭐☆☆☆ | 1.1 | 1.3 | [Ramon Santamaria](https://github.com/raysan5) | | [core_input_gamepad](core/core_input_gamepad.c) | core_input_gamepad | ⭐☆☆☆ | 1.1 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) | | [core_input_multitouch](core/core_input_multitouch.c) | core_input_multitouch | ⭐☆☆☆ | 2.1 | 2.5 | [Berni](https://github.com/Berni8k) | | [core_input_gestures](core/core_input_gestures.c) | core_input_gestures | ⭐⭐☆☆ | 1.4 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) | -| [core_input_gestures_testbed](core/core_input_gestures_testbed.c) | core_input_gestures_testbed | ⭐⭐⭐☆ | 5.0 | 5.6-dev | [ubkp](https://github.com/ubkp) | +| [core_input_gestures_testbed](core/core_input_gestures_testbed.c) | core_input_gestures_testbed | ⭐⭐⭐☆ | 5.0 | 6.0 | [ubkp](https://github.com/ubkp) | | [core_input_virtual_controls](core/core_input_virtual_controls.c) | core_input_virtual_controls | ⭐⭐☆☆ | 5.0 | 5.0 | [GreenSnakeLinux](https://github.com/GreenSnakeLinux) | | [core_2d_camera](core/core_2d_camera.c) | core_2d_camera | ⭐⭐☆☆ | 1.5 | 3.0 | [Ramon Santamaria](https://github.com/raysan5) | | [core_2d_camera_mouse_zoom](core/core_2d_camera_mouse_zoom.c) | core_2d_camera_mouse_zoom | ⭐⭐☆☆ | 4.2 | 4.2 | [Jeffery Myers](https://github.com/JeffM2501) | @@ -62,16 +62,16 @@ Examples using raylib [core](../src/rcore.c) module platform functionality: wind | [core_random_sequence](core/core_random_sequence.c) | core_random_sequence | ⭐☆☆☆ | 5.0 | 5.0 | [Dalton Overmyer](https://github.com/REDl3east) | | [core_automation_events](core/core_automation_events.c) | core_automation_events | ⭐⭐⭐☆ | 5.0 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) | | [core_highdpi_demo](core/core_highdpi_demo.c) | core_highdpi_demo | ⭐⭐☆☆ | 5.0 | 5.5 | [Jonathan Marler](https://github.com/marler8997) | -| [core_render_texture](core/core_render_texture.c) | core_render_texture | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | +| [core_render_texture](core/core_render_texture.c) | core_render_texture | ⭐☆☆☆ | 6.0 | 6.0 | [Ramon Santamaria](https://github.com/raysan5) | | [core_undo_redo](core/core_undo_redo.c) | core_undo_redo | ⭐⭐⭐☆ | 5.5 | 5.6 | [Ramon Santamaria](https://github.com/raysan5) | | [core_viewport_scaling](core/core_viewport_scaling.c) | core_viewport_scaling | ⭐⭐☆☆ | 5.5 | 5.5 | [Agnis Aldiņš](https://github.com/nezvers) | | [core_input_actions](core/core_input_actions.c) | core_input_actions | ⭐⭐☆☆ | 5.5 | 5.6 | [Jett](https://github.com/JettMonstersGoBoom) | | [core_directory_files](core/core_directory_files.c) | core_directory_files | ⭐☆☆☆ | 5.5 | 5.6 | [Hugo ARNAL](https://github.com/hugoarnal) | -| [core_highdpi_testbed](core/core_highdpi_testbed.c) | core_highdpi_testbed | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | -| [core_screen_recording](core/core_screen_recording.c) | core_screen_recording | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | -| [core_clipboard_text](core/core_clipboard_text.c) | core_clipboard_text | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Ananth S](https://github.com/Ananth1839) | +| [core_highdpi_testbed](core/core_highdpi_testbed.c) | core_highdpi_testbed | ⭐☆☆☆ | 6.0 | 6.0 | [Ramon Santamaria](https://github.com/raysan5) | +| [core_screen_recording](core/core_screen_recording.c) | core_screen_recording | ⭐⭐☆☆ | 6.0 | 6.0 | [Ramon Santamaria](https://github.com/raysan5) | +| [core_clipboard_text](core/core_clipboard_text.c) | core_clipboard_text | ⭐⭐☆☆ | 6.0 | 6.0 | [Ananth S](https://github.com/Ananth1839) | | [core_text_file_loading](core/core_text_file_loading.c) | core_text_file_loading | ⭐☆☆☆ | 5.5 | 5.6 | [Aanjishnu Bhattacharyya](https://github.com/NimComPoo-04) | -| [core_compute_hash](core/core_compute_hash.c) | core_compute_hash | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | +| [core_compute_hash](core/core_compute_hash.c) | core_compute_hash | ⭐⭐☆☆ | 6.0 | 6.0 | [Ramon Santamaria](https://github.com/raysan5) | | [core_keyboard_testbed](core/core_keyboard_testbed.c) | core_keyboard_testbed | ⭐⭐☆☆ | 5.6 | 5.6 | [Ramon Santamaria](https://github.com/raysan5) | | [core_window_web](core/core_window_web.c) | core_window_web | ⭐☆☆☆ | 1.3 | 5.5 | [Ramon Santamaria](https://github.com/raysan5) | @@ -94,7 +94,7 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( | [shapes_easings_ball](shapes/shapes_easings_ball.c) | shapes_easings_ball | ⭐⭐☆☆ | 2.5 | 2.5 | [Ramon Santamaria](https://github.com/raysan5) | | [shapes_easings_box](shapes/shapes_easings_box.c) | shapes_easings_box | ⭐⭐☆☆ | 2.5 | 2.5 | [Ramon Santamaria](https://github.com/raysan5) | | [shapes_easings_rectangles](shapes/shapes_easings_rectangles.c) | shapes_easings_rectangles | ⭐⭐⭐☆ | 2.0 | 2.5 | [Ramon Santamaria](https://github.com/raysan5) | -| [shapes_recursive_tree](shapes/shapes_recursive_tree.c) | shapes_recursive_tree | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) | +| [shapes_recursive_tree](shapes/shapes_recursive_tree.c) | shapes_recursive_tree | ⭐⭐⭐☆ | 6.0 | 6.0 | [Jopestpe](https://github.com/jopestpe) | | [shapes_ring_drawing](shapes/shapes_ring_drawing.c) | shapes_ring_drawing | ⭐⭐⭐☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | | [shapes_circle_sector_drawing](shapes/shapes_circle_sector_drawing.c) | shapes_circle_sector_drawing | ⭐⭐⭐☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | | [shapes_rounded_rectangle_drawing](shapes/shapes_rounded_rectangle_drawing.c) | shapes_rounded_rectangle_drawing | ⭐⭐⭐☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | @@ -104,30 +104,32 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( | [shapes_digital_clock](shapes/shapes_digital_clock.c) | shapes_digital_clock | ⭐⭐⭐⭐️ | 5.5 | 5.6 | [Hamza RAHAL](https://github.com/hmz-rhl) | | [shapes_double_pendulum](shapes/shapes_double_pendulum.c) | shapes_double_pendulum | ⭐⭐☆☆ | 5.5 | 5.5 | [JoeCheong](https://github.com/Joecheong2006) | | [shapes_dashed_line](shapes/shapes_dashed_line.c) | shapes_dashed_line | ⭐☆☆☆ | 5.5 | 5.5 | [Luís Almeida](https://github.com/luis605) | -| [shapes_triangle_strip](shapes/shapes_triangle_strip.c) | shapes_triangle_strip | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) | +| [shapes_triangle_strip](shapes/shapes_triangle_strip.c) | shapes_triangle_strip | ⭐⭐☆☆ | 6.0 | 6.0 | [Jopestpe](https://github.com/jopestpe) | | [shapes_vector_angle](shapes/shapes_vector_angle.c) | shapes_vector_angle | ⭐⭐☆☆ | 1.0 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) | | [shapes_pie_chart](shapes/shapes_pie_chart.c) | shapes_pie_chart | ⭐⭐⭐☆ | 5.5 | 5.6 | [Gideon Serfontein](https://github.com/GideonSerf) | | [shapes_kaleidoscope](shapes/shapes_kaleidoscope.c) | shapes_kaleidoscope | ⭐⭐☆☆ | 5.5 | 5.6 | [Hugo ARNAL](https://github.com/hugoarnal) | -| [shapes_clock_of_clocks](shapes/shapes_clock_of_clocks.c) | shapes_clock_of_clocks | ⭐⭐☆☆ | 5.5 | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) | -| [shapes_math_sine_cosine](shapes/shapes_math_sine_cosine.c) | shapes_math_sine_cosine | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) | -| [shapes_mouse_trail](shapes/shapes_mouse_trail.c) | shapes_mouse_trail | ⭐☆☆☆ | 5.6 | 5.6-dev | [Balamurugan R](https://github.com/Bala050814) | +| [shapes_clock_of_clocks](shapes/shapes_clock_of_clocks.c) | shapes_clock_of_clocks | ⭐⭐☆☆ | 5.5 | 6.0 | [JP Mortiboys](https://github.com/themushroompirates) | +| [shapes_math_sine_cosine](shapes/shapes_math_sine_cosine.c) | shapes_math_sine_cosine | ⭐⭐☆☆ | 6.0 | 6.0 | [Jopestpe](https://github.com/jopestpe) | +| [shapes_mouse_trail](shapes/shapes_mouse_trail.c) | shapes_mouse_trail | ⭐☆☆☆ | 5.6 | 6.0 | [Balamurugan R](https://github.com/Bala050814) | | [shapes_simple_particles](shapes/shapes_simple_particles.c) | shapes_simple_particles | ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) | -| [shapes_starfield_effect](shapes/shapes_starfield_effect.c) | shapes_starfield_effect | ⭐⭐☆☆ | 5.5 | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) | -| [shapes_lines_drawing](shapes/shapes_lines_drawing.c) | shapes_lines_drawing | ⭐☆☆☆ | 5.6-dev | 5.6 | [Robin](https://github.com/RobinsAviary) | -| [shapes_math_angle_rotation](shapes/shapes_math_angle_rotation.c) | shapes_math_angle_rotation | ⭐☆☆☆ | 5.6-dev | 5.6 | [Kris](https://github.com/krispy-snacc) | -| [shapes_rlgl_color_wheel](shapes/shapes_rlgl_color_wheel.c) | shapes_rlgl_color_wheel | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) | -| [shapes_rlgl_triangle](shapes/shapes_rlgl_triangle.c) | shapes_rlgl_triangle | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) | -| [shapes_ball_physics](shapes/shapes_ball_physics.c) | shapes_ball_physics | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) | -| [shapes_penrose_tile](shapes/shapes_penrose_tile.c) | shapes_penrose_tile | ⭐⭐⭐⭐️ | 5.5 | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) | +| [shapes_starfield_effect](shapes/shapes_starfield_effect.c) | shapes_starfield_effect | ⭐⭐☆☆ | 5.5 | 6.0 | [JP Mortiboys](https://github.com/themushroompirates) | +| [shapes_lines_drawing](shapes/shapes_lines_drawing.c) | shapes_lines_drawing | ⭐☆☆☆ | 6.0 | 5.6 | [Robin](https://github.com/RobinsAviary) | +| [shapes_math_angle_rotation](shapes/shapes_math_angle_rotation.c) | shapes_math_angle_rotation | ⭐☆☆☆ | 6.0 | 5.6 | [Kris](https://github.com/krispy-snacc) | +| [shapes_rlgl_color_wheel](shapes/shapes_rlgl_color_wheel.c) | shapes_rlgl_color_wheel | ⭐⭐⭐☆ | 6.0 | 6.0 | [Robin](https://github.com/RobinsAviary) | +| [shapes_rlgl_triangle](shapes/shapes_rlgl_triangle.c) | shapes_rlgl_triangle | ⭐⭐☆☆ | 6.0 | 6.0 | [Robin](https://github.com/RobinsAviary) | +| [shapes_ball_physics](shapes/shapes_ball_physics.c) | shapes_ball_physics | ⭐⭐☆☆ | 6.0 | 6.0 | [David Buzatto](https://github.com/davidbuzatto) | +| [shapes_penrose_tile](shapes/shapes_penrose_tile.c) | shapes_penrose_tile | ⭐⭐⭐⭐️ | 5.5 | 6.0 | [David Buzatto](https://github.com/davidbuzatto) | | [shapes_hilbert_curve](shapes/shapes_hilbert_curve.c) | shapes_hilbert_curve | ⭐⭐⭐☆ | 5.6 | 5.6 | [Hamza RAHAL](https://github.com/hmz-rhl) | | [shapes_easings_testbed](shapes/shapes_easings_testbed.c) | shapes_easings_testbed | ⭐⭐⭐☆ | 2.5 | 2.5 | [Juan Miguel López](https://github.com/flashback-fx) | -### category: textures [30] +### category: textures [32] Examples using raylib textures functionality, including image/textures loading/generation and drawing, provided by raylib [textures](../src/rtextures.c) module. | example | image | difficulty
level | version
created | last version
updated | original
developer | |-----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------| +| [textures_clipboard_image](textures/textures_clipboard_image.c) | textures_clipboard_image | ⭐☆☆☆ | 6.0 | 6.0 | [Maicon Santana](https://github.com/maiconpintoabreu) | +| [textures_magnifying_glass](textures/textures_magnifying_glass.c) | textures_magnifying_glass | ⭐⭐⭐☆ | 5.6 | 5.6 | [Luke Vaughan](https://github.com/badram) | | [textures_logo_raylib](textures/textures_logo_raylib.c) | textures_logo_raylib | ⭐☆☆☆ | 1.0 | 1.0 | [Ramon Santamaria](https://github.com/raysan5) | | [textures_srcrec_dstrec](textures/textures_srcrec_dstrec.c) | textures_srcrec_dstrec | ⭐⭐⭐☆ | 1.3 | 1.3 | [Ramon Santamaria](https://github.com/raysan5) | | [textures_image_drawing](textures/textures_image_drawing.c) | textures_image_drawing | ⭐⭐☆☆ | 1.4 | 1.4 | [Ramon Santamaria](https://github.com/raysan5) | @@ -155,7 +157,7 @@ Examples using raylib textures functionality, including image/textures loading/g | [textures_image_rotate](textures/textures_image_rotate.c) | textures_image_rotate | ⭐⭐☆☆ | 1.0 | 1.0 | [Ramon Santamaria](https://github.com/raysan5) | | [textures_screen_buffer](textures/textures_screen_buffer.c) | textures_screen_buffer | ⭐⭐☆☆ | 5.5 | 5.5 | [Agnis Aldiņš](https://github.com/nezvers) | | [textures_textured_curve](textures/textures_textured_curve.c) | textures_textured_curve | ⭐⭐⭐☆ | 4.5 | 4.5 | [Jeffery Myers](https://github.com/JeffM2501) | -| [textures_sprite_stacking](textures/textures_sprite_stacking.c) | textures_sprite_stacking | ⭐⭐☆☆ | 5.6-dev | 6.0 | [Robin](https://github.com/RobinsAviary) | +| [textures_sprite_stacking](textures/textures_sprite_stacking.c) | textures_sprite_stacking | ⭐⭐☆☆ | 6.0 | 6.0 | [Robin](https://github.com/RobinsAviary) | | [textures_cellular_automata](textures/textures_cellular_automata.c) | textures_cellular_automata | ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) | | [textures_framebuffer_rendering](textures/textures_framebuffer_rendering.c) | textures_framebuffer_rendering | ⭐⭐☆☆ | 5.6 | 5.6 | [Jack Boakes](https://github.com/jackboakes) | @@ -178,9 +180,9 @@ Examples using raylib text functionality, including sprite fonts loading/generat | [text_unicode_ranges](text/text_unicode_ranges.c) | text_unicode_ranges | ⭐⭐⭐⭐️ | 5.5 | 5.6 | [Vadim Gunko](https://github.com/GuvaCode) | | [text_3d_drawing](text/text_3d_drawing.c) | text_3d_drawing | ⭐⭐⭐⭐️ | 3.5 | 4.0 | [Vlad Adrian](https://github.com/demizdor) | | [text_codepoints_loading](text/text_codepoints_loading.c) | text_codepoints_loading | ⭐⭐⭐☆ | 4.2 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) | -| [text_inline_styling](text/text_inline_styling.c) | text_inline_styling | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Wagner Barongello](https://github.com/SultansOfCode) | -| [text_words_alignment](text/text_words_alignment.c) | text_words_alignment | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) | -| [text_strings_management](text/text_strings_management.c) | text_strings_management | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) | +| [text_inline_styling](text/text_inline_styling.c) | text_inline_styling | ⭐⭐⭐☆ | 6.0 | 6.0 | [Wagner Barongello](https://github.com/SultansOfCode) | +| [text_words_alignment](text/text_words_alignment.c) | text_words_alignment | ⭐☆☆☆ | 6.0 | 6.0 | [JP Mortiboys](https://github.com/themushroompirates) | +| [text_strings_management](text/text_strings_management.c) | text_strings_management | ⭐⭐⭐☆ | 6.0 | 6.0 | [David Buzatto](https://github.com/davidbuzatto) | ### category: models [30] @@ -210,16 +212,16 @@ Examples using raylib models functionality, including models loading/generation | [models_textured_cube](models/models_textured_cube.c) | models_textured_cube | ⭐⭐☆☆ | 4.5 | 4.5 | [Ramon Santamaria](https://github.com/raysan5) | | [models_animation_gpu_skinning](models/models_animation_gpu_skinning.c) | models_animation_gpu_skinning | ⭐⭐⭐☆ | 4.5 | 4.5 | [Daniel Holden](https://github.com/orangeduck) | | [models_bone_socket](models/models_bone_socket.c) | models_bone_socket | ⭐⭐⭐⭐️ | 4.5 | 4.5 | [iP](https://github.com/ipzaur) | -| [models_tesseract_view](models/models_tesseract_view.c) | models_tesseract_view | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Timothy van der Valk](https://github.com/arceryz) | +| [models_tesseract_view](models/models_tesseract_view.c) | models_tesseract_view | ⭐⭐☆☆ | 6.0 | 6.0 | [Timothy van der Valk](https://github.com/arceryz) | | [models_basic_voxel](models/models_basic_voxel.c) | models_basic_voxel | ⭐⭐☆☆ | 5.5 | 5.5 | [Tim Little](https://github.com/timlittle) | -| [models_rotating_cube](models/models_rotating_cube.c) | models_rotating_cube | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) | -| [models_decals](models/models_decals.c) | models_decals | ⭐⭐⭐⭐️ | 5.6-dev | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) | -| [models_directional_billboard](models/models_directional_billboard.c) | models_directional_billboard | ⭐⭐☆☆ | 5.6-dev | 5.6 | [Robin](https://github.com/RobinsAviary) | -| [models_animation_blend_custom](models/models_animation_blend_custom.c) | models_animation_blend_custom | ⭐⭐⭐⭐️ | 5.5 | 5.5 | [dmitrii-brand](https://github.com/dmitrii-brand) | -| [models_animation_blending](models/models_animation_blending.c) | models_animation_blending | ☆☆☆☆ | 5.5 | 5.6-dev | [Kirandeep](https://github.com/Kirandeep-Singh-Khehra) | -| [models_animation_timming](models/models_animation_timming.c) | models_animation_timming | ⭐⭐☆☆ | 5.6 | 5.6 | [Ramon Santamaria](https://github.com/raysan5) | +| [models_rotating_cube](models/models_rotating_cube.c) | models_rotating_cube | ⭐☆☆☆ | 6.0 | 6.0 | [Jopestpe](https://github.com/jopestpe) | +| [models_decals](models/models_decals.c) | models_decals | ⭐⭐⭐⭐️ | 6.0 | 6.0 | [JP Mortiboys](https://github.com/themushroompirates) | +| [models_directional_billboard](models/models_directional_billboard.c) | models_directional_billboard | ⭐⭐☆☆ | 6.0 | 5.6 | [Robin](https://github.com/RobinsAviary) | +| [models_animation_blend_custom](models/models_animation_blend_custom.c) | models_animation_blend_custom | ⭐⭐⭐⭐️ | 5.5 | 6.0 | [dmitrii-brand](https://github.com/dmitrii-brand) | +| [models_animation_blending](models/models_animation_blending.c) | models_animation_blending | ⭐⭐⭐⭐️ | 5.5 | 6.0 | [Kirandeep](https://github.com/Kirandeep-Singh-Khehra) | +| [models_animation_timing](models/models_animation_timing.c) | models_animation_timing | ⭐⭐⭐☆ | 5.6 | 6.0 | [Ramon Santamaria](https://github.com/raysan5) | -### category: shaders [34] +### category: shaders [35] Examples using raylib shaders functionality, including shaders loading, parameters configuration and drawing using them (model shaders and postprocessing shaders). This functionality is directly provided by raylib [rlgl](../src/rlgl.c) module. @@ -256,9 +258,10 @@ Examples using raylib shaders functionality, including shaders loading, paramete | [shaders_basic_pbr](shaders/shaders_basic_pbr.c) | shaders_basic_pbr | ⭐⭐⭐⭐️ | 5.0 | 5.5 | [Afan OLOVCIC](https://github.com/_DevDad) | | [shaders_lightmap_rendering](shaders/shaders_lightmap_rendering.c) | shaders_lightmap_rendering | ⭐⭐⭐☆ | 4.5 | 4.5 | [Jussi Viitala](https://github.com/nullstare) | | [shaders_rounded_rectangle](shaders/shaders_rounded_rectangle.c) | shaders_rounded_rectangle | ⭐⭐⭐☆ | 5.5 | 5.5 | [Anstro Pleuton](https://github.com/anstropleuton) | -| [shaders_depth_rendering](shaders/shaders_depth_rendering.c) | shaders_depth_rendering | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Luís Almeida](https://github.com/luis605) | +| [shaders_depth_rendering](shaders/shaders_depth_rendering.c) | shaders_depth_rendering | ⭐⭐⭐☆ | 6.0 | 6.0 | [Luís Almeida](https://github.com/luis605) | | [shaders_game_of_life](shaders/shaders_game_of_life.c) | shaders_game_of_life | ⭐⭐⭐☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) | | [shaders_rlgl_compute](shaders/shaders_rlgl_compute.c) | shaders_rlgl_compute | ⭐⭐⭐⭐️ | 4.0 | 4.0 | [Teddy Astie](https://github.com/tsnake41) | +| [shaders_cel_shading](shaders/shaders_cel_shading.c) | shaders_cel_shading | ⭐⭐⭐☆ | 6.0 | 6.0 | [Gleb A](https://github.com/ggrizzly) | ### category: audio [9] @@ -268,13 +271,13 @@ Examples using raylib audio functionality, including sound/music loading and pla |-----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------| | [audio_module_playing](audio/audio_module_playing.c) | audio_module_playing | ⭐☆☆☆ | 1.5 | 3.5 | [Ramon Santamaria](https://github.com/raysan5) | | [audio_music_stream](audio/audio_music_stream.c) | audio_music_stream | ⭐☆☆☆ | 1.3 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) | -| [audio_raw_stream](audio/audio_raw_stream.c) | audio_raw_stream | ⭐⭐⭐☆ | 1.6 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) | +| [audio_raw_stream](audio/audio_raw_stream.c) | audio_raw_stream | ⭐⭐⭐☆ | 1.6 | 6.0 | [Ramon Santamaria](https://github.com/raysan5) | | [audio_sound_loading](audio/audio_sound_loading.c) | audio_sound_loading | ⭐☆☆☆ | 1.1 | 3.5 | [Ramon Santamaria](https://github.com/raysan5) | | [audio_mixed_processor](audio/audio_mixed_processor.c) | audio_mixed_processor | ⭐⭐⭐⭐️ | 4.2 | 4.2 | [hkc](https://github.com/hatkidchan) | | [audio_stream_effects](audio/audio_stream_effects.c) | audio_stream_effects | ⭐⭐⭐⭐️ | 4.2 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) | | [audio_sound_multi](audio/audio_sound_multi.c) | audio_sound_multi | ⭐⭐☆☆ | 5.0 | 5.0 | [Jeffery Myers](https://github.com/JeffM2501) | | [audio_sound_positioning](audio/audio_sound_positioning.c) | audio_sound_positioning | ⭐⭐☆☆ | 5.5 | 5.5 | [Le Juez Victor](https://github.com/Bigfoot71) | -| [audio_spectrum_visualizer](audio/audio_spectrum_visualizer.c) | audio_spectrum_visualizer | ⭐⭐⭐☆ | 6.0 | 5.6-dev | [IANN](https://github.com/meisei4) | +| [audio_spectrum_visualizer](audio/audio_spectrum_visualizer.c) | audio_spectrum_visualizer | ⭐⭐⭐☆ | 6.0 | 6.0 | [IANN](https://github.com/meisei4) | Some example missing? As always, contributions are welcome, feel free to send new examples! Here is an [examples template](examples_template.c) with instructions to start with! diff --git a/examples/audio/audio_spectrum_visualizer.c b/examples/audio/audio_spectrum_visualizer.c index d2dbbbb57..f5ffe2f2d 100644 --- a/examples/audio/audio_spectrum_visualizer.c +++ b/examples/audio/audio_spectrum_visualizer.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★☆] 3/4 * -* Example originally created with raylib 6.0, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Inspired by Inigo Quilez's https://www.shadertoy.com/ * Resources/specification: https://gist.github.com/soulthreads/2efe50da4be1fb5f7ab60ff14ca434b8 diff --git a/examples/core/core_clipboard_text.c b/examples/core/core_clipboard_text.c index 59de6509c..6ced65654 100644 --- a/examples/core/core_clipboard_text.c +++ b/examples/core/core_clipboard_text.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Ananth S (@Ananth1839) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/core/core_compute_hash.c b/examples/core/core_compute_hash.c index f7d3ba9ac..890c14620 100644 --- a/examples/core/core_compute_hash.c +++ b/examples/core/core_compute_hash.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software diff --git a/examples/core/core_delta_time.c b/examples/core/core_delta_time.c index b77957ed6..26b0d13b1 100644 --- a/examples/core/core_delta_time.c +++ b/examples/core/core_delta_time.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 5.5, last time updated with raylib 5.6-dev +* Example originally created with raylib 5.5, last time updated with raylib 6.0 * * Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/core/core_highdpi_testbed.c b/examples/core/core_highdpi_testbed.c index cfff1f3c5..601d12e8c 100644 --- a/examples/core/core_highdpi_testbed.c +++ b/examples/core/core_highdpi_testbed.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Ramon Santamaria (@raysan5) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/core/core_input_gestures_testbed.c b/examples/core/core_input_gestures_testbed.c index e0ffeb13f..6cb09d0d2 100644 --- a/examples/core/core_input_gestures_testbed.c +++ b/examples/core/core_input_gestures_testbed.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★☆] 3/4 * -* Example originally created with raylib 5.0, last time updated with raylib 5.6-dev +* Example originally created with raylib 5.0, last time updated with raylib 6.0 * * Example contributed by ubkp (@ubkp) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/core/core_render_texture.c b/examples/core/core_render_texture.c index e30220a73..b11237ebc 100644 --- a/examples/core/core_render_texture.c +++ b/examples/core/core_render_texture.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software diff --git a/examples/core/core_screen_recording.c b/examples/core/core_screen_recording.c index 633ddcf81..33de31a5a 100644 --- a/examples/core/core_screen_recording.c +++ b/examples/core/core_screen_recording.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software diff --git a/examples/examples_list.txt b/examples/examples_list.txt index dc3312893..0fe453785 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -10,14 +10,14 @@ # This list is used as the main reference by [rexm] tool for examples collection validation and management # core;core_basic_window;★☆☆☆;1.0;1.0;2013;2025;"Ramon Santamaria";@raysan5 -core;core_delta_time;★☆☆☆;5.5;5.6-dev;2025;2025;"Robin";@RobinsAviary +core;core_delta_time;★☆☆☆;5.5;6.0;2025;2025;"Robin";@RobinsAviary core;core_input_keys;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5 core;core_input_mouse;★☆☆☆;1.0;5.5;2014;2025;"Ramon Santamaria";@raysan5 core;core_input_mouse_wheel;★☆☆☆;1.1;1.3;2014;2025;"Ramon Santamaria";@raysan5 core;core_input_gamepad;★☆☆☆;1.1;4.2;2013;2025;"Ramon Santamaria";@raysan5 core;core_input_multitouch;★☆☆☆;2.1;2.5;2019;2025;"Berni";@Berni8k core;core_input_gestures;★★☆☆;1.4;4.2;2016;2025;"Ramon Santamaria";@raysan5 -core;core_input_gestures_testbed;★★★☆;5.0;5.6-dev;2023;2025;"ubkp";@ubkp +core;core_input_gestures_testbed;★★★☆;5.0;6.0;2023;2025;"ubkp";@ubkp core;core_input_virtual_controls;★★☆☆;5.0;5.0;2024;2025;"GreenSnakeLinux";@GreenSnakeLinux core;core_2d_camera;★★☆☆;1.5;3.0;2016;2025;"Ramon Santamaria";@raysan5 core;core_2d_camera_mouse_zoom;★★☆☆;4.2;4.2;2022;2025;"Jeffery Myers";@JeffM2501 @@ -46,16 +46,16 @@ core;core_smooth_pixelperfect;★★★☆;3.7;4.0;2021;2025;"Giancamillo Alessa core;core_random_sequence;★☆☆☆;5.0;5.0;2023;2025;"Dalton Overmyer";@REDl3east core;core_automation_events;★★★☆;5.0;5.0;2023;2025;"Ramon Santamaria";@raysan5 core;core_highdpi_demo;★★☆☆;5.0;5.5;2025;2025;"Jonathan Marler";@marler8997 -core;core_render_texture;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5 +core;core_render_texture;★☆☆☆;6.0;6.0;2025;2025;"Ramon Santamaria";@raysan5 core;core_undo_redo;★★★☆;5.5;5.6;2025;2025;"Ramon Santamaria";@raysan5 core;core_viewport_scaling;★★☆☆;5.5;5.5;2025;2025;"Agnis Aldiņš";@nezvers core;core_input_actions;★★☆☆;5.5;5.6;2025;2025;"Jett";@JettMonstersGoBoom core;core_directory_files;★☆☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal -core;core_highdpi_testbed;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5 -core;core_screen_recording;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5 -core;core_clipboard_text;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Ananth S";@Ananth1839 +core;core_highdpi_testbed;★☆☆☆;6.0;6.0;2025;2025;"Ramon Santamaria";@raysan5 +core;core_screen_recording;★★☆☆;6.0;6.0;2025;2025;"Ramon Santamaria";@raysan5 +core;core_clipboard_text;★★☆☆;6.0;6.0;2025;2025;"Ananth S";@Ananth1839 core;core_text_file_loading;★☆☆☆;5.5;5.6;0;0;"Aanjishnu Bhattacharyya";@NimComPoo-04 -core;core_compute_hash;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5 +core;core_compute_hash;★★☆☆;6.0;6.0;2025;2025;"Ramon Santamaria";@raysan5 core;core_keyboard_testbed;★★☆☆;5.6;5.6;2026;2026;"Ramon Santamaria";@raysan5 core;core_window_web;★☆☆☆;1.3;5.5;2015;2025;"Ramon Santamaria";@raysan5 shapes;shapes_basic_shapes;★☆☆☆;1.0;4.2;2014;2025;"Ramon Santamaria";@raysan5 @@ -71,7 +71,7 @@ shapes;shapes_following_eyes;★★☆☆;2.5;2.5;2013;2025;"Ramon Santamaria";@ shapes;shapes_easings_ball;★★☆☆;2.5;2.5;2014;2025;"Ramon Santamaria";@raysan5 shapes;shapes_easings_box;★★☆☆;2.5;2.5;2014;2025;"Ramon Santamaria";@raysan5 shapes;shapes_easings_rectangles;★★★☆;2.0;2.5;2014;2025;"Ramon Santamaria";@raysan5 -shapes;shapes_recursive_tree;★★★☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe +shapes;shapes_recursive_tree;★★★☆;6.0;6.0;2025;2025;"Jopestpe";@jopestpe shapes;shapes_ring_drawing;★★★☆;2.5;2.5;2018;2025;"Vlad Adrian";@demizdor shapes;shapes_circle_sector_drawing;★★★☆;2.5;2.5;2018;2025;"Vlad Adrian";@demizdor shapes;shapes_rounded_rectangle_drawing;★★★☆;2.5;2.5;2018;2025;"Vlad Adrian";@demizdor @@ -81,23 +81,25 @@ shapes;shapes_splines_drawing;★★★☆;5.0;5.0;2023;2025;"Ramon Santamaria"; shapes;shapes_digital_clock;★★★★;5.5;5.6;2025;2025;"Hamza RAHAL";@hmz-rhl shapes;shapes_double_pendulum;★★☆☆;5.5;5.5;2025;2025;"JoeCheong";@Joecheong2006 shapes;shapes_dashed_line;★☆☆☆;5.5;5.5;2025;2025;"Luís Almeida";@luis605 -shapes;shapes_triangle_strip;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe +shapes;shapes_triangle_strip;★★☆☆;6.0;6.0;2025;2025;"Jopestpe";@jopestpe shapes;shapes_vector_angle;★★☆☆;1.0;5.0;2023;2025;"Ramon Santamaria";@raysan5 shapes;shapes_pie_chart;★★★☆;5.5;5.6;2025;2025;"Gideon Serfontein";@GideonSerf shapes;shapes_kaleidoscope;★★☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal -shapes;shapes_clock_of_clocks;★★☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates -shapes;shapes_math_sine_cosine;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe -shapes;shapes_mouse_trail;★☆☆☆;5.6;5.6-dev;2025;2025;"Balamurugan R";@Bala050814 +shapes;shapes_clock_of_clocks;★★☆☆;5.5;6.0;2025;2025;"JP Mortiboys";@themushroompirates +shapes;shapes_math_sine_cosine;★★☆☆;6.0;6.0;2025;2025;"Jopestpe";@jopestpe +shapes;shapes_mouse_trail;★☆☆☆;5.6;6.0;2025;2025;"Balamurugan R";@Bala050814 shapes;shapes_simple_particles;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant -shapes;shapes_starfield_effect;★★☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates -shapes;shapes_lines_drawing;★☆☆☆;5.6-dev;5.6;2025;2025;"Robin";@RobinsAviary -shapes;shapes_math_angle_rotation;★☆☆☆;5.6-dev;5.6;2025;2025;"Kris";@krispy-snacc -shapes;shapes_rlgl_color_wheel;★★★☆;5.6-dev;5.6-dev;2025;2025;"Robin";@RobinsAviary -shapes;shapes_rlgl_triangle;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Robin";@RobinsAviary -shapes;shapes_ball_physics;★★☆☆;5.6-dev;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto -shapes;shapes_penrose_tile;★★★★;5.5;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto +shapes;shapes_starfield_effect;★★☆☆;5.5;6.0;2025;2025;"JP Mortiboys";@themushroompirates +shapes;shapes_lines_drawing;★☆☆☆;6.0;5.6;2025;2025;"Robin";@RobinsAviary +shapes;shapes_math_angle_rotation;★☆☆☆;6.0;5.6;2025;2025;"Kris";@krispy-snacc +shapes;shapes_rlgl_color_wheel;★★★☆;6.0;6.0;2025;2025;"Robin";@RobinsAviary +shapes;shapes_rlgl_triangle;★★☆☆;6.0;6.0;2025;2025;"Robin";@RobinsAviary +shapes;shapes_ball_physics;★★☆☆;6.0;6.0;2025;2025;"David Buzatto";@davidbuzatto +shapes;shapes_penrose_tile;★★★★;5.5;6.0;2025;2025;"David Buzatto";@davidbuzatto shapes;shapes_hilbert_curve;★★★☆;5.6;5.6;2025;2025;"Hamza RAHAL";@hmz-rhl shapes;shapes_easings_testbed;★★★☆;2.5;2.5;2019;2025;"Juan Miguel López";@flashback-fx +textures;textures_clipboard_image;★☆☆☆;6.0;6.0;2026;2026;"Maicon Santana";@maiconpintoabreu +textures;textures_magnifying_glass;★★★☆;5.6;5.6;2026;2026;"Luke Vaughan";@badram textures;textures_logo_raylib;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5 textures;textures_srcrec_dstrec;★★★☆;1.3;1.3;2015;2025;"Ramon Santamaria";@raysan5 textures;textures_image_drawing;★★☆☆;1.4;1.4;2016;2025;"Ramon Santamaria";@raysan5 @@ -125,7 +127,7 @@ textures;textures_image_channel;★★☆☆;5.5;5.5;2024;2025;"Bruno Cabral";@b textures;textures_image_rotate;★★☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5 textures;textures_screen_buffer;★★☆☆;5.5;5.5;2025;2025;"Agnis Aldiņš";@nezvers textures;textures_textured_curve;★★★☆;4.5;4.5;2022;2025;"Jeffery Myers";@JeffM2501 -textures;textures_sprite_stacking;★★☆☆;5.6-dev;6.0;2025;2025;"Robin";@RobinsAviary +textures;textures_sprite_stacking;★★☆☆;6.0;6.0;2025;2025;"Robin";@RobinsAviary textures;textures_cellular_automata;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant textures;textures_framebuffer_rendering;★★☆☆;5.6;5.6;2026;2026;"Jack Boakes";@jackboakes text;text_sprite_fonts;★☆☆☆;1.7;3.7;2017;2025;"Ramon Santamaria";@raysan5 @@ -141,9 +143,9 @@ text;text_unicode_emojis;★★★★;2.5;4.0;2019;2025;"Vlad Adrian";@demizdor text;text_unicode_ranges;★★★★;5.5;5.6;2025;2025;"Vadim Gunko";@GuvaCode text;text_3d_drawing;★★★★;3.5;4.0;2021;2025;"Vlad Adrian";@demizdor text;text_codepoints_loading;★★★☆;4.2;4.2;2022;2025;"Ramon Santamaria";@raysan5 -text;text_inline_styling;★★★☆;5.6-dev;5.6-dev;2025;2025;"Wagner Barongello";@SultansOfCode -text;text_words_alignment;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates -text;text_strings_management;★★★☆;5.6-dev;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto +text;text_inline_styling;★★★☆;6.0;6.0;2025;2025;"Wagner Barongello";@SultansOfCode +text;text_words_alignment;★☆☆☆;6.0;6.0;2025;2025;"JP Mortiboys";@themushroompirates +text;text_strings_management;★★★☆;6.0;6.0;2025;2025;"David Buzatto";@davidbuzatto models;models_loading_iqm;★★☆☆;2.5;3.5;2019;2025;"Culacant";@culacant models;models_billboard_rendering;★★★☆;1.3;3.5;2015;2025;"Ramon Santamaria";@raysan5 models;models_box_collisions;★☆☆☆;1.3;3.5;2015;2025;"Ramon Santamaria";@raysan5 @@ -166,14 +168,14 @@ models;models_skybox_rendering;★★☆☆;1.8;4.0;2017;2025;"Ramon Santamaria" models;models_textured_cube;★★☆☆;4.5;4.5;2022;2025;"Ramon Santamaria";@raysan5 models;models_animation_gpu_skinning;★★★☆;4.5;4.5;2024;2025;"Daniel Holden";@orangeduck models;models_bone_socket;★★★★;4.5;4.5;2024;2025;"iP";@ipzaur -models;models_tesseract_view;★★☆☆;5.6-dev;5.6-dev;2024;2025;"Timothy van der Valk";@arceryz +models;models_tesseract_view;★★☆☆;6.0;6.0;2024;2025;"Timothy van der Valk";@arceryz models;models_basic_voxel;★★☆☆;5.5;5.5;2025;2025;"Tim Little";@timlittle -models;models_rotating_cube;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe -models;models_decals;★★★★;5.6-dev;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates -models;models_directional_billboard;★★☆☆;5.6-dev;5.6;2025;2025;"Robin";@RobinsAviary -models;models_animation_blend_custom;★★★★;5.5;5.5;2026;2026;"dmitrii-brand";@dmitrii-brand -models;models_animation_blending;☆☆☆☆;5.5;5.6-dev;2024;2024;"Kirandeep";@Kirandeep-Singh-Khehra -models;models_animation_timing;★★☆☆;5.6;5.6;2026;2026;"Ramon Santamaria";@raysan5 +models;models_rotating_cube;★☆☆☆;6.0;6.0;2025;2025;"Jopestpe";@jopestpe +models;models_decals;★★★★;6.0;6.0;2025;2025;"JP Mortiboys";@themushroompirates +models;models_directional_billboard;★★☆☆;6.0;5.6;2025;2025;"Robin";@RobinsAviary +models;models_animation_blend_custom;★★★★;5.5;6.0;2026;2026;"dmitrii-brand";@dmitrii-brand +models;models_animation_blending;★★★★;5.5;6.0;2024;2026;"Kirandeep";@Kirandeep-Singh-Khehra +models;models_animation_timing;★★★☆;5.6;6.0;2026;2026;"Ramon Santamaria";@raysan5 shaders;shaders_ascii_rendering;★★☆☆;5.5;5.6;2025;2025;"Maicon Santana";@maiconpintoabreu shaders;shaders_basic_lighting;★★★★;3.0;4.2;2019;2025;"Chris Camacho";@chriscamacho shaders;shaders_model_shader;★★☆☆;1.3;3.7;2014;2025;"Ramon Santamaria";@raysan5 @@ -205,15 +207,16 @@ shaders;shaders_depth_writing;★★☆☆;4.2;4.2;2022;2025;"Buğra Alptekin Sa shaders;shaders_basic_pbr;★★★★;5.0;5.5;2023;2025;"Afan OLOVCIC";@_DevDad shaders;shaders_lightmap_rendering;★★★☆;4.5;4.5;2019;2025;"Jussi Viitala";@nullstare shaders;shaders_rounded_rectangle;★★★☆;5.5;5.5;2025;2025;"Anstro Pleuton";@anstropleuton -shaders;shaders_depth_rendering;★★★☆;5.6-dev;5.6-dev;2025;2025;"Luís Almeida";@luis605 +shaders;shaders_depth_rendering;★★★☆;6.0;6.0;2025;2025;"Luís Almeida";@luis605 shaders;shaders_game_of_life;★★★☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant shaders;shaders_rlgl_compute;★★★★;4.0;4.0;2021;2025;"Teddy Astie";@tsnake41 +shaders;shaders_cel_shading;★★★☆;6.0;6.0;2026;2026;"Gleb A";@ggrizzly audio;audio_module_playing;★☆☆☆;1.5;3.5;2016;2025;"Ramon Santamaria";@raysan5 audio;audio_music_stream;★☆☆☆;1.3;4.2;2015;2025;"Ramon Santamaria";@raysan5 -audio;audio_raw_stream;★★★☆;1.6;4.2;2015;2025;"Ramon Santamaria";@raysan5 +audio;audio_raw_stream;★★★☆;1.6;6.0;2015;2026;"Ramon Santamaria";@raysan5 audio;audio_sound_loading;★☆☆☆;1.1;3.5;2014;2025;"Ramon Santamaria";@raysan5 audio;audio_mixed_processor;★★★★;4.2;4.2;2023;2025;"hkc";@hatkidchan audio;audio_stream_effects;★★★★;4.2;5.0;2022;2025;"Ramon Santamaria";@raysan5 audio;audio_sound_multi;★★☆☆;5.0;5.0;2023;2025;"Jeffery Myers";@JeffM2501 audio;audio_sound_positioning;★★☆☆;5.5;5.5;2025;2025;"Le Juez Victor";@Bigfoot71 -audio;audio_spectrum_visualizer;★★★☆;6.0;5.6-dev;2025;2025;"IANN";@meisei4 +audio;audio_spectrum_visualizer;★★★☆;6.0;6.0;2025;2025;"IANN";@meisei4 diff --git a/examples/models/models_animation_blend_custom.c b/examples/models/models_animation_blend_custom.c index 005982ec6..8262f6ac2 100644 --- a/examples/models/models_animation_blend_custom.c +++ b/examples/models/models_animation_blend_custom.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★★] 4/4 * -* Example originally created with raylib 5.5, last time updated with raylib 5.5 +* Example originally created with raylib 5.5, last time updated with raylib 6.0 * * Example contributed by dmitrii-brand (@dmitrii-brand) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/models/models_animation_blending.c b/examples/models/models_animation_blending.c index e44583299..e79067c3d 100644 --- a/examples/models/models_animation_blending.c +++ b/examples/models/models_animation_blending.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★★] 4/4 * -* Example originally created with raylib 5.5, last time updated with raylib 5.6-dev +* Example originally created with raylib 5.5, last time updated with raylib 6.0 * * Example contributed by Kirandeep (@Kirandeep-Singh-Khehra) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/models/models_animation_timing.c b/examples/models/models_animation_timing.c index 030ad81e1..52d262957 100644 --- a/examples/models/models_animation_timing.c +++ b/examples/models/models_animation_timing.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★☆] 3/4 * -* Example originally created with raylib 5.6, last time updated with raylib 5.6 +* Example originally created with raylib 5.6, last time updated with raylib 6.0 * * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software diff --git a/examples/models/models_decals.c b/examples/models/models_decals.c index 9eba33de6..6e80283f2 100644 --- a/examples/models/models_decals.c +++ b/examples/models/models_decals.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★★] 4/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5) * Based on previous work by @mrdoob diff --git a/examples/models/models_directional_billboard.c b/examples/models/models_directional_billboard.c index caab94afb..390616fa2 100644 --- a/examples/models/models_directional_billboard.c +++ b/examples/models/models_directional_billboard.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6 +* Example originally created with raylib 6.0, last time updated with raylib 5.6 * * Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/models/models_rotating_cube.c b/examples/models/models_rotating_cube.c index c5b633fea..7cfca1620 100644 --- a/examples/models/models_rotating_cube.c +++ b/examples/models/models_rotating_cube.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Jopestpe (@jopestpe) * diff --git a/examples/models/models_tesseract_view.c b/examples/models/models_tesseract_view.c index 1544873fb..9829d63e3 100644 --- a/examples/models/models_tesseract_view.c +++ b/examples/models/models_tesseract_view.c @@ -6,7 +6,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Timothy van der Valk (@arceryz) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shaders/shaders_depth_rendering.c b/examples/shaders/shaders_depth_rendering.c index 866135020..0bec4eb35 100644 --- a/examples/shaders/shaders_depth_rendering.c +++ b/examples/shaders/shaders_depth_rendering.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★☆] 3/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Luís Almeida (@luis605) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shapes/shapes_ball_physics.c b/examples/shapes/shapes_ball_physics.c index b790c7e90..f01a7c8e1 100644 --- a/examples/shapes/shapes_ball_physics.c +++ b/examples/shapes/shapes_ball_physics.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by David Buzatto (@davidbuzatto) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shapes/shapes_clock_of_clocks.c b/examples/shapes/shapes_clock_of_clocks.c index d87ec6411..ad87411f9 100644 --- a/examples/shapes/shapes_clock_of_clocks.c +++ b/examples/shapes/shapes_clock_of_clocks.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 5.5, last time updated with raylib 5.6-dev +* Example originally created with raylib 5.5, last time updated with raylib 6.0 * * Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shapes/shapes_lines_drawing.c b/examples/shapes/shapes_lines_drawing.c index 76e81abb5..c3ea0fc7b 100644 --- a/examples/shapes/shapes_lines_drawing.c +++ b/examples/shapes/shapes_lines_drawing.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6 +* Example originally created with raylib 6.0, last time updated with raylib 5.6 * * Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shapes/shapes_math_angle_rotation.c b/examples/shapes/shapes_math_angle_rotation.c index 63c9aaa91..bf7e84b86 100644 --- a/examples/shapes/shapes_math_angle_rotation.c +++ b/examples/shapes/shapes_math_angle_rotation.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6 +* Example originally created with raylib 6.0, last time updated with raylib 5.6 * * Example contributed by Kris (@krispy-snacc) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shapes/shapes_math_sine_cosine.c b/examples/shapes/shapes_math_sine_cosine.c index c9964a9ff..7ffa1c217 100644 --- a/examples/shapes/shapes_math_sine_cosine.c +++ b/examples/shapes/shapes_math_sine_cosine.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Jopestpe (@jopestpe) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shapes/shapes_penrose_tile.c b/examples/shapes/shapes_penrose_tile.c index f94eae763..0221a10b3 100644 --- a/examples/shapes/shapes_penrose_tile.c +++ b/examples/shapes/shapes_penrose_tile.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★★] 4/4 * -* Example originally created with raylib 5.5, last time updated with raylib 5.6-dev +* Example originally created with raylib 5.5, last time updated with raylib 6.0 * Based on: https://processing.org/examples/penrosetile.html * * Example contributed by David Buzatto (@davidbuzatto) and reviewed by Ramon Santamaria (@raysan5) diff --git a/examples/shapes/shapes_recursive_tree.c b/examples/shapes/shapes_recursive_tree.c index f15758773..3977eecc6 100644 --- a/examples/shapes/shapes_recursive_tree.c +++ b/examples/shapes/shapes_recursive_tree.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★☆] 3/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Jopestpe (@jopestpe) * diff --git a/examples/shapes/shapes_rlgl_color_wheel.c b/examples/shapes/shapes_rlgl_color_wheel.c index f02226a83..a03dcf2de 100644 --- a/examples/shapes/shapes_rlgl_color_wheel.c +++ b/examples/shapes/shapes_rlgl_color_wheel.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★☆] 3/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shapes/shapes_rlgl_triangle.c b/examples/shapes/shapes_rlgl_triangle.c index 56cdc43bc..30920131c 100644 --- a/examples/shapes/shapes_rlgl_triangle.c +++ b/examples/shapes/shapes_rlgl_triangle.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shapes/shapes_starfield_effect.c b/examples/shapes/shapes_starfield_effect.c index 484f4fb78..f0d5d57e1 100644 --- a/examples/shapes/shapes_starfield_effect.c +++ b/examples/shapes/shapes_starfield_effect.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 5.5, last time updated with raylib 5.6-dev +* Example originally created with raylib 5.5, last time updated with raylib 6.0 * * Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shapes/shapes_triangle_strip.c b/examples/shapes/shapes_triangle_strip.c index de712270c..aef0c0291 100644 --- a/examples/shapes/shapes_triangle_strip.c +++ b/examples/shapes/shapes_triangle_strip.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Jopestpe (@jopestpe) * diff --git a/examples/text/text_inline_styling.c b/examples/text/text_inline_styling.c index 8634ccc19..2d2b5e135 100644 --- a/examples/text/text_inline_styling.c +++ b/examples/text/text_inline_styling.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★☆] 3/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Wagner Barongello (@SultansOfCode) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/text/text_strings_management.c b/examples/text/text_strings_management.c index db4540081..60f0941f3 100644 --- a/examples/text/text_strings_management.c +++ b/examples/text/text_strings_management.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★☆] 3/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by David Buzatto (@davidbuzatto) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/text/text_words_alignment.c b/examples/text/text_words_alignment.c index 8017f33eb..f0ebc78a5 100644 --- a/examples/text/text_words_alignment.c +++ b/examples/text/text_words_alignment.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/textures/textures_clipboard_image.c b/examples/textures/textures_clipboard_image.c index aa955da2e..1e9ec0846 100644 --- a/examples/textures/textures_clipboard_image.c +++ b/examples/textures/textures_clipboard_image.c @@ -34,7 +34,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [textures] example - clipboard_image"); + InitWindow(screenWidth, screenHeight, "raylib [textures] example - clipboard image"); TextureCollection collection[MAX_TEXTURE_COLLECTION] = { 0 }; int currentCollectionIndex = 0; diff --git a/examples/textures/textures_sprite_stacking.c b/examples/textures/textures_sprite_stacking.c index b20474711..671e82461 100644 --- a/examples/textures/textures_sprite_stacking.c +++ b/examples/textures/textures_sprite_stacking.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 5.6-dev, last time updated with raylib 6.0 +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/projects/VS2022/examples/shaders_cel_shading.vcxproj b/projects/VS2022/examples/shaders_cel_shading.vcxproj new file mode 100644 index 000000000..c37636be1 --- /dev/null +++ b/projects/VS2022/examples/shaders_cel_shading.vcxproj @@ -0,0 +1,569 @@ + + + + + Debug.DLL + ARM64 + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + ARM64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {D5556782-5113-403C-8E7A-2417B8CD0CC6} + Win32Proj + shaders_cel_shading + 10.0 + shaders_cel_shading + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file diff --git a/projects/VS2022/examples/textures_clipboard_image.vcxproj b/projects/VS2022/examples/textures_clipboard_image.vcxproj new file mode 100644 index 000000000..ed2c667a2 --- /dev/null +++ b/projects/VS2022/examples/textures_clipboard_image.vcxproj @@ -0,0 +1,569 @@ + + + + + Debug.DLL + ARM64 + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + ARM64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654} + Win32Proj + textures_clipboard_image + 10.0 + textures_clipboard_image + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file diff --git a/projects/VS2022/examples/textures_magnifying_glass.vcxproj b/projects/VS2022/examples/textures_magnifying_glass.vcxproj new file mode 100644 index 000000000..3abbd2d94 --- /dev/null +++ b/projects/VS2022/examples/textures_magnifying_glass.vcxproj @@ -0,0 +1,569 @@ + + + + + Debug.DLL + ARM64 + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + ARM64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {099441CA-5A99-4E50-AA2E-EB397EF0A50A} + Win32Proj + textures_magnifying_glass + 10.0 + textures_magnifying_glass + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index 51782892c..7d10de904 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -437,6 +437,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_window_web", "examples EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_animation_timing", "examples\models_animation_timing.vcxproj", "{89D5A0E9-683C-465C-BF85-A880865175C8}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_magnifying_glass", "examples\textures_magnifying_glass.vcxproj", "{099441CA-5A99-4E50-AA2E-EB397EF0A50A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_clipboard_image", "examples\textures_clipboard_image.vcxproj", "{6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_cel_shading", "examples\shaders_cel_shading.vcxproj", "{D5556782-5113-403C-8E7A-2417B8CD0CC6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 @@ -5469,6 +5475,78 @@ Global {89D5A0E9-683C-465C-BF85-A880865175C8}.Release|x64.Build.0 = Release|x64 {89D5A0E9-683C-465C-BF85-A880865175C8}.Release|x86.ActiveCfg = Release|Win32 {89D5A0E9-683C-465C-BF85-A880865175C8}.Release|x86.Build.0 = Release|Win32 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Debug|ARM64.Build.0 = Debug|ARM64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Debug|x64.ActiveCfg = Debug|x64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Debug|x64.Build.0 = Debug|x64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Debug|x86.ActiveCfg = Debug|Win32 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Debug|x86.Build.0 = Debug|Win32 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Release|ARM64.ActiveCfg = Release|ARM64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Release|ARM64.Build.0 = Release|ARM64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Release|x64.ActiveCfg = Release|x64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Release|x64.Build.0 = Release|x64 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Release|x86.ActiveCfg = Release|Win32 + {099441CA-5A99-4E50-AA2E-EB397EF0A50A}.Release|x86.Build.0 = Release|Win32 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Debug|ARM64.Build.0 = Debug|ARM64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Debug|x64.ActiveCfg = Debug|x64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Debug|x64.Build.0 = Debug|x64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Debug|x86.ActiveCfg = Debug|Win32 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Debug|x86.Build.0 = Debug|Win32 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Release|ARM64.ActiveCfg = Release|ARM64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Release|ARM64.Build.0 = Release|ARM64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Release|x64.ActiveCfg = Release|x64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Release|x64.Build.0 = Release|x64 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Release|x86.ActiveCfg = Release|Win32 + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654}.Release|x86.Build.0 = Release|Win32 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Debug|ARM64.Build.0 = Debug|ARM64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Debug|x64.ActiveCfg = Debug|x64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Debug|x64.Build.0 = Debug|x64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Debug|x86.ActiveCfg = Debug|Win32 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Debug|x86.Build.0 = Debug|Win32 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release|ARM64.ActiveCfg = Release|ARM64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release|ARM64.Build.0 = Release|ARM64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release|x64.ActiveCfg = Release|x64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release|x64.Build.0 = Release|x64 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release|x86.ActiveCfg = Release|Win32 + {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -5689,6 +5767,9 @@ Global {BB9C957D-34F1-46AE-B64A-9E0499C1746D} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} {4E7157E0-6CDB-47AE-A19A-FEC3876FA8A3} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {89D5A0E9-683C-465C-BF85-A880865175C8} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} + {099441CA-5A99-4E50-AA2E-EB397EF0A50A} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} + {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} + {D5556782-5113-403C-8E7A-2417B8CD0CC6} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} diff --git a/tools/rexm/reports/examples_validation.md b/tools/rexm/reports/examples_validation.md index e46b93e46..25e32779a 100644 --- a/tools/rexm/reports/examples_validation.md +++ b/tools/rexm/reports/examples_validation.md @@ -109,6 +109,8 @@ Example elements validated: | shapes_penrose_tile | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_hilbert_curve | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_easings_testbed | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| textures_clipboard_image | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| textures_magnifying_glass | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_logo_raylib | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_srcrec_dstrec | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_image_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -184,7 +186,7 @@ Example elements validated: | models_directional_billboard | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_animation_blend_custom | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_animation_blending | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| models_animation_timming | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| models_animation_timing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_ascii_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_basic_lighting | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_model_shader | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -219,6 +221,7 @@ Example elements validated: | shaders_depth_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_game_of_life | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_rlgl_compute | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shaders_cel_shading | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_module_playing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_music_stream | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_raw_stream | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | From 19ec2588be8d1e9254a0c529f12e54033d098e18 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 16 Mar 2026 17:04:30 +0100 Subject: [PATCH 12/41] Update Makefiles for emsdk version 5.0.x, using required `node 22.16.0` and `Python 3.13.3` --- projects/4coder/Makefile | 6 +++--- projects/VSCode/Makefile | 4 ++-- src/Makefile | 4 ++-- tools/rexm/Makefile | 4 ++-- tools/rexm/rexm.c | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/projects/4coder/Makefile b/projects/4coder/Makefile index 1b598eed5..30dcd7770 100644 --- a/projects/4coder/Makefile +++ b/projects/4coder/Makefile @@ -2,7 +2,7 @@ # # raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 # -# Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2026 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. @@ -117,8 +117,8 @@ ifeq ($(PLATFORM),PLATFORM_WEB) EMSDK_PATH ?= C:/raylib/emsdk EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten CLANG_PATH = $(EMSDK_PATH)/upstream/bin - PYTHON_PATH = $(EMSDK_PATH)/python/3.9.2-nuget_64bit - NODE_PATH = $(EMSDK_PATH)/node/20.18.0_64bit/bin + PYTHON_PATH = $(EMSDK_PATH)/python/3.13.3_64bit + NODE_PATH = $(EMSDK_PATH)/node/22.16.0_64bit/bin export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH);C:\raylib\MinGW\bin:$$(PATH) endif diff --git a/projects/VSCode/Makefile b/projects/VSCode/Makefile index 219673670..4f6d03b31 100644 --- a/projects/VSCode/Makefile +++ b/projects/VSCode/Makefile @@ -120,8 +120,8 @@ ifeq ($(PLATFORM),PLATFORM_WEB) EMSDK_PATH ?= C:/raylib/emsdk EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten CLANG_PATH = $(EMSDK_PATH)/upstream/bin - PYTHON_PATH = $(EMSDK_PATH)/python/3.9.2-nuget_64bit - NODE_PATH = $(EMSDK_PATH)/node/20.18.0_64bit/bin + PYTHON_PATH = $(EMSDK_PATH)/python/3.13.3_64bit + NODE_PATH = $(EMSDK_PATH)/node/22.16.0_64bit/bin export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH):$$(PATH) endif diff --git a/src/Makefile b/src/Makefile index 9826ddf8e..b67ba3e6a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -198,8 +198,8 @@ ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_R EMSDK_PATH ?= C:/raylib/emsdk EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten CLANG_PATH := $(EMSDK_PATH)/upstream/bin - PYTHON_PATH := $(EMSDK_PATH)/python/3.9.2-nuget_64bit - NODE_PATH := $(EMSDK_PATH)/node/20.18.0_64bit/bin + PYTHON_PATH := $(EMSDK_PATH)/python/3.13.3_64bit + NODE_PATH := $(EMSDK_PATH)/node/22.16.0_64bit/bin export PATH := $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH);C:/raylib/MinGW/bin;$(PATH) endif endif diff --git a/tools/rexm/Makefile b/tools/rexm/Makefile index d7d71f64f..c8f2490c0 100644 --- a/tools/rexm/Makefile +++ b/tools/rexm/Makefile @@ -99,8 +99,8 @@ ifeq ($(PLATFORM_OS),WINDOWS) EMSDK_PATH ?= C:/raylib/emsdk EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten CLANG_PATH = $(EMSDK_PATH)/upstream/bin - PYTHON_PATH = $(EMSDK_PATH)/python/3.9.2-nuget_64bit - NODE_PATH = $(EMSDK_PATH)/node/20.18.0_64bit/bin + PYTHON_PATH = $(EMSDK_PATH)/python/3.13.3_64bit + NODE_PATH = $(EMSDK_PATH)/node/22.16.0_64bit/bin export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH):$$(PATH) endif endif diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index c681530c9..49d4dce9a 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -1504,11 +1504,11 @@ int main(int argc, char *argv[]) //ChangeDirectory(exBasePath); //_putenv("MAKE_PATH=C:\\raylib\\w64devkit\\bin"); //_putenv("EMSDK_PATH = C:\\raylib\\emsdk"); - //_putenv("PYTHON_PATH=$(EMSDK_PATH)\\python\\3.9.2-nuget_64bit"); - //_putenv("NODE_PATH=$(EMSDK_PATH)\\node\\20.18.0_64bit\\bin"); + //_putenv("PYTHON_PATH=$(EMSDK_PATH)\\python\\3.13.3_64bit"); + //_putenv("NODE_PATH=$(EMSDK_PATH)\\node\\22.16.0_64bit\\bin"); //_putenv("PATH=%PATH%;$(MAKE_PATH);$(EMSDK_PATH);$(NODE_PATH);$(PYTHON_PATH)"); - _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin;C:\\raylib\\emsdk\\python\\3.9.2-nuget_64bit;C:\\raylib\\emsdk\\node\\20.18.0_64bit\\bin"); + _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin;C:\\raylib\\emsdk\\python\\3.13.3_64bit;C:\\raylib\\emsdk\\node\\22.16.0_64bit\\bin"); #endif for (int i = 0; i < exBuildListCount; i++) From d2be4ac2c9b80dbcd3d9fe4b09d428fcca215426 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 16 Mar 2026 17:04:36 +0100 Subject: [PATCH 13/41] Update CHANGELOG --- CHANGELOG | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 192fe9207..f6a3e8ad1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,16 +8,16 @@ Release: raylib 6.0 (?? March 2026) ------------------------------------------------------------------------- KEY CHANGES: - New Software Renderer backend [rlsw] - - New rcore platform backend: Memory (memory buffer) - - New rcore platform backend: Win32 (experimental) - - New rcore platform backend: Emscripten (experimental) - - Redesigned Skeletal Animation System + - New platform backend: Memory (memory buffer) + - New platform backend: Win32 (experimental) + - New platform backend: Emscripten (experimental) - Redesigned fullscreen modes and high-dpi content scaling + - Redesigned Skeletal Animation System - Redesigned Build Config System [config.h] - New File System API - New Text Management API - New tool: [rexm] raylib examples manager - - New examples: +50 new examples and format unification + - Added +50 new examples to learn from Detailed changes: @@ -36,7 +36,7 @@ Detailed changes: [rcore] REVIEWED: Automation system, saving to memory buffer and binary file (#5476) by @belan2470 [rcore] REVIEWED: Check if `shader.locs` is not NULL before try to access (#5622) by @maiconpintoabreu [rcore] REVIEWED: Content scaling on macOS (#5186) by @mchcopl -[rcore] REVIEWED: `GetRandomValue()`, fix modulo bias (#5392) by @Marcos-D +[rcore] REVIEWED: `GetRandomValue()`, fix modulo bias (#5392) by @Marcos-D -WARNING- [rcore] REVIEWED: Controller not available after window init (#5358) by @sergii [rcore] REVIEWED: Cursor lock/unlock inconsistent behaviour (#5323) by @tacf [rcore] REVIEWED: Description of `RestoreWindow()` by @johnnymarler @@ -783,8 +783,9 @@ Detailed changes: Release: raylib 5.5 (18 November 2024) ------------------------------------------------------------------------- KEY CHANGES: - - New tool: raylib project creator - - New rcore backends: RGFW and SDL3 + - New tool: raylib project creator [rpc] + - New platform backends: RGFW + - New platform backends: SDL3 (along SDL2) - New platforms supported: Dreamcast, N64, PSP, PSVita, PS4 - Added GPU Skinning support (all platforms and GL versions) - Added raymath C++ operators From 7401214e92bc7aa41e3f06a7bd94a3182f38426b Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 16 Mar 2026 17:14:53 +0100 Subject: [PATCH 14/41] Update audio_stream_callback.c --- examples/audio/audio_stream_callback.c | 226 +++++++++++++------------ 1 file changed, 118 insertions(+), 108 deletions(-) diff --git a/examples/audio/audio_stream_callback.c b/examples/audio/audio_stream_callback.c index e31e8e80b..088c74dcb 100644 --- a/examples/audio/audio_stream_callback.c +++ b/examples/audio/audio_stream_callback.c @@ -6,133 +6,53 @@ * * Example originally created with raylib 6.0, last time updated with raylib 6.0 * -* Example created by Dan Hoang (@dan-hoang) and reviewed by +* Example created by Dan Hoang (@dan-hoang) and reviewed by Ramon Santamaria (@raysan5) +* +* NOTE: Example sends a wave to the audio device, +* user gets the choice of four waves: sine, square, triangle, and sawtooth +* A stream is set up to play to the audio device; stream is hooked to a callback that +* generates a wave, that is determined by user choice * * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software * -* Copyright (c) 2015-2026 +* Copyright (c) 2026 Dan Hoang (@dan-hoang) * ********************************************************************************************/ #include "raylib.h" + #include #include #define BUFFER_SIZE 4096 #define SAMPLE_RATE 44100 -// This example sends a wave to the audio device -// The user gets the choice of four waves: sine, square, triangle, and sawtooth -// A stream is set up to play to the audio device -// The stream is hooked to a callback that generates a wave -// The callback used is determined by user choice -typedef enum -{ +// Wave type +typedef enum { SINE, SQUARE, TRIANGLE, SAWTOOTH } WaveType; -int waveFrequency = 440; -int newWaveFrequency = 440; -int waveIndex = 0; +//------------------------------------------------------------------------------------ +// Module Functions Declaration +//------------------------------------------------------------------------------------ +static void SineCallback(void *framesOut, unsigned int frameCount); +static void SquareCallback(void *framesOut, unsigned int frameCount); +static void TriangleCallback(void *framesOut, unsigned int frameCount); +static void SawtoothCallback(void *framesOut, unsigned int frameCount); -// Buffer for keeping the last second of uploaded audio, part of which will be drawn on the screen -float buffer[SAMPLE_RATE] = {}; +static int waveFrequency = 440; +static int newWaveFrequency = 440; +static int waveIndex = 0; -void SineCallback(void *framesOut, unsigned int frameCount) -{ - int wavelength = SAMPLE_RATE/waveFrequency; - - // Synthesize the sine wave - for (int i = 0; i < frameCount; i++) - { - ((float *)framesOut)[i] = sin(2*PI*waveIndex/wavelength); - - waveIndex++; - - if (waveIndex >= wavelength) - { - waveFrequency = newWaveFrequency; - waveIndex = 0; - } - } - - // Save the synthesized samples for later drawing - for (int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount]; - for (int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i]; -} - -void SquareCallback(void *framesOut, unsigned int frameCount) -{ - int wavelength = SAMPLE_RATE/waveFrequency; - - // Synthesize the square wave - for (int i = 0; i < frameCount; i++) - { - ((float *)framesOut)[i] = (waveIndex < wavelength/2)? 1 : -1; - waveIndex++; - - if (waveIndex >= wavelength) - { - waveFrequency = newWaveFrequency; - waveIndex = 0; - } - } - - // Save the synthesized samples for later drawing - for (int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount]; - for (int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i]; -} - -void TriangleCallback(void *framesOut, unsigned int frameCount) -{ - int wavelength = SAMPLE_RATE/waveFrequency; - - // Synthesize the triangle wave - for (int i = 0; i < frameCount; i++) - { - ((float *)framesOut)[i] = (waveIndex < wavelength/2)? (-1 + 2.0f*waveIndex/(wavelength/2)) : (1 - 2.0f*(waveIndex - wavelength/2)/(wavelength/2)); - waveIndex++; - - if (waveIndex >= wavelength) - { - waveFrequency = newWaveFrequency; - waveIndex = 0; - } - } - - // Save the synthesized samples for later drawing - for (int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount]; - for (int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i]; -} - -void SawtoothCallback(void *framesOut, unsigned int frameCount) -{ - int wavelength = SAMPLE_RATE/waveFrequency; - - // Synthesize the sawtooth wave - for (int i = 0; i < frameCount; i++) - { - ((float *)framesOut)[i] = -1 + 2.0f*waveIndex/wavelength; - waveIndex++; - - if (waveIndex >= wavelength) - { - waveFrequency = newWaveFrequency; - waveIndex = 0; - } - } - - // Save the synthesized samples for later drawing - for (int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount]; - for (int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i]; -} - -AudioCallback waveCallbacks[] = { SineCallback, SquareCallback, TriangleCallback, SawtoothCallback }; -char *waveTypesAsString[] = { "sine", "square", "triangle", "sawtooth" }; +// Buffer to keep the last second of uploaded audio, +// part of which will be drawn on the screen +static float buffer[SAMPLE_RATE] = { 0 }; +static AudioCallback waveCallbacks[] = { SineCallback, SquareCallback, TriangleCallback, SawtoothCallback }; +static char *waveTypesAsString[] = { "sine", "square", "triangle", "sawtooth" }; //------------------------------------------------------------------------------------ // Program main entry point @@ -167,7 +87,6 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - if (IsKeyDown(KEY_UP)) { newWaveFrequency += 10; @@ -199,7 +118,6 @@ int main(void) SetAudioStreamCallback(stream, waveCallbacks[waveType]); } - //---------------------------------------------------------------------------------- // Draw @@ -226,7 +144,7 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- - UnloadAudioStream(stream); // Close raw audio stream and delete buffers from RAM + UnloadAudioStream(stream); // Close raw audio stream and delete buffers from RAM CloseAudioDevice(); // Close audio device (music streaming is automatically stopped) CloseWindow(); // Close window and OpenGL context @@ -234,3 +152,95 @@ int main(void) return 0; } + +//------------------------------------------------------------------------------------ +// Module Functions Definition +//------------------------------------------------------------------------------------ +static void SineCallback(void *framesOut, unsigned int frameCount) +{ + int wavelength = SAMPLE_RATE/waveFrequency; + + // Synthesize the sine wave + for (int i = 0; i < frameCount; i++) + { + ((float *)framesOut)[i] = sin(2*PI*waveIndex/wavelength); + + waveIndex++; + + if (waveIndex >= wavelength) + { + waveFrequency = newWaveFrequency; + waveIndex = 0; + } + } + + // Save the synthesized samples for later drawing + for (int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount]; + for (int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i]; +} + +static void SquareCallback(void *framesOut, unsigned int frameCount) +{ + int wavelength = SAMPLE_RATE/waveFrequency; + + // Synthesize the square wave + for (int i = 0; i < frameCount; i++) + { + ((float *)framesOut)[i] = (waveIndex < wavelength/2)? 1 : -1; + waveIndex++; + + if (waveIndex >= wavelength) + { + waveFrequency = newWaveFrequency; + waveIndex = 0; + } + } + + // Save the synthesized samples for later drawing + for (int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount]; + for (int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i]; +} + +static void TriangleCallback(void *framesOut, unsigned int frameCount) +{ + int wavelength = SAMPLE_RATE/waveFrequency; + + // Synthesize the triangle wave + for (int i = 0; i < frameCount; i++) + { + ((float *)framesOut)[i] = (waveIndex < wavelength/2)? (-1 + 2.0f*waveIndex/(wavelength/2)) : (1 - 2.0f*(waveIndex - wavelength/2)/(wavelength/2)); + waveIndex++; + + if (waveIndex >= wavelength) + { + waveFrequency = newWaveFrequency; + waveIndex = 0; + } + } + + // Save the synthesized samples for later drawing + for (int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount]; + for (int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i]; +} + +static void SawtoothCallback(void *framesOut, unsigned int frameCount) +{ + int wavelength = SAMPLE_RATE/waveFrequency; + + // Synthesize the sawtooth wave + for (int i = 0; i < frameCount; i++) + { + ((float *)framesOut)[i] = -1 + 2.0f*waveIndex/wavelength; + waveIndex++; + + if (waveIndex >= wavelength) + { + waveFrequency = newWaveFrequency; + waveIndex = 0; + } + } + + // Save the synthesized samples for later drawing + for (int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount]; + for (int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i]; +} From 483d68790037d0e7f87e4d4025788d802c84566e Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 16 Mar 2026 17:19:27 +0100 Subject: [PATCH 15/41] Updated examples versions, validated with REXM --- examples/Makefile | 1 + examples/Makefile.Web | 4 + examples/README.md | 19 +- examples/examples_list.txt | 15 +- examples/models/models_animation_timing.c | 2 +- .../models/models_directional_billboard.c | 2 +- examples/shaders/shaders_ascii_rendering.c | 2 +- examples/shaders/shaders_color_correction.c | 2 +- examples/shaders/shaders_game_of_life.c | 2 +- examples/shaders/shaders_mandelbrot_set.c | 2 +- .../shaders/shaders_normalmap_rendering.c | 2 +- .../examples/audio_stream_callback.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 29 +- tools/rexm/reports/examples_validation.md | 1 + 14 files changed, 628 insertions(+), 24 deletions(-) create mode 100644 projects/VS2022/examples/audio_stream_callback.vcxproj diff --git a/examples/Makefile b/examples/Makefile index 95719672c..6b15d22ff 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -747,6 +747,7 @@ AUDIO = \ audio/audio_sound_multi \ audio/audio_sound_positioning \ audio/audio_spectrum_visualizer \ + audio/audio_stream_callback \ audio/audio_stream_effects #EXAMPLES_LIST_END diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 4bf635a22..730fec5f9 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -721,6 +721,7 @@ AUDIO = \ audio/audio_sound_multi \ audio/audio_sound_positioning \ audio/audio_spectrum_visualizer \ + audio/audio_stream_callback \ audio/audio_stream_effects # Default target entry @@ -1596,6 +1597,9 @@ audio/audio_spectrum_visualizer: audio/audio_spectrum_visualizer.c --preload-file audio/resources/shaders/glsl100/fft.fs@resources/shaders/glsl100/fft.fs \ --preload-file audio/resources/country.mp3@resources/country.mp3 +audio/audio_stream_callback: audio/audio_stream_callback.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + audio/audio_stream_effects: audio/audio_stream_effects.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file audio/resources/country.mp3@resources/country.mp3 diff --git a/examples/README.md b/examples/README.md index 17719be00..43e2dcc63 100644 --- a/examples/README.md +++ b/examples/README.md @@ -17,7 +17,7 @@ You may find it easier to use than other toolchains, especially when it comes to - `zig build [module]` to compile all examples for a module (e.g. `zig build core`) - `zig build [example]` to compile _and run_ a particular example (e.g. `zig build core_basic_window`) -## EXAMPLES COLLECTION [TOTAL: 211] +## EXAMPLES COLLECTION [TOTAL: 212] ### category: core [49] @@ -216,10 +216,10 @@ Examples using raylib models functionality, including models loading/generation | [models_basic_voxel](models/models_basic_voxel.c) | models_basic_voxel | ⭐⭐☆☆ | 5.5 | 5.5 | [Tim Little](https://github.com/timlittle) | | [models_rotating_cube](models/models_rotating_cube.c) | models_rotating_cube | ⭐☆☆☆ | 6.0 | 6.0 | [Jopestpe](https://github.com/jopestpe) | | [models_decals](models/models_decals.c) | models_decals | ⭐⭐⭐⭐️ | 6.0 | 6.0 | [JP Mortiboys](https://github.com/themushroompirates) | -| [models_directional_billboard](models/models_directional_billboard.c) | models_directional_billboard | ⭐⭐☆☆ | 6.0 | 5.6 | [Robin](https://github.com/RobinsAviary) | +| [models_directional_billboard](models/models_directional_billboard.c) | models_directional_billboard | ⭐⭐☆☆ | 6.0 | 6.0 | [Robin](https://github.com/RobinsAviary) | | [models_animation_blend_custom](models/models_animation_blend_custom.c) | models_animation_blend_custom | ⭐⭐⭐⭐️ | 5.5 | 6.0 | [dmitrii-brand](https://github.com/dmitrii-brand) | | [models_animation_blending](models/models_animation_blending.c) | models_animation_blending | ⭐⭐⭐⭐️ | 5.5 | 6.0 | [Kirandeep](https://github.com/Kirandeep-Singh-Khehra) | -| [models_animation_timing](models/models_animation_timing.c) | models_animation_timing | ⭐⭐⭐☆ | 5.6 | 6.0 | [Ramon Santamaria](https://github.com/raysan5) | +| [models_animation_timing](models/models_animation_timing.c) | models_animation_timing | ⭐⭐⭐☆ | 6.0 | 6.0 | [Ramon Santamaria](https://github.com/raysan5) | ### category: shaders [35] @@ -227,7 +227,7 @@ Examples using raylib shaders functionality, including shaders loading, paramete | example | image | difficulty
level | version
created | last version
updated | original
developer | |-----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------| -| [shaders_ascii_rendering](shaders/shaders_ascii_rendering.c) | shaders_ascii_rendering | ⭐⭐☆☆ | 5.5 | 5.6 | [Maicon Santana](https://github.com/maiconpintoabreu) | +| [shaders_ascii_rendering](shaders/shaders_ascii_rendering.c) | shaders_ascii_rendering | ⭐⭐☆☆ | 5.5 | 6.0 | [Maicon Santana](https://github.com/maiconpintoabreu) | | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | shaders_basic_lighting | ⭐⭐⭐⭐️ | 3.0 | 4.2 | [Chris Camacho](https://github.com/chriscamacho) | | [shaders_model_shader](shaders/shaders_model_shader.c) | shaders_model_shader | ⭐⭐☆☆ | 1.3 | 3.7 | [Ramon Santamaria](https://github.com/raysan5) | | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | shaders_shapes_textures | ⭐⭐☆☆ | 1.7 | 3.7 | [Ramon Santamaria](https://github.com/raysan5) | @@ -239,15 +239,15 @@ Examples using raylib shaders functionality, including shaders loading, paramete | [shaders_texture_outline](shaders/shaders_texture_outline.c) | shaders_texture_outline | ⭐⭐⭐☆ | 4.0 | 4.0 | [Serenity Skiff](https://github.com/GoldenThumbs) | | [shaders_texture_waves](shaders/shaders_texture_waves.c) | shaders_texture_waves | ⭐⭐☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) | | [shaders_julia_set](shaders/shaders_julia_set.c) | shaders_julia_set | ⭐⭐⭐☆ | 2.5 | 4.0 | [Josh Colclough](https://github.com/joshcol9232) | -| [shaders_mandelbrot_set](shaders/shaders_mandelbrot_set.c) | shaders_mandelbrot_set | ⭐⭐⭐☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) | -| [shaders_color_correction](shaders/shaders_color_correction.c) | shaders_color_correction | ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) | +| [shaders_mandelbrot_set](shaders/shaders_mandelbrot_set.c) | shaders_mandelbrot_set | ⭐⭐⭐☆ | 6.0 | 6.0 | [Jordi Santonja](https://github.com/JordSant) | +| [shaders_color_correction](shaders/shaders_color_correction.c) | shaders_color_correction | ⭐⭐☆☆ | 6.0 | 6.0 | [Jordi Santonja](https://github.com/JordSant) | | [shaders_eratosthenes_sieve](shaders/shaders_eratosthenes_sieve.c) | shaders_eratosthenes_sieve | ⭐⭐⭐☆ | 2.5 | 4.0 | [ProfJski](https://github.com/ProfJski) | | [shaders_fog_rendering](shaders/shaders_fog_rendering.c) | shaders_fog_rendering | ⭐⭐⭐☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) | | [shaders_simple_mask](shaders/shaders_simple_mask.c) | shaders_simple_mask | ⭐⭐☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) | | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) | shaders_hot_reloading | ⭐⭐⭐☆ | 3.0 | 3.5 | [Ramon Santamaria](https://github.com/raysan5) | | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) | shaders_mesh_instancing | ⭐⭐⭐⭐️ | 3.7 | 4.2 | [seanpringle](https://github.com/seanpringle) | | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) | shaders_multi_sample2d | ⭐⭐☆☆ | 3.5 | 3.5 | [Ramon Santamaria](https://github.com/raysan5) | -| [shaders_normalmap_rendering](shaders/shaders_normalmap_rendering.c) | shaders_normalmap_rendering | ⭐⭐⭐⭐️ | 5.6 | 5.6 | [Jeremy Montgomery](https://github.com/Sir_Irk) | +| [shaders_normalmap_rendering](shaders/shaders_normalmap_rendering.c) | shaders_normalmap_rendering | ⭐⭐⭐⭐️ | 6.0 | 6.0 | [Jeremy Montgomery](https://github.com/Sir_Irk) | | [shaders_spotlight_rendering](shaders/shaders_spotlight_rendering.c) | shaders_spotlight_rendering | ⭐⭐☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) | | [shaders_deferred_rendering](shaders/shaders_deferred_rendering.c) | shaders_deferred_rendering | ⭐⭐⭐⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) | | [shaders_hybrid_rendering](shaders/shaders_hybrid_rendering.c) | shaders_hybrid_rendering | ⭐⭐⭐⭐️ | 4.2 | 4.2 | [Buğra Alptekin Sarı](https://github.com/BugraAlptekinSari) | @@ -259,11 +259,11 @@ Examples using raylib shaders functionality, including shaders loading, paramete | [shaders_lightmap_rendering](shaders/shaders_lightmap_rendering.c) | shaders_lightmap_rendering | ⭐⭐⭐☆ | 4.5 | 4.5 | [Jussi Viitala](https://github.com/nullstare) | | [shaders_rounded_rectangle](shaders/shaders_rounded_rectangle.c) | shaders_rounded_rectangle | ⭐⭐⭐☆ | 5.5 | 5.5 | [Anstro Pleuton](https://github.com/anstropleuton) | | [shaders_depth_rendering](shaders/shaders_depth_rendering.c) | shaders_depth_rendering | ⭐⭐⭐☆ | 6.0 | 6.0 | [Luís Almeida](https://github.com/luis605) | -| [shaders_game_of_life](shaders/shaders_game_of_life.c) | shaders_game_of_life | ⭐⭐⭐☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) | +| [shaders_game_of_life](shaders/shaders_game_of_life.c) | shaders_game_of_life | ⭐⭐⭐☆ | 6.0 | 6.0 | [Jordi Santonja](https://github.com/JordSant) | | [shaders_rlgl_compute](shaders/shaders_rlgl_compute.c) | shaders_rlgl_compute | ⭐⭐⭐⭐️ | 4.0 | 4.0 | [Teddy Astie](https://github.com/tsnake41) | | [shaders_cel_shading](shaders/shaders_cel_shading.c) | shaders_cel_shading | ⭐⭐⭐☆ | 6.0 | 6.0 | [Gleb A](https://github.com/ggrizzly) | -### category: audio [9] +### category: audio [10] Examples using raylib audio functionality, including sound/music loading and playing. This functionality is provided by raylib [raudio](../src/raudio.c) module. Note this module can be used standalone independently of raylib. @@ -278,6 +278,7 @@ Examples using raylib audio functionality, including sound/music loading and pla | [audio_sound_multi](audio/audio_sound_multi.c) | audio_sound_multi | ⭐⭐☆☆ | 5.0 | 5.0 | [Jeffery Myers](https://github.com/JeffM2501) | | [audio_sound_positioning](audio/audio_sound_positioning.c) | audio_sound_positioning | ⭐⭐☆☆ | 5.5 | 5.5 | [Le Juez Victor](https://github.com/Bigfoot71) | | [audio_spectrum_visualizer](audio/audio_spectrum_visualizer.c) | audio_spectrum_visualizer | ⭐⭐⭐☆ | 6.0 | 6.0 | [IANN](https://github.com/meisei4) | +| [audio_stream_callback](audio/audio_stream_callback.c) | audio_stream_callback | ⭐⭐⭐☆ | 6.0 | 6.0 | [Dan Hoang](https://github.com/dan-hoang) | Some example missing? As always, contributions are welcome, feel free to send new examples! Here is an [examples template](examples_template.c) with instructions to start with! diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 0fe453785..b5b27da1d 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -172,11 +172,11 @@ models;models_tesseract_view;★★☆☆;6.0;6.0;2024;2025;"Timothy van der Val models;models_basic_voxel;★★☆☆;5.5;5.5;2025;2025;"Tim Little";@timlittle models;models_rotating_cube;★☆☆☆;6.0;6.0;2025;2025;"Jopestpe";@jopestpe models;models_decals;★★★★;6.0;6.0;2025;2025;"JP Mortiboys";@themushroompirates -models;models_directional_billboard;★★☆☆;6.0;5.6;2025;2025;"Robin";@RobinsAviary +models;models_directional_billboard;★★☆☆;6.0;6.0;2025;2025;"Robin";@RobinsAviary models;models_animation_blend_custom;★★★★;5.5;6.0;2026;2026;"dmitrii-brand";@dmitrii-brand models;models_animation_blending;★★★★;5.5;6.0;2024;2026;"Kirandeep";@Kirandeep-Singh-Khehra -models;models_animation_timing;★★★☆;5.6;6.0;2026;2026;"Ramon Santamaria";@raysan5 -shaders;shaders_ascii_rendering;★★☆☆;5.5;5.6;2025;2025;"Maicon Santana";@maiconpintoabreu +models;models_animation_timing;★★★☆;6.0;6.0;2026;2026;"Ramon Santamaria";@raysan5 +shaders;shaders_ascii_rendering;★★☆☆;5.5;6.0;2025;2025;"Maicon Santana";@maiconpintoabreu shaders;shaders_basic_lighting;★★★★;3.0;4.2;2019;2025;"Chris Camacho";@chriscamacho shaders;shaders_model_shader;★★☆☆;1.3;3.7;2014;2025;"Ramon Santamaria";@raysan5 shaders;shaders_shapes_textures;★★☆☆;1.7;3.7;2015;2025;"Ramon Santamaria";@raysan5 @@ -188,15 +188,15 @@ shaders;shaders_texture_rendering;★★☆☆;2.0;3.7;2019;2025;"Michał Ciesie shaders;shaders_texture_outline;★★★☆;4.0;4.0;2021;2025;"Serenity Skiff";@GoldenThumbs shaders;shaders_texture_waves;★★☆☆;2.5;3.7;2019;2025;"Anata";@anatagawa shaders;shaders_julia_set;★★★☆;2.5;4.0;2019;2025;"Josh Colclough";@joshcol9232 -shaders;shaders_mandelbrot_set;★★★☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant -shaders;shaders_color_correction;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant +shaders;shaders_mandelbrot_set;★★★☆;6.0;6.0;2025;2025;"Jordi Santonja";@JordSant +shaders;shaders_color_correction;★★☆☆;6.0;6.0;2025;2025;"Jordi Santonja";@JordSant shaders;shaders_eratosthenes_sieve;★★★☆;2.5;4.0;2019;2025;"ProfJski";@ProfJski shaders;shaders_fog_rendering;★★★☆;2.5;3.7;2019;2025;"Chris Camacho";@chriscamacho shaders;shaders_simple_mask;★★☆☆;2.5;3.7;2019;2025;"Chris Camacho";@chriscamacho shaders;shaders_hot_reloading;★★★☆;3.0;3.5;2020;2025;"Ramon Santamaria";@raysan5 shaders;shaders_mesh_instancing;★★★★;3.7;4.2;2020;2025;"seanpringle";@seanpringle shaders;shaders_multi_sample2d;★★☆☆;3.5;3.5;2020;2025;"Ramon Santamaria";@raysan5 -shaders;shaders_normalmap_rendering;★★★★;5.6;5.6;2025;2025;"Jeremy Montgomery";@Sir_Irk +shaders;shaders_normalmap_rendering;★★★★;6.0;6.0;2025;2025;"Jeremy Montgomery";@Sir_Irk shaders;shaders_spotlight_rendering;★★☆☆;2.5;3.7;2019;2025;"Chris Camacho";@chriscamacho shaders;shaders_deferred_rendering;★★★★;4.5;4.5;2023;2025;"Justin Andreas Lacoste";@27justin shaders;shaders_hybrid_rendering;★★★★;4.2;4.2;2022;2025;"Buğra Alptekin Sarı";@BugraAlptekinSari @@ -208,7 +208,7 @@ shaders;shaders_basic_pbr;★★★★;5.0;5.5;2023;2025;"Afan OLOVCIC";@_DevDad shaders;shaders_lightmap_rendering;★★★☆;4.5;4.5;2019;2025;"Jussi Viitala";@nullstare shaders;shaders_rounded_rectangle;★★★☆;5.5;5.5;2025;2025;"Anstro Pleuton";@anstropleuton shaders;shaders_depth_rendering;★★★☆;6.0;6.0;2025;2025;"Luís Almeida";@luis605 -shaders;shaders_game_of_life;★★★☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant +shaders;shaders_game_of_life;★★★☆;6.0;6.0;2025;2025;"Jordi Santonja";@JordSant shaders;shaders_rlgl_compute;★★★★;4.0;4.0;2021;2025;"Teddy Astie";@tsnake41 shaders;shaders_cel_shading;★★★☆;6.0;6.0;2026;2026;"Gleb A";@ggrizzly audio;audio_module_playing;★☆☆☆;1.5;3.5;2016;2025;"Ramon Santamaria";@raysan5 @@ -220,3 +220,4 @@ audio;audio_stream_effects;★★★★;4.2;5.0;2022;2025;"Ramon Santamaria";@ra audio;audio_sound_multi;★★☆☆;5.0;5.0;2023;2025;"Jeffery Myers";@JeffM2501 audio;audio_sound_positioning;★★☆☆;5.5;5.5;2025;2025;"Le Juez Victor";@Bigfoot71 audio;audio_spectrum_visualizer;★★★☆;6.0;6.0;2025;2025;"IANN";@meisei4 +audio;audio_stream_callback;★★★☆;6.0;6.0;2026;2026;"Dan Hoang";@dan-hoang diff --git a/examples/models/models_animation_timing.c b/examples/models/models_animation_timing.c index 52d262957..a302322fe 100644 --- a/examples/models/models_animation_timing.c +++ b/examples/models/models_animation_timing.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★☆] 3/4 * -* Example originally created with raylib 5.6, last time updated with raylib 6.0 +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software diff --git a/examples/models/models_directional_billboard.c b/examples/models/models_directional_billboard.c index 390616fa2..56164943b 100644 --- a/examples/models/models_directional_billboard.c +++ b/examples/models/models_directional_billboard.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 6.0, last time updated with raylib 5.6 +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shaders/shaders_ascii_rendering.c b/examples/shaders/shaders_ascii_rendering.c index d3302bf53..a4225abe3 100644 --- a/examples/shaders/shaders_ascii_rendering.c +++ b/examples/shaders/shaders_ascii_rendering.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★☆☆] 2/4 * -* Example originally created with raylib 5.5, last time updated with raylib 5.6 +* Example originally created with raylib 5.5, last time updated with raylib 6.0 * * Example contributed by Maicon Santana (@maiconpintoabreu) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shaders/shaders_color_correction.c b/examples/shaders/shaders_color_correction.c index 826baecc7..8a78066f1 100644 --- a/examples/shaders/shaders_color_correction.c +++ b/examples/shaders/shaders_color_correction.c @@ -7,7 +7,7 @@ * NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support, * OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version * -* Example originally created with raylib 5.6, last time updated with raylib 5.6 +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Jordi Santonja (@JordSant) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shaders/shaders_game_of_life.c b/examples/shaders/shaders_game_of_life.c index 0ae91b756..251095e2b 100644 --- a/examples/shaders/shaders_game_of_life.c +++ b/examples/shaders/shaders_game_of_life.c @@ -7,7 +7,7 @@ * NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support, * OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version * -* Example originally created with raylib 5.6, last time updated with raylib 5.6 +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Jordi Santonja (@JordSant) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/examples/shaders/shaders_mandelbrot_set.c b/examples/shaders/shaders_mandelbrot_set.c index dc592b6e4..b5c8a8e94 100644 --- a/examples/shaders/shaders_mandelbrot_set.c +++ b/examples/shaders/shaders_mandelbrot_set.c @@ -9,7 +9,7 @@ * * NOTE: Shaders used in this example are #version 330 (OpenGL 3.3) * -* Example originally created with raylib 5.6, last time updated with raylib 5.6 +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Jordi Santonja (@JordSant) * Based on previous work by Josh Colclough (@joshcol9232) diff --git a/examples/shaders/shaders_normalmap_rendering.c b/examples/shaders/shaders_normalmap_rendering.c index 07399a78e..6d39cc28e 100644 --- a/examples/shaders/shaders_normalmap_rendering.c +++ b/examples/shaders/shaders_normalmap_rendering.c @@ -7,7 +7,7 @@ * NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support, * OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version * -* Example originally created with raylib 5.6, last time updated with raylib 5.6 +* Example originally created with raylib 6.0, last time updated with raylib 6.0 * * Example contributed by Jeremy Montgomery (@Sir_Irk) and reviewed by Ramon Santamaria (@raysan5) * diff --git a/projects/VS2022/examples/audio_stream_callback.vcxproj b/projects/VS2022/examples/audio_stream_callback.vcxproj new file mode 100644 index 000000000..70d3daae5 --- /dev/null +++ b/projects/VS2022/examples/audio_stream_callback.vcxproj @@ -0,0 +1,569 @@ + + + + + Debug.DLL + ARM64 + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + ARM64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED} + Win32Proj + audio_stream_callback + 10.0 + audio_stream_callback + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\audio + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\audio + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\audio + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\audio + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\audio + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\audio + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\audio + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\audio + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\audio + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\audio + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\audio + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\audio + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index 7d10de904..c852d7855 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -443,6 +443,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_clipboard_image", EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_cel_shading", "examples\shaders_cel_shading.vcxproj", "{D5556782-5113-403C-8E7A-2417B8CD0CC6}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "audio_stream_callback", "examples\audio_stream_callback.vcxproj", "{F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|ARM64 = Debug.DLL|ARM64 @@ -5547,6 +5549,30 @@ Global {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release|x64.Build.0 = Release|x64 {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release|x86.ActiveCfg = Release|Win32 {D5556782-5113-403C-8E7A-2417B8CD0CC6}.Release|x86.Build.0 = Release|Win32 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Debug|ARM64.Build.0 = Debug|ARM64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Debug|x64.ActiveCfg = Debug|x64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Debug|x64.Build.0 = Debug|x64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Debug|x86.ActiveCfg = Debug|Win32 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Debug|x86.Build.0 = Debug|Win32 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Release|ARM64.ActiveCfg = Release|ARM64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Release|ARM64.Build.0 = Release|ARM64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Release|x64.ActiveCfg = Release|x64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Release|x64.Build.0 = Release|x64 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Release|x86.ActiveCfg = Release|Win32 + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -5709,7 +5735,7 @@ Global {C54703BF-D68A-480D-BE27-49B62E45D582} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} {9CD8BCAD-F212-4BCC-BA98-899743CE3279} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} {0981CA28-E4A5-4DF1-987F-A41D09131EFC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} - {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} + {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} {6BFF72EA-7362-4A3B-B6E5-9A3655BBBDA3} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} {6777EC3C-077C-42FC-B4AD-B799CE55CCE4} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} {A61DAD9C-271C-4E95-81AA-DB4CD58564D4} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} @@ -5770,6 +5796,7 @@ Global {099441CA-5A99-4E50-AA2E-EB397EF0A50A} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} {6E6F4A8A-675A-42F2-8AD1-4BF2757C2654} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} {D5556782-5113-403C-8E7A-2417B8CD0CC6} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} + {F94B1675-03AE-4EB0-BC0E-071F3C33B9ED} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} diff --git a/tools/rexm/reports/examples_validation.md b/tools/rexm/reports/examples_validation.md index 25e32779a..3863ea38d 100644 --- a/tools/rexm/reports/examples_validation.md +++ b/tools/rexm/reports/examples_validation.md @@ -231,3 +231,4 @@ Example elements validated: | audio_sound_multi | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_sound_positioning | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_spectrum_visualizer | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| audio_stream_callback | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | From e0d3037e1519c2f64f9ee1c9adbaf1facc2d97b4 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 16 Mar 2026 17:51:44 +0100 Subject: [PATCH 16/41] Update raylib.h --- src/raylib.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/raylib.h b/src/raylib.h index a1391de19..951f1ffb3 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -7,6 +7,7 @@ * - Multiplatform: Windows, Linux, macOS, FreeBSD, Web, Android, Raspberry Pi, DRM native... * - Written in plain C code (C99) in PascalCase/camelCase notation * - Hardware accelerated with OpenGL (1.1, 2.1, 3.3, 4.3, ES2, ES3 - choose at compile) +* - Software renderer optional, for systems with no GPU: [rlsw] * - Custom OpenGL abstraction layer (usable as standalone module): [rlgl] * - Multiple Fonts formats supported (TTF, OTF, FNT, BDF, Sprite fonts) * - Many texture formats supportted, including compressed formats (DXT, ETC, ASTC) From 1eea511070ece8e4f96e961588811340ebd0b11e Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 16 Mar 2026 17:51:53 +0100 Subject: [PATCH 17/41] Remove trailing spaces --- .github/workflows/build_webassembly.yml | 18 +++++++++--------- examples/audio/audio_stream_callback.c | 8 ++++---- projects/4coder/Makefile | 8 ++++---- src/platforms/rcore_desktop_sdl.c | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build_webassembly.yml b/.github/workflows/build_webassembly.yml index 2a126ff46..1e4066c26 100644 --- a/.github/workflows/build_webassembly.yml +++ b/.github/workflows/build_webassembly.yml @@ -18,20 +18,20 @@ on: jobs: build: runs-on: windows-latest - + env: RELEASE_NAME: raylib-dev_webassembly - + steps: - name: Checkout uses: actions/checkout@master - + - name: Setup emsdk uses: mymindstorm/setup-emsdk@v14 with: version: 5.0.3 actions-cache-folder: 'emsdk-cache' - + - name: Setup Release Version run: | echo "RELEASE_NAME=raylib-${{ github.event.release.tag_name }}_webassembly" >> $GITHUB_ENV @@ -39,7 +39,7 @@ jobs: if: github.event_name == 'release' && github.event.action == 'published' - name: Setup Environment - run: | + run: | mkdir build cd build mkdir ${{ env.RELEASE_NAME }} @@ -47,14 +47,14 @@ jobs: mkdir include mkdir lib cd ../.. - + - name: Build Library run: | cd src emcc -v make PLATFORM=PLATFORM_WEB EMSDK_PATH="D:/a/raylib/raylib/emsdk-cache/emsdk-main" RAYLIB_RELEASE_PATH="../build/${{ env.RELEASE_NAME }}/lib" -B cd .. - + - name: Generate Artifacts run: | copy /Y .\src\raylib.h .\build\${{ env.RELEASE_NAME }}\include\raylib.h @@ -67,7 +67,7 @@ jobs: 7z a ./${{ env.RELEASE_NAME }}.zip ./${{ env.RELEASE_NAME }} dir shell: cmd - + - name: Upload Artifacts uses: actions/upload-artifact@v4 with: @@ -75,7 +75,7 @@ jobs: path: | ./build/${{ env.RELEASE_NAME }} !./build/${{ env.RELEASE_NAME }}.zip - + - name: Upload Artifact to Release uses: softprops/action-gh-release@v1 with: diff --git a/examples/audio/audio_stream_callback.c b/examples/audio/audio_stream_callback.c index 088c74dcb..a033571d1 100644 --- a/examples/audio/audio_stream_callback.c +++ b/examples/audio/audio_stream_callback.c @@ -8,9 +8,9 @@ * * Example created by Dan Hoang (@dan-hoang) and reviewed by Ramon Santamaria (@raysan5) * -* NOTE: Example sends a wave to the audio device, +* NOTE: Example sends a wave to the audio device, * user gets the choice of four waves: sine, square, triangle, and sawtooth -* A stream is set up to play to the audio device; stream is hooked to a callback that +* A stream is set up to play to the audio device; stream is hooked to a callback that * generates a wave, that is determined by user choice * * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, @@ -28,7 +28,7 @@ #define BUFFER_SIZE 4096 #define SAMPLE_RATE 44100 -// Wave type +// Wave type typedef enum { SINE, SQUARE, @@ -48,7 +48,7 @@ static int waveFrequency = 440; static int newWaveFrequency = 440; static int waveIndex = 0; -// Buffer to keep the last second of uploaded audio, +// Buffer to keep the last second of uploaded audio, // part of which will be drawn on the screen static float buffer[SAMPLE_RATE] = { 0 }; static AudioCallback waveCallbacks[] = { SineCallback, SquareCallback, TriangleCallback, SawtoothCallback }; diff --git a/projects/4coder/Makefile b/projects/4coder/Makefile index 30dcd7770..ec0977aaf 100644 --- a/projects/4coder/Makefile +++ b/projects/4coder/Makefile @@ -163,7 +163,7 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif ifeq ($(PLATFORM),PLATFORM_WEB) # HTML5 emscripten compiler - # WARNING: To compile to HTML5, code must be redesigned + # WARNING: To compile to HTML5, code must be redesigned # to use emscripten.h and emscripten_set_main_loop() CC = emcc endif @@ -297,12 +297,12 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) # Libraries for Debian GNU/Linux desktop compiling # NOTE: Required packages: libegl1-mesa-dev LDLIBS = -lraylib -lGL -lm -lpthread -ldl -lrt - + # On X11 requires also below libraries LDLIBS += -lX11 # NOTE: It seems additional libraries are not required any more, latest GLFW just dlopen them #LDLIBS += -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor - + # On Wayland windowing system, additional libraries requires ifeq ($(USE_WAYLAND_DISPLAY),TRUE) LDLIBS += -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon @@ -354,7 +354,7 @@ OBJS = main.c # For Android platform we call a custom Makefile.Android ifeq ($(PLATFORM),PLATFORM_ANDROID) - MAKEFILE_PARAMS = -f Makefile.Android + MAKEFILE_PARAMS = -f Makefile.Android export PROJECT_NAME export SRC_DIR else diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 5cd93ebd7..9b6bea987 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -2126,11 +2126,11 @@ int InitPlatform(void) //---------------------------------------------------------------------------- // Get base time from window initialization CORE.Time.base = (double)(SDL_GetPerformanceCounter()/SDL_GetPerformanceFrequency()); - + #if defined(_WIN32) && SUPPORT_WINMM_HIGHRES_TIMER && !SUPPORT_BUSY_WAIT_LOOP SDL_SetHint(SDL_HINT_TIMER_RESOLUTION, "1"); // SDL equivalent of timeBeginPeriod() and timeEndPeriod() #endif - + // NOTE: No need to call InitTimer(), let SDL manage it internally //---------------------------------------------------------------------------- From 22e1e86c52eb9650193557b22155eab3056a960e Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 17 Mar 2026 08:12:09 +0100 Subject: [PATCH 18/41] Update raylib.vcxproj.filters --- projects/VS2022/raylib/raylib.vcxproj.filters | 3 --- 1 file changed, 3 deletions(-) diff --git a/projects/VS2022/raylib/raylib.vcxproj.filters b/projects/VS2022/raylib/raylib.vcxproj.filters index 75cc28a7e..17ac7f9b8 100644 --- a/projects/VS2022/raylib/raylib.vcxproj.filters +++ b/projects/VS2022/raylib/raylib.vcxproj.filters @@ -102,9 +102,6 @@ Header Files - - Header Files - From 5cd7202777f9e9c35756527e3dc8a465a50e4367 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 17 Mar 2026 08:12:15 +0100 Subject: [PATCH 19/41] Update models_rlgl_solar_system.c --- examples/models/models_rlgl_solar_system.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/models/models_rlgl_solar_system.c b/examples/models/models_rlgl_solar_system.c index 0988ede8d..1becc6348 100644 --- a/examples/models/models_rlgl_solar_system.c +++ b/examples/models/models_rlgl_solar_system.c @@ -66,8 +66,6 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera, CAMERA_ORBITAL); - earthRotation += (5.0f*rotationSpeed); earthOrbitRotation += (365/360.0f*(5.0f*rotationSpeed)*rotationSpeed); moonRotation += (2.0f*rotationSpeed); From 93be463322ad2ae0c3940415b722ca44f9c8612b Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 17 Mar 2026 08:13:00 +0100 Subject: [PATCH 20/41] Added missing resource to `audio_module_playing` example #5664 --- examples/Makefile.Web | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 730fec5f9..68c34f31b 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -1570,7 +1570,8 @@ audio/audio_mixed_processor: audio/audio_mixed_processor.c --preload-file audio/resources/coin.wav@resources/coin.wav audio/audio_module_playing: audio/audio_module_playing.c - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ + --preload-file audio/resources/mini1111.xm@resources/mini1111.xm audio/audio_music_stream: audio/audio_music_stream.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ From e7d999e3c75c5b72a02afaf0f1455d88a599293d Mon Sep 17 00:00:00 2001 From: Le Juez Victor <90587919+Bigfoot71@users.noreply.github.com> Date: Tue, 17 Mar 2026 17:50:32 +0100 Subject: [PATCH 21/41] [rlsw] RenderTexture support (#5655) * review texture formats Added support for `R3G3B2`, `R5G6B5`, `R4G4B4A4` and `R5G5B5A1` Added depth formats * use of textures for the framebuffer - Framebuffers can now use all texture types that are already available. - The 24-bit depth format has been removed as it is no longer needed. - Framebuffer formats are still defined at compile time. - The allocated texture size is now preserved, which avoids frequent reallocations when resizing framebuffers and will allow the use of `glTexSubImage2D`. * review framebuffer blit/copy This greatly simplifies the framebuffer blit/copy logic while now supporting all pixel formats. It is slightly slower in debug builds, but this path is mainly kept for compatibility anyway. The `copy_fast` version is still used for the "normal" cases when presenting to the screen. * review pixel get/set less ops for certain formats + fixes * fix depth write * texture read/write cleanup + tweaks I made the pointers parameters `restrict` for reading/writing textures, which resulted in a slight improvement. And I reviewed the `static inline` statements, which could potentially bias the compiler; no difference, but it's cleaner. * style tweaks * review uint8_t <-> float conversion * added a reusable object pool system will allow management of both textures and framebuffers added support for `glTexSubImage2D` added handling of 'GL_OUT_OF_MEMORY' errors removed the default internal texture (unused) * added FBO API + refactored rasterizer dispatch logic * fix ndc projection + review presentation and rename rlsw's resize/copy/blit * add `glRenderbufferStorage` binding + tweaks and fixes * fix quad sorting + simplify quad rasterization part * fix line shaking issue * support of `GL_DRAW_FRAMEBUFFER_BINDING` * update rlgl - support of rlsw's framebuffers * fix pixel origin in line rasterization my bad, an oversight in my previous fix. This offset should have been moved here rather than per pixel during truncation. * style tweaks * fix vla issue with msvc - fill depth / fill color --- src/external/rlsw.h | 6547 +++++++++++++++++++++++++------------------ src/rlgl.h | 28 +- 2 files changed, 3881 insertions(+), 2694 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index 46cba4c74..81d4a54f1 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -51,10 +51,9 @@ * rlsw capabilities could be customized defining some internal * values before library inclusion (default values listed): * -* #define SW_GL_FRAMEBUFFER_COPY_BGRA true -* #define SW_GL_BINDING_COPY_TEXTURE true -* #define SW_COLOR_BUFFER_BITS 24 -* #define SW_DEPTH_BUFFER_BITS 16 +* #define SW_FRAMEBUFFER_OUTPUT_BGRA true +* #define SW_FRAMEBUFFER_COLOR_TYPE R8G8B8A8 +* #define SW_FRAMEBUFFER_DEPTH_TYPE D32 * #define SW_MAX_PROJECTION_STACK_SIZE 2 * #define SW_MAX_MODELVIEW_STACK_SIZE 8 * #define SW_MAX_TEXTURE_STACK_SIZE 2 @@ -102,6 +101,9 @@ #ifndef SW_MALLOC #define SW_MALLOC(sz) malloc(sz) #endif +#ifndef SW_CALLOC + #define SW_CALLOC(n,sz) calloc(n,sz) +#endif #ifndef SW_REALLOC #define SW_REALLOC(ptr, newSz) realloc(ptr, newSz) #endif @@ -117,16 +119,16 @@ #endif #endif -#ifndef SW_GL_FRAMEBUFFER_COPY_BGRA - #define SW_GL_FRAMEBUFFER_COPY_BGRA true +#ifndef SW_FRAMEBUFFER_OUTPUT_BGRA + #define SW_FRAMEBUFFER_OUTPUT_BGRA true #endif -#ifndef SW_COLOR_BUFFER_BITS - #define SW_COLOR_BUFFER_BITS 32 //< 32 (rgba), 16 (rgb packed) or 8 (rgb packed) +#ifndef SW_FRAMEBUFFER_COLOR_TYPE + #define SW_FRAMEBUFFER_COLOR_TYPE R8G8B8A8 // Or R5G6B5, R3G3B2, etc; see `sw_pixelformat_t` #endif -#ifndef SW_DEPTH_BUFFER_BITS - #define SW_DEPTH_BUFFER_BITS 16 //< 32, 24 or 16 +#ifndef SW_FRAMEBUFFER_DEPTH_TYPE + #define SW_FRAMEBUFFER_DEPTH_TYPE D32 // Or D16, D8 #endif #ifndef SW_MAX_PROJECTION_STACK_SIZE @@ -141,6 +143,10 @@ #define SW_MAX_TEXTURE_STACK_SIZE 2 #endif +#ifndef SW_MAX_FRAMEBUFFERS + #define SW_MAX_FRAMEBUFFERS 8 +#endif + #ifndef SW_MAX_TEXTURES #define SW_MAX_TEXTURES 128 #endif @@ -294,6 +300,7 @@ typedef double GLclampd; #define GL_LUMINANCE_ALPHA 0x190A #define GL_RGB 0x1907 #define GL_RGBA 0x1908 +#define GL_DEPTH_COMPONENT 0x1902 #define GL_BYTE 0x1400 #define GL_UNSIGNED_BYTE 0x1401 @@ -302,6 +309,70 @@ typedef double GLclampd; #define GL_INT 0x1404 #define GL_UNSIGNED_INT 0x1405 #define GL_FLOAT 0x1406 +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 + +// OpenGL internal formats (not all are supported; see SWinternalformat) +#define GL_ALPHA4 0x803B +#define GL_ALPHA8 0x803C +#define GL_ALPHA12 0x803D +#define GL_ALPHA16 0x803E +#define GL_LUMINANCE4 0x803F +#define GL_LUMINANCE8 0x8040 +#define GL_LUMINANCE12 0x8041 +#define GL_LUMINANCE16 0x8042 +#define GL_LUMINANCE4_ALPHA4 0x8043 +#define GL_LUMINANCE6_ALPHA2 0x8044 +#define GL_LUMINANCE8_ALPHA8 0x8045 +#define GL_LUMINANCE12_ALPHA4 0x8046 +#define GL_LUMINANCE12_ALPHA12 0x8047 +#define GL_LUMINANCE16_ALPHA16 0x8048 +#define GL_INTENSITY 0x8049 +#define GL_INTENSITY4 0x804A +#define GL_INTENSITY8 0x804B +#define GL_INTENSITY12 0x804C +#define GL_INTENSITY16 0x804D +#define GL_R3_G3_B2 0x2A10 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB8 0x8051 +#define GL_RGB10 0x8052 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B + +// OpenGL internal formats extension +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_R16F 0x822D +#define GL_RGB16F 0x881B +#define GL_RGBA16F 0x881A +#define GL_R32F 0x822E +#define GL_RGB32F 0x8815 +#define GL_RGBA32F 0x8814 + +// OpenGL GL_EXT_framebuffer_object +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 // WARNING: Not implemented (defined for RLGL) // OpenGL Definitions NOT USED #define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 @@ -320,13 +391,21 @@ typedef double GLclampd; #define GL_NOTEQUAL 0x0205 #define GL_GEQUAL 0x0206 #define GL_ALWAYS 0x0207 +#define GL_RENDERBUFFER 0x8D41 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 //---------------------------------------------------------------------------------- // OpenGL Bindings to rlsw //---------------------------------------------------------------------------------- -#define glReadPixels(x, y, w, h, f, t, p) swCopyFramebuffer((x), (y), (w), (h), (f), (t), (p)) +#define glReadPixels(x, y, w, h, f, t, p) swReadPixels((x), (y), (w), (h), (f), (t), (p)) #define glEnable(state) swEnable((state)) #define glDisable(state) swDisable((state)) +#define glGetIntegerv(pname, params) swGetIntegerv((pname), (params)) #define glGetFloatv(pname, params) swGetFloatv((pname), (params)) #define glGetString(pname) swGetString((pname)) #define glGetError() swGetError() @@ -381,23 +460,36 @@ typedef double GLclampd; #define glDrawElements(m,c,t,i) swDrawElements((m),(c),(t),(i)) #define glGenTextures(c, v) swGenTextures((c), (v)) #define glDeleteTextures(c, v) swDeleteTextures((c), (v)) -#define glTexImage2D(tr, l, if, w, h, b, f, t, p) swTexImage2D((w), (h), (f), (t), (p)) -#define glTexParameteri(tr, pname, param) swTexParameteri((pname), (param)) #define glBindTexture(tr, id) swBindTexture((id)) +#define glTexImage2D(tr, l, if, w, h, b, f, t, p) swTexImage2D((w), (h), (f), (t), (p)) +#define glTexSubImage2D(tr, l, x, y, w, h, f, t, p) swTexSubImage2D((x), (y), (w), (h), (f), (t), (p)); +#define glTexParameteri(tr, pname, param) swTexParameteri((pname), (param)) + +// OpenGL GL_EXT_framebuffer_object +#define glGenFramebuffers(c, v) swGenFramebuffers((c), (v)) +#define glDeleteFramebuffers(c, v) swDeleteFramebuffers((c), (v)) +#define glBindFramebuffer(tr, id) swBindFramebuffer((id)) +#define glFramebufferTexture2D(tr, a, t, tex, ml) swFramebufferTexture2D((a), (tex)) +#define glFramebufferRenderbuffer(tr, a, rbtr, rb) swFramebufferTexture2D((a), (rb)) +#define glCheckFramebufferStatus(tr) swCheckFramebufferStatus() +#define glGetFramebufferAttachmentParameteriv(tr, a, p, v) swGetFramebufferAttachmentParameteriv((a), (p), (v)) +#define glGenRenderbuffers(c, v) swGenTextures((c), (v)) +#define glDeleteRenderbuffers(c, v) swDeleteTextures((c), (v)) +#define glBindRenderbuffer(tr, rb) swBindTexture((rb)) +#define glRenderbufferStorage(tr, f, w, h) swTexStorage2D((w), (h), (f)) // OpenGL functions NOT IMPLEMENTED by rlsw -#define glDepthMask(X) ((void)(X)) -#define glColorMask(X,Y,Z,W) ((void)(X),(void)(Y),(void)(Z),(void)(W)) -#define glPixelStorei(X,Y) ((void)(X),(void)(Y)) -#define glHint(X,Y) ((void)(X),(void)(Y)) -#define glShadeModel(X) ((void)(X)) -#define glFrontFace(X) ((void)(X)) -#define glDepthFunc(X) ((void)(X)) -#define glTexSubImage2D(X,Y,Z,W,A,B,C,D,E) ((void)(X),(void)(Y),(void)(Z),(void)(W),(void)(A),(void)(B),(void)(C),(void)(D),(void)(E)) -#define glGetTexImage(X,Y,Z,W,A) ((void)(X),(void)(Y),(void)(Z),(void)(W),(void)(A)) -#define glNormal3f(X,Y,Z) ((void)(X),(void)(Y),(void)(Z)) -#define glNormal3fv(X) ((void)(X)) -#define glNormalPointer(X,Y,Z) ((void)(X),(void)(Y),(void)(Z)) +#define glDepthMask(X) ((void)(X)) +#define glColorMask(X,Y,Z,W) ((void)(X),(void)(Y),(void)(Z),(void)(W)) +#define glPixelStorei(X,Y) ((void)(X),(void)(Y)) +#define glHint(X,Y) ((void)(X),(void)(Y)) +#define glShadeModel(X) ((void)(X)) +#define glFrontFace(X) ((void)(X)) +#define glDepthFunc(X) ((void)(X)) +#define glGetTexImage(X,Y,Z,W,A) ((void)(X),(void)(Y),(void)(Z),(void)(W),(void)(A)) +#define glNormal3f(X,Y,Z) ((void)(X),(void)(Y),(void)(Z)) +#define glNormal3fv(X) ((void)(X)) +#define glNormalPointer(X,Y,Z) ((void)(X),(void)(Y),(void)(Z)) //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -427,7 +519,8 @@ typedef enum { SW_PROJECTION_STACK_DEPTH = GL_PROJECTION_STACK_DEPTH, SW_TEXTURE_MATRIX = GL_TEXTURE_MATRIX, SW_TEXTURE_STACK_DEPTH = GL_TEXTURE_STACK_DEPTH, - SW_VIEWPORT = GL_VIEWPORT + SW_VIEWPORT = GL_VIEWPORT, + SW_DRAW_FRAMEBUFFER_BINDING = GL_DRAW_FRAMEBUFFER_BINDING, } SWget; typedef enum { @@ -448,6 +541,7 @@ typedef enum { } SWarray; typedef enum { + SW_DRAW_INVALID = -1, SW_POINTS = GL_POINTS, SW_LINES = GL_LINES, SW_TRIANGLES = GL_TRIANGLES, @@ -484,21 +578,47 @@ typedef enum { SW_LUMINANCE_ALPHA = GL_LUMINANCE_ALPHA, SW_RGB = GL_RGB, SW_RGBA = GL_RGBA, + SW_DEPTH_COMPONENT = GL_DEPTH_COMPONENT, } SWformat; typedef enum { SW_UNSIGNED_BYTE = GL_UNSIGNED_BYTE, + SW_UNSIGNED_BYTE_3_3_2 = GL_UNSIGNED_BYTE_3_3_2, SW_BYTE = GL_BYTE, SW_UNSIGNED_SHORT = GL_UNSIGNED_SHORT, + SW_UNSIGNED_SHORT_5_6_5 = GL_UNSIGNED_SHORT_5_6_5, + SW_UNSIGNED_SHORT_4_4_4_4 = GL_UNSIGNED_SHORT_4_4_4_4, + SW_UNSIGNED_SHORT_5_5_5_1 = GL_UNSIGNED_SHORT_5_5_5_1, SW_SHORT = GL_SHORT, SW_UNSIGNED_INT = GL_UNSIGNED_INT, SW_INT = GL_INT, SW_FLOAT = GL_FLOAT } SWtype; +typedef enum { + SW_LUMINANCE8 = GL_LUMINANCE8, + SW_LUMINANCE8_ALPHA8 = GL_LUMINANCE8_ALPHA8, + SW_R3_G3_B2 = GL_R3_G3_B2, + SW_RGB8 = GL_RGB8, + SW_RGBA4 = GL_RGBA4, + SW_RGB5_A1 = GL_RGB5_A1, + SW_RGBA8 = GL_RGBA8, + SW_R16F = GL_R16F, + SW_RGB16F = GL_RGB16F, + SW_RGBA16F = GL_RGBA16F, + SW_R32F = GL_R32F, + SW_RGB32F = GL_RGB32F, + SW_RGBA32F = GL_RGBA32F, + SW_DEPTH_COMPONENT16 = GL_DEPTH_COMPONENT16, + SW_DEPTH_COMPONENT24 = GL_DEPTH_COMPONENT24, + SW_DEPTH_COMPONENT32 = GL_DEPTH_COMPONENT32, + SW_DEPTH_COMPONENT32F = GL_DEPTH_COMPONENT32F, + //SW_R5_G6_B5, // Not defined by OpenGL +} SWinternalformat; + typedef enum { SW_NEAREST = GL_NEAREST, - SW_LINEAR = GL_LINEAR + SW_LINEAR = GL_LINEAR } SWfilter; typedef enum { @@ -513,6 +633,23 @@ typedef enum { SW_TEXTURE_WRAP_T = GL_TEXTURE_WRAP_T } SWtexparam; +typedef enum { + SW_COLOR_ATTACHMENT = GL_COLOR_ATTACHMENT0, + SW_DEPTH_ATTACHMENT = GL_DEPTH_ATTACHMENT, +} SWattachment; + +typedef enum { + SW_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, + SW_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, +} SWattachget; + +typedef enum { + SW_FRAMEBUFFER_COMPLETE = GL_FRAMEBUFFER_COMPLETE, + SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, + SW_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT, + SW_FRAMEBUFFER_INCOMPLETE_DIMENSIONS = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS, +} SWfbstatus; + typedef enum { SW_NO_ERROR = GL_NO_ERROR, SW_INVALID_ENUM = GL_INVALID_ENUM, @@ -520,6 +657,7 @@ typedef enum { SW_STACK_OVERFLOW = GL_STACK_OVERFLOW, SW_STACK_UNDERFLOW = GL_STACK_UNDERFLOW, SW_INVALID_OPERATION = GL_INVALID_OPERATION, + SW_OUT_OF_MEMORY = GL_OUT_OF_MEMORY, } SWerrcode; //------------------------------------------------------------------------------------ @@ -528,9 +666,9 @@ typedef enum { SWAPI bool swInit(int w, int h); SWAPI void swClose(void); -SWAPI bool swResizeFramebuffer(int w, int h); -SWAPI void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels); -SWAPI void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels); +SWAPI bool swResize(int w, int h); +SWAPI void swReadPixels(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels); +SWAPI void swBlitPixels(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels); SWAPI void swEnable(SWstate state); SWAPI void swDisable(SWstate state); @@ -595,10 +733,17 @@ SWAPI void swDrawElements(SWdraw mode, int count, int type, const void *indices) SWAPI void swGenTextures(int count, uint32_t *textures); SWAPI void swDeleteTextures(int count, uint32_t *textures); - -SWAPI void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data); -SWAPI void swTexParameteri(int param, int value); SWAPI void swBindTexture(uint32_t id); +SWAPI void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data); +SWAPI void swTexSubImage2D(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +SWAPI void swTexParameteri(int param, int value); + +SWAPI void swGenFramebuffers(int count, uint32_t* framebuffers); +SWAPI void swDeleteFramebuffers(int count, uint32_t* framebuffers); +SWAPI void swBindFramebuffer(uint32_t id); +SWAPI void swFramebufferTexture2D(SWattachment attach, uint32_t texture); +SWAPI SWfbstatus swCheckFramebufferStatus(void); +SWAPI void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWattachget property, int *v); #endif // RLSW_H @@ -607,9 +752,10 @@ SWAPI void swBindTexture(uint32_t id); * RLSW IMPLEMENTATION * ************************************************************************************/ -#define RLSW_IMPLEMENTATION #if defined(RLSW_IMPLEMENTATION) +#undef RLSW_IMPLEMENTATION // Undef to allow template expanding without implementation redefinition + #include // Required for: malloc(), free() #include // Required for: NULL, size_t, uint8_t, uint16_t, uint32_t... #include // Required for: sinf(), cosf(), floorf(), fabsf(), sqrtf(), roundf() @@ -711,79 +857,27 @@ SWAPI void swBindTexture(uint32_t id); #define SW_DEG2RAD (SW_PI/180.0f) #define SW_RAD2DEG (180.0f/SW_PI) -#define SW_COLOR_PIXEL_SIZE (SW_COLOR_BUFFER_BITS >> 3) -#define SW_DEPTH_PIXEL_SIZE (SW_DEPTH_BUFFER_BITS >> 3) -#define SW_PIXEL_SIZE (SW_COLOR_PIXEL_SIZE + SW_DEPTH_PIXEL_SIZE) +#define SW_HANDLE_NULL 0u +#define SW_POOL_SLOT_LIVE 0x80u // bit7 of the generation byte +#define SW_POOL_SLOT_VER_MASK 0x7Fu // bits6:0 = anti-ABA counter -#if (SW_PIXEL_SIZE <= 4) - #define SW_PIXEL_ALIGNMENT 4 -#else // if (SW_PIXEL_SIZE <= 8) - #define SW_PIXEL_ALIGNMENT 8 -#endif +#define SW_CONCAT(a, b) a##b +#define SW_CONCATX(a, b) SW_CONCAT(a, b) -#if (SW_COLOR_BUFFER_BITS == 8) - #define SW_COLOR_TYPE uint8_t - #define SW_COLOR_IS_PACKED 1 - #define SW_COLOR_PACK_COMP 1 - #define SW_PACK_COLOR(r,g,b) ((((uint8_t)((r)*7+0.5f))&0x07)<<5 | (((uint8_t)((g)*7+0.5f))&0x07)<<2 | ((uint8_t)((b)*3+0.5f))&0x03) - #define SW_UNPACK_R(p) (((p)>>5)&0x07) - #define SW_UNPACK_G(p) (((p)>>2)&0x07) - #define SW_UNPACK_B(p) ((p)&0x03) - #define SW_SCALE_R(v) ((v)*255+3)/7 - #define SW_SCALE_G(v) ((v)*255+3)/7 - #define SW_SCALE_B(v) ((v)*255+1)/3 - #define SW_TO_FLOAT_R(v) ((v)*(1.0f/7.0f)) - #define SW_TO_FLOAT_G(v) ((v)*(1.0f/7.0f)) - #define SW_TO_FLOAT_B(v) ((v)*(1.0f/3.0f)) -#elif (SW_COLOR_BUFFER_BITS == 16) - #define SW_COLOR_TYPE uint16_t - #define SW_COLOR_IS_PACKED 1 - #define SW_COLOR_PACK_COMP 1 - #define SW_PACK_COLOR(r,g,b) ((((uint16_t)((r)*31+0.5f))&0x1F)<<11 | (((uint16_t)((g)*63+0.5f))&0x3F)<<5 | ((uint16_t)((b)*31+0.5f))&0x1F) - #define SW_UNPACK_R(p) (((p)>>11)&0x1F) - #define SW_UNPACK_G(p) (((p)>>5)&0x3F) - #define SW_UNPACK_B(p) ((p)&0x1F) - #define SW_SCALE_R(v) ((v)*255+15)/31 - #define SW_SCALE_G(v) ((v)*255+31)/63 - #define SW_SCALE_B(v) ((v)*255+15)/31 - #define SW_TO_FLOAT_R(v) ((v)*(1.0f/31.0f)) - #define SW_TO_FLOAT_G(v) ((v)*(1.0f/63.0f)) - #define SW_TO_FLOAT_B(v) ((v)*(1.0f/31.0f)) -#else // 32 bits - #define SW_COLOR_TYPE uint8_t - #define SW_COLOR_IS_PACKED 0 - #define SW_COLOR_PACK_COMP 4 -#endif +#define SW_FRAMEBUFFER_COLOR8_GET(c,p,o) SW_CONCATX(sw_pixel_get_color8_, SW_FRAMEBUFFER_COLOR_TYPE)((c),(p),(o)) +#define SW_FRAMEBUFFER_COLOR_GET(c,p,o) SW_CONCATX(sw_pixel_get_color_, SW_FRAMEBUFFER_COLOR_TYPE)((c),(p),(o)) +#define SW_FRAMEBUFFER_COLOR_SET(p,c,o) SW_CONCATX(sw_pixel_set_color_, SW_FRAMEBUFFER_COLOR_TYPE)((p),(c),(o)) -#if (SW_DEPTH_BUFFER_BITS == 16) - #define SW_DEPTH_TYPE uint16_t - #define SW_DEPTH_IS_PACKED 1 - #define SW_DEPTH_PACK_COMP 1 - #define SW_DEPTH_MAX UINT16_MAX - #define SW_DEPTH_SCALE (1.0f/UINT16_MAX) - #define SW_PACK_DEPTH(d) ((SW_DEPTH_TYPE)((d)*SW_DEPTH_MAX)) - #define SW_UNPACK_DEPTH(p) (p) -#elif (SW_DEPTH_BUFFER_BITS == 24) - #define SW_DEPTH_TYPE uint8_t - #define SW_DEPTH_IS_PACKED 0 - #define SW_DEPTH_PACK_COMP 3 - #define SW_DEPTH_MAX 0xFFFFFFU - #define SW_DEPTH_SCALE (1.0f/0xFFFFFFU) - #define SW_PACK_DEPTH_0(d) ((uint8_t)(((uint32_t)((d)*SW_DEPTH_MAX)>>16)&0xFFU)) - #define SW_PACK_DEPTH_1(d) ((uint8_t)(((uint32_t)((d)*SW_DEPTH_MAX)>>8)&0xFFU)) - #define SW_PACK_DEPTH_2(d) ((uint8_t)((uint32_t)((d)*SW_DEPTH_MAX)&0xFFU)) - #define SW_UNPACK_DEPTH(p) ((((uint32_t)(p)[0]<<16)|((uint32_t)(p)[1]<<8)|(uint32_t)(p)[2])) -#else // 32 bits - #define SW_DEPTH_TYPE float - #define SW_DEPTH_IS_PACKED 1 - #define SW_DEPTH_PACK_COMP 1 - #define SW_DEPTH_MAX 1.0f - #define SW_DEPTH_SCALE 1.0f - #define SW_PACK_DEPTH(d) ((SW_DEPTH_TYPE)(d)) - #define SW_UNPACK_DEPTH(p) (p) -#endif +#define SW_FRAMEBUFFER_DEPTH_GET(p,o) SW_CONCATX(sw_pixel_get_depth_, SW_FRAMEBUFFER_DEPTH_TYPE)((p),(o)) +#define SW_FRAMEBUFFER_DEPTH_SET(p,d,o) SW_CONCATX(sw_pixel_set_depth_, SW_FRAMEBUFFER_DEPTH_TYPE)((p),(d),(o)) -#define SW_STATE_CHECK(flags) (SW_STATE_CHECK_EX(RLSW.stateFlags, (flags))) +#define SW_FRAMEBUFFER_COLOR_FORMAT SW_CONCATX(SW_PIXELFORMAT_COLOR_, SW_FRAMEBUFFER_COLOR_TYPE) +#define SW_FRAMEBUFFER_DEPTH_FORMAT SW_CONCATX(SW_PIXELFORMAT_DEPTH_, SW_FRAMEBUFFER_DEPTH_TYPE) + +#define SW_FRAMEBUFFER_COLOR_SIZE SW_PIXELFORMAT_SIZE[SW_FRAMEBUFFER_COLOR_FORMAT] +#define SW_FRAMEBUFFER_DEPTH_SIZE SW_PIXELFORMAT_SIZE[SW_FRAMEBUFFER_DEPTH_FORMAT] + +#define SW_STATE_CHECK(flags) (SW_STATE_CHECK_EX(RLSW.stateFlags, (flags))) #define SW_STATE_CHECK_EX(state, flags) (((state) & (flags)) == (flags)) #define SW_STATE_SCISSOR_TEST (1 << 0) @@ -795,33 +889,34 @@ SWAPI void swBindTexture(uint32_t id); //---------------------------------------------------------------------------------- // Module Types and Structures Definition //---------------------------------------------------------------------------------- +// Aliases types +typedef uint32_t sw_handle_t; +typedef uint16_t sw_half_t; + // Pixel data format type -// NOTE: Enum aligned with raylib PixelFormat typedef enum { SW_PIXELFORMAT_UNKNOWN = 0, - SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE, // 8 bit per pixel (no alpha) - SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) - SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5, // 16 bpp - SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8, // 24 bpp - SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) - SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) - SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, // 32 bpp - SW_PIXELFORMAT_UNCOMPRESSED_R32, // 32 bpp (1 channel - float) - SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) - SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) - SW_PIXELFORMAT_UNCOMPRESSED_R16, // 16 bpp (1 channel - half float) - SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16, // 16*3 bpp (3 channels - half float) - SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16, // 16*4 bpp (4 channels - half float) + SW_PIXELFORMAT_COLOR_GRAYSCALE, // 8 bit per pixel (no alpha) + SW_PIXELFORMAT_COLOR_GRAYALPHA, // 8*2 bpp (2 channels) + SW_PIXELFORMAT_COLOR_R3G3B2, // 8 bpp + SW_PIXELFORMAT_COLOR_R5G6B5, // 16 bpp + SW_PIXELFORMAT_COLOR_R8G8B8, // 24 bpp + SW_PIXELFORMAT_COLOR_R5G5B5A1, // 16 bpp (1 bit alpha) + SW_PIXELFORMAT_COLOR_R4G4B4A4, // 16 bpp (4 bit alpha) + SW_PIXELFORMAT_COLOR_R8G8B8A8, // 32 bpp + SW_PIXELFORMAT_COLOR_R32, // 32 bpp (1 channel - float) + SW_PIXELFORMAT_COLOR_R32G32B32, // 32*3 bpp (3 channels - float) + SW_PIXELFORMAT_COLOR_R32G32B32A32, // 32*4 bpp (4 channels - float) + SW_PIXELFORMAT_COLOR_R16, // 16 bpp (1 channel - half float) + SW_PIXELFORMAT_COLOR_R16G16B16, // 16*3 bpp (3 channels - half float) + SW_PIXELFORMAT_COLOR_R16G16B16A16, // 16*4 bpp (4 channels - half float) + SW_PIXELFORMAT_DEPTH_D8, // 1 bpp + SW_PIXELFORMAT_DEPTH_D16, // 2 bpp + SW_PIXELFORMAT_DEPTH_D32, // 4 bpp + SW_PIXELFORMAT_COUNT } sw_pixelformat_t; -typedef void (*sw_factor_f)( - float *SW_RESTRICT factor, - const float *SW_RESTRICT src, - const float *SW_RESTRICT dst -); - typedef float sw_matrix_t[4*4]; -typedef uint16_t sw_half_t; typedef struct { float position[4]; // Position coordinates @@ -833,53 +928,58 @@ typedef struct { } sw_vertex_t; typedef struct { - uint8_t *pixels; // Texture pixels (RGBA32) - + void *pixels; // Texture pixels + sw_pixelformat_t format; // Texture format int width, height; // Dimensions of the texture int wMinus1, hMinus1; // Dimensions minus one - + int allocSz; // Allocated size SWfilter minFilter; // Minification filter SWfilter magFilter; // Magnification filter - SWwrap sWrap; // texcoord.x wrap mode SWwrap tWrap; // texcoord.y wrap mode - float tx; // Texel width float ty; // Texel height } sw_texture_t; -// Pixel data type -typedef SW_ALIGN(SW_PIXEL_ALIGNMENT) struct { - SW_COLOR_TYPE color[SW_COLOR_PACK_COMP]; - SW_DEPTH_TYPE depth[SW_DEPTH_PACK_COMP]; -#if (SW_PIXEL_SIZE % SW_PIXEL_ALIGNMENT != 0) - uint8_t padding[SW_PIXEL_ALIGNMENT - SW_PIXEL_SIZE % SW_PIXEL_ALIGNMENT]; -#endif -} sw_pixel_t; +typedef struct { + sw_texture_t color; + sw_texture_t depth; +} sw_default_framebuffer_t; typedef struct { - sw_pixel_t *pixels; - int width; - int height; - int allocSz; + sw_handle_t colorAttachment; + sw_handle_t depthAttachment; } sw_framebuffer_t; typedef struct { - sw_framebuffer_t framebuffer; // Main framebuffer - sw_pixel_t clearValue; // Clear value of the framebuffer + void *data; // flat storage [capacity*stride] bytes + uint8_t *gen; // generation per slot [capacity] + uint32_t *freeList; // free indices stack [capacity] + int freeCount; + int watermark; // next blank index (starts at 1, skips 0) + int capacity; + size_t stride; +} sw_pool_t; - float vpCenter[2]; // Viewport center - float vpHalf[2]; // Viewport half dimensions - int vpSize[2]; // Viewport dimensions (minus one) - int vpMin[2]; // Viewport minimum renderable point (top-left) - int vpMax[2]; // Viewport maximum renderable point (bottom-right) +typedef void (*sw_blend_factor_t)(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst); +typedef void (*sw_raster_triangle_f)(const sw_vertex_t *v0, const sw_vertex_t *v1, const sw_vertex_t *v2); +typedef void (*sw_raster_quad_f)(const sw_vertex_t *v0, const sw_vertex_t *v1, const sw_vertex_t *v2, const sw_vertex_t *v3); +typedef void (*sw_raster_line_f)(const sw_vertex_t *v0, const sw_vertex_t *v1); +typedef void (*sw_raster_point_f)(const sw_vertex_t *v); - int scMin[2]; // Scissor rectangle minimum renderable point (top-left) - int scMax[2]; // Scissor rectangle maximum renderable point (bottom-right) - float scClipMin[2]; // Scissor rectangle minimum renderable point in clip space - float scClipMax[2]; // Scissor rectangle maximum renderable point in clip space +typedef struct { + sw_default_framebuffer_t framebuffer; // Default framebuffer + float clearColor[4]; // Clear color of the framebuffer + float clearDepth; // Clear depth of the framebuffer - uint32_t currentTexture; // Current active texture id + float vpCenter[2]; // Viewport center + float vpHalf[2]; // Viewport half dimensions + int vpSize[2]; // Viewport dimensions + + int scMin[2]; // Scissor rectangle minimum renderable point (top-left) + int scMax[2]; // Scissor rectangle maximum renderable point (bottom-right) + float scClipMin[2]; // Scissor rectangle minimum renderable point in clip space + float scClipMax[2]; // Scissor rectangle maximum renderable point in clip space struct { float *positions; @@ -897,7 +997,6 @@ typedef struct { SWdraw drawMode; // Current primitive mode (e.g., lines, triangles) SWpoly polyMode; // Current polygon filling mode (e.g., lines, triangles) - int reqVertices; // Number of vertices required for the primitive being drawn float pointRadius; // Rasterized point radius float lineWidth; // Rasterized line width @@ -912,21 +1011,23 @@ typedef struct { sw_matrix_t matMVP; // Model view projection matrix, calculated and used internally bool isDirtyMVP; // Indicates if the MVP matrix should be rebuilt + sw_handle_t boundFramebufferId; // Framebuffer currently bound + sw_texture_t* colorBuffer; // Color buffer currently bound + sw_texture_t* depthBuffer; // Depth buffer currently bound + sw_pool_t framebufferPool; // Framebuffer object pool + + sw_texture_t* boundTexture; // Texture currently bound + sw_pool_t texturePool; // Texture object pool + SWfactor srcFactor; SWfactor dstFactor; - sw_factor_f srcFactorFunc; - sw_factor_f dstFactorFunc; + sw_blend_factor_t srcFactorFunc; + sw_blend_factor_t dstFactorFunc; SWface cullFace; // Faces to cull SWerrcode errCode; // Last error code - sw_texture_t *loadedTextures; - int loadedTextureCount; - - uint32_t *freeTextureIds; - int freeTextureIdCount; - uint32_t stateFlags; } sw_context_t; @@ -936,7 +1037,44 @@ typedef struct { static sw_context_t RLSW = { 0 }; //---------------------------------------------------------------------------------- -// Module Functions Declaration +// Internal Constants Definition +//---------------------------------------------------------------------------------- +// Pixel formats sizes in bytes +static const int SW_PIXELFORMAT_SIZE[SW_PIXELFORMAT_COUNT] = +{ + [SW_PIXELFORMAT_COLOR_GRAYSCALE] = 1, + [SW_PIXELFORMAT_COLOR_GRAYALPHA] = 2, + [SW_PIXELFORMAT_COLOR_R3G3B2] = 1, + [SW_PIXELFORMAT_COLOR_R5G6B5] = 2, + [SW_PIXELFORMAT_COLOR_R8G8B8] = 3, + [SW_PIXELFORMAT_COLOR_R5G5B5A1] = 2, + [SW_PIXELFORMAT_COLOR_R4G4B4A4] = 2, + [SW_PIXELFORMAT_COLOR_R8G8B8A8] = 4, + [SW_PIXELFORMAT_COLOR_R32] = 4, + [SW_PIXELFORMAT_COLOR_R32G32B32] = 12, + [SW_PIXELFORMAT_COLOR_R32G32B32A32] = 16, + [SW_PIXELFORMAT_COLOR_R16] = 2, + [SW_PIXELFORMAT_COLOR_R16G16B16] = 6, + [SW_PIXELFORMAT_COLOR_R16G16B16A16] = 8, + [SW_PIXELFORMAT_DEPTH_D8] = 1, + [SW_PIXELFORMAT_DEPTH_D16] = 2, + [SW_PIXELFORMAT_DEPTH_D32] = 4, +}; + +static const int SW_PRIMITIVE_VERTEX_COUNT[] = +{ + // Remember that this is acceptable; these are small indices + [SW_POINTS] = 1, + [SW_LINES] = 2, + [SW_TRIANGLES] = 3, + [SW_QUADS] = 4, +}; + +//---------------------------------------------------------------------------------- +// Internal Functions Definitions +//---------------------------------------------------------------------------------- + +// Math helper functions //---------------------------------------------------------------------------------- static inline void sw_matrix_id(sw_matrix_t dst) { @@ -977,12 +1115,24 @@ static inline void sw_matrix_mul_rst(float *SW_RESTRICT dst, const float *SW_RES static inline void sw_matrix_mul(sw_matrix_t dst, const sw_matrix_t left, const sw_matrix_t right) { float result[16]; - sw_matrix_mul_rst(result, left, right); - for (int i = 0; i < 16; i++) dst[i] = result[i]; } +static inline int sw_clamp_int(int v, int min, int max) +{ + if (v < min) return min; + if (v > max) return max; + return v; +} + +static inline int sw_clamp(float v, float min, float max) +{ + if (v < min) return min; + if (v > max) return max; + return v; +} + static inline float sw_saturate(float x) { union { float f; uint32_t u; } fb; @@ -1005,11 +1155,14 @@ static inline float sw_fract(float x) return (x - floorf(x)); } -static inline int sw_clampi(int v, int min, int max) +static inline uint8_t sw_luminance8(const uint8_t *color) { - if (v < min) return min; - if (v > max) return max; - return v; + return (uint8_t)((color[0]*77 + color[1]*150 + color[2]*29) >> 8); +} + +static inline float sw_luminance(const float *color) +{ + return color[0]*0.299f + color[1]*0.587f + color[2]*0.114f; } static inline void sw_lerp_vertex_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float t) @@ -1117,105 +1270,30 @@ static inline void sw_add_vertex_grad_scaled_PTCH( out->homogeneous[3] += gradients->homogeneous[3]*scale; } -static inline void sw_float_to_unorm8_simd(uint8_t dst[4], const float src[4]) -{ -#if defined(SW_HAS_NEON) - float32x4_t values = vld1q_f32(src); - float32x4_t scaled = vmulq_n_f32(values, 255.0f); - int32x4_t clamped_s32 = vcvtq_s32_f32(scaled); // f32 -> s32 (truncated) - int16x4_t narrow16_s = vqmovn_s32(clamped_s32); - int16x8_t combined16_s = vcombine_s16(narrow16_s, narrow16_s); - uint8x8_t narrow8_u = vqmovun_s16(combined16_s); - vst1_lane_u32((uint32_t*)dst, vreinterpret_u32_u8(narrow8_u), 0); -#elif defined(SW_HAS_SSE41) - __m128 values = _mm_loadu_ps(src); - __m128 scaled = _mm_mul_ps(values, _mm_set1_ps(255.0f)); - __m128i clamped = _mm_cvtps_epi32(scaled); // f32 -> s32 (truncated) - clamped = _mm_packus_epi32(clamped, clamped); // s32 -> u16 (saturated < 0 to 0) - clamped = _mm_packus_epi16(clamped, clamped); // u16 -> u8 (saturated > 255 to 255) - *(uint32_t*)dst = _mm_cvtsi128_si32(clamped); -#elif defined(SW_HAS_SSE2) - __m128 values = _mm_loadu_ps(src); - __m128 scaled = _mm_mul_ps(values, _mm_set1_ps(255.0f)); - __m128i clamped = _mm_cvtps_epi32(scaled); // f32 -> s32 (truncated) - clamped = _mm_packs_epi32(clamped, clamped); // s32 -> s16 (saturated) - clamped = _mm_packus_epi16(clamped, clamped); // s16 -> u8 (saturated < 0 to 0) - *(uint32_t*)dst = _mm_cvtsi128_si32(clamped); -#elif defined(SW_HAS_RVV) - // TODO: Sample code generated by AI, needs testing and review - // NOTE: RVV 1.0 specs define the use of __riscv_ prefix for instrinsic functions - size_t vl = __riscv_vsetvl_e32m1(4); // Load up to 4 floats into a vector register - vfloat32m1_t vsrc = __riscv_vle32_v_f32m1(src, vl); // Load float32 values - - // Clamp to [0.0f, 1.0f] - vfloat32m1_t vzero = __riscv_vfmv_v_f_f32m1(0.0f, vl); - vfloat32m1_t vone = __riscv_vfmv_v_f_f32m1(1.0f, vl); - vsrc = __riscv_vfmin_vv_f32m1(vsrc, vone, vl); - vsrc = __riscv_vfmax_vv_f32m1(vsrc, vzero, vl); - - // Multiply by 255.0f and add 0.5f for rounding - vfloat32m1_t vscaled = __riscv_vfmul_vf_f32m1(vsrc, 255.0f, vl); - vscaled = __riscv_vfadd_vf_f32m1(vscaled, 0.5f, vl); - - // Convert to unsigned integer (truncate toward zero) - vuint32m1_t vu32 = __riscv_vfcvt_xu_f_v_u32m1(vscaled, vl); - - // Narrow from u32 -> u8 - vuint8m1_t vu8 = __riscv_vnclipu_wx_u8m1(vu32, 0, vl); // Round toward zero - __riscv_vse8_v_u8m1(dst, vu8, vl); // Store result -#else - for (int i = 0; i < 4; i++) - { - float val = src[i]*255.0f; - val = (val > 255.0f)? 255.0f : val; - val = (val < 0.0f)? 0.0f : val; - dst[i] = (uint8_t)val; - } -#endif -} - -static inline void sw_float_from_unorm8_simd(float dst[4], const uint8_t src[4]) -{ -#if defined(SW_HAS_NEON) - uint8x8_t bytes8 = vld1_u8(src); // Reading 8 bytes, faster, but let's hope not hitting the end of the page (unlikely)... - uint16x8_t bytes16 = vmovl_u8(bytes8); - uint32x4_t ints = vmovl_u16(vget_low_u16(bytes16)); - float32x4_t floats = vcvtq_f32_u32(ints); - floats = vmulq_n_f32(floats, SW_INV_255); - vst1q_f32(dst, floats); -#elif defined(SW_HAS_SSE41) - __m128i bytes = _mm_cvtsi32_si128(*(const uint32_t *)src); - __m128i ints = _mm_cvtepu8_epi32(bytes); - __m128 floats = _mm_cvtepi32_ps(ints); - floats = _mm_mul_ps(floats, _mm_set1_ps(SW_INV_255)); - _mm_storeu_ps(dst, floats); -#elif defined(SW_HAS_SSE2) - __m128i bytes = _mm_cvtsi32_si128(*(const uint32_t *)src); - bytes = _mm_unpacklo_epi8(bytes, _mm_setzero_si128()); - __m128i ints = _mm_unpacklo_epi16(bytes, _mm_setzero_si128()); - __m128 floats = _mm_cvtepi32_ps(ints); - floats = _mm_mul_ps(floats, _mm_set1_ps(SW_INV_255)); - _mm_storeu_ps(dst, floats); -#elif defined(SW_HAS_RVV) - // TODO: Sample code generated by AI, needs testing and review - size_t vl = __riscv_vsetvl_e8m1(4); // Set vector length for 8-bit input elements - vuint8m1_t vsrc_u8 = __riscv_vle8_v_u8m1(src, vl); // Load 4 unsigned 8-bit integers - vuint32m1_t vsrc_u32 = __riscv_vwcvt_xu_u_v_u32m1(vsrc_u8, vl); // Widen to 32-bit unsigned integers - vfloat32m1_t vsrc_f32 = __riscv_vfcvt_f_xu_v_f32m1(vsrc_u32, vl); // Convert to float32 - vfloat32m1_t vnorm = __riscv_vfmul_vf_f32m1(vsrc_f32, SW_INV_255, vl); // Multiply by 1/255.0 to normalize - __riscv_vse32_v_f32m1(dst, vnorm, vl); // Store result -#else - dst[0] = (float)src[0]*SW_INV_255; - dst[1] = (float)src[1]*SW_INV_255; - dst[2] = (float)src[2]*SW_INV_255; - dst[3] = (float)src[3]*SW_INV_255; -#endif -} - // Half conversion functions +static inline uint16_t sw_float_to_half_ui(uint32_t ui) +{ + int32_t s = (ui >> 16) & 0x8000; + int32_t em = ui & 0x7fffffff; + + // bias exponent and round to nearest; 112 is relative exponent bias (127-15) + int32_t h = (em - (112 << 23) + (1 << 12)) >> 13; + + // underflow: flush to zero; 113 encodes exponent -14 + h = (em < (113 << 23))? 0 : h; + + // overflow: infinity; 143 encodes exponent 16 + h = (em >= (143 << 23))? 0x7c00 : h; + + // NaN; note that we convert all types of NaN to qNaN + h = (em > (255 << 23))? 0x7e00 : h; + + return (uint16_t)(s | h); +} + static inline uint32_t sw_half_to_float_ui(uint16_t h) { - uint32_t s = (uint32_t)(h & 0x8000) << 16; + uint32_t s = (unsigned)(h & 0x8000) << 16; int32_t em = h & 0x7fff; // bias exponent and pad mantissa with 0; 112 is relative exponent bias (127-15) @@ -1224,2229 +1302,147 @@ static inline uint32_t sw_half_to_float_ui(uint16_t h) // denormal: flush to zero r = (em < (1 << 10))? 0 : r; - // NOTE: infinity/NaN; NaN payload is preserved as a byproduct of unifying inf/nan cases - // 112 is an exponent bias fixup; since it is already applied once, applying it twice converts 31 to 255 + // infinity/NaN; note that we preserve NaN payload as a byproduct of unifying inf/nan cases + // 112 is an exponent bias fixup; since we already applied it once, applying it twice converts 31 to 255 r += (em >= (31 << 10))? (112 << 23) : 0; return s | r; } -static inline float sw_half_to_float(sw_half_t y) -{ - union { float f; uint32_t i; } v = { .i = sw_half_to_float_ui(y) }; - - return v.f; -} - -static inline uint16_t sw_half_from_float_ui(uint32_t ui) -{ - int32_t s = (ui >> 16) & 0x8000; - int32_t em = ui & 0x7fffffff; - - // Bias exponent and round to nearest; 112 is relative exponent bias (127-15) - int32_t h = (em - (112 << 23) + (1 << 12)) >> 13; - - // Underflow: flush to zero; 113 encodes exponent -14 - h = (em < (113 << 23))? 0 : h; - - // Overflow: infinity; 143 encodes exponent 16 - h = (em >= (143 << 23))? 0x7c00 : h; - - // NOTE: NaN; all types of NaN aree converted to qNaN - h = (em > (255 << 23))? 0x7e00 : h; - - return (uint16_t)(s | h); -} - -static inline sw_half_t sw_half_from_float(float i) +static inline sw_half_t sw_float_to_half(float i) { union { float f; uint32_t i; } v; v.f = i; - return sw_half_from_float_ui(v.i); + return sw_float_to_half_ui(v.i); } -// Framebuffer management functions -//------------------------------------------------------------------------------------------- -static inline bool sw_framebuffer_load(int w, int h) +static inline float sw_half_to_float(sw_half_t y) { - int size = w*h; + union { float f; uint32_t i; } v; + v.i = sw_half_to_float_ui(y); + return v.f; +} - RLSW.framebuffer.pixels = SW_MALLOC(sizeof(sw_pixel_t)*size); - if (RLSW.framebuffer.pixels == NULL) return false; +static inline uint8_t sw_expand_1to8(uint32_t v) { return v ? 255 : 0; } +static inline uint8_t sw_expand_2to8(uint32_t v) { return (uint8_t)(v*85); } +static inline uint8_t sw_expand_3to8(uint32_t v) { return (uint8_t)((v << 5) | (v << 2) | (v >> 1)); } +static inline uint8_t sw_expand_4to8(uint32_t v) { return (uint8_t)((v << 4) | v); } +static inline uint8_t sw_expand_5to8(uint32_t v) { return (uint8_t)((v << 3) | (v >> 2)); } +static inline uint8_t sw_expand_6to8(uint32_t v) { return (uint8_t)((v << 2) | (v >> 4)); } - RLSW.framebuffer.width = w; - RLSW.framebuffer.height = h; - RLSW.framebuffer.allocSz = size; +static inline float sw_expand_1tof(uint32_t v) { return v ? 1.0f : 0.0f; } +static inline float sw_expand_2tof(uint32_t v) { return (float)v*(1.0f/3.0f); } +static inline float sw_expand_3tof(uint32_t v) { return (float)v*(1.0f/7.0f); } +static inline float sw_expand_4tof(uint32_t v) { return (float)v*(1.0f/15.0f); } +static inline float sw_expand_5tof(uint32_t v) { return (float)v*(1.0f/31.0f); } +static inline float sw_expand_6tof(uint32_t v) { return (float)v*(1.0f/63.0f); } + +static inline uint32_t sw_compress_8to1(uint8_t v) { return v >> 7; } +static inline uint32_t sw_compress_8to2(uint8_t v) { return v >> 6; } +static inline uint32_t sw_compress_8to3(uint8_t v) { return v >> 5; } +static inline uint32_t sw_compress_8to4(uint8_t v) { return v >> 4; } +static inline uint32_t sw_compress_8to5(uint8_t v) { return v >> 3; } +static inline uint32_t sw_compress_8to6(uint8_t v) { return v >> 2; } + +static inline uint32_t sw_compress_fto1(float v) { return v >= 0.5f ? 1 : 0; } +static inline uint32_t sw_compress_fto2(float v) { return (uint32_t)(v* 3.0f + 0.5f) & 0x03; } +static inline uint32_t sw_compress_fto3(float v) { return (uint32_t)(v* 7.0f + 0.5f) & 0x07; } +static inline uint32_t sw_compress_fto4(float v) { return (uint32_t)(v*15.0f + 0.5f) & 0x0F; } +static inline uint32_t sw_compress_fto5(float v) { return (uint32_t)(v*31.0f + 0.5f) & 0x1F; } +static inline uint32_t sw_compress_fto6(float v) { return (uint32_t)(v*63.0f + 0.5f) & 0x3F; } +//------------------------------------------------------------------------------------------- + +// Object pool functions +//------------------------------------------------------------------------------------------- +static bool sw_pool_init(sw_pool_t *pool, int capacity, size_t stride) +{ + *pool = (sw_pool_t) { 0 }; + + pool->data = SW_CALLOC(capacity, stride); + pool->gen = SW_CALLOC(capacity, sizeof(uint8_t)); + pool->freeList = SW_MALLOC(capacity*sizeof(uint32_t)); + + if (!pool->data || !pool->gen || !pool->freeList) + { + SW_FREE(pool->data); + SW_FREE(pool->gen); + SW_FREE(pool->freeList); + return false; + } + + pool->watermark = 1; + pool->capacity = capacity; + pool->stride = stride; return true; } -static inline bool sw_framebuffer_resize(int w, int h) +static void sw_pool_destroy(sw_pool_t *pool) { - int newSize = w*h; + SW_FREE(pool->data); + SW_FREE(pool->gen); + SW_FREE(pool->freeList); + *pool = (sw_pool_t) { 0 }; +} - if (newSize <= RLSW.framebuffer.allocSz) +static sw_handle_t sw_pool_alloc(sw_pool_t *pool) +{ + uint32_t index; + + if (pool->freeCount > 0) { - RLSW.framebuffer.width = w; - RLSW.framebuffer.height = h; - return true; + index = pool->freeList[--pool->freeCount]; + } + else + { + if (pool->watermark >= pool->capacity) return SW_HANDLE_NULL; + index = (uint32_t)pool->watermark++; } - void *newPixels = SW_REALLOC(RLSW.framebuffer.pixels, sizeof(sw_pixel_t)*newSize); - if (newPixels == NULL) return false; + uint8_t ver = ((pool->gen[index] & SW_POOL_SLOT_VER_MASK) + 1) & SW_POOL_SLOT_VER_MASK; + if (ver == 0) ver = 1; + pool->gen[index] = SW_POOL_SLOT_LIVE | ver; - RLSW.framebuffer.pixels = newPixels; + uint8_t *slot = (uint8_t *)pool->data + index*pool->stride; + for (size_t i = 0; i < pool->stride; i++) slot[i] = 0; - RLSW.framebuffer.width = w; - RLSW.framebuffer.height = h; - RLSW.framebuffer.allocSz = newSize; + return (sw_handle_t)index; +} +static void *sw_pool_get(const sw_pool_t *pool, sw_handle_t handle) +{ + if (handle == SW_HANDLE_NULL) return NULL; + if ((int)handle >= pool->capacity) return NULL; + if (!(pool->gen[handle] & SW_POOL_SLOT_LIVE)) return NULL; + + return (char *)pool->data + handle*pool->stride; +} + +static bool sw_pool_valid(const sw_pool_t *pool, sw_handle_t handle) +{ + return sw_pool_get(pool, handle) != NULL; +} + +static bool sw_pool_free(sw_pool_t *pool, sw_handle_t handle) +{ + if (!sw_pool_valid(pool, handle)) return false; + + pool->gen[handle] &= SW_POOL_SLOT_VER_MASK; // delete live flag + pool->freeList[pool->freeCount++] = handle; return true; } - -static inline void sw_framebuffer_read_color(float dst[4], const sw_pixel_t *src) -{ -#if SW_COLOR_IS_PACKED - SW_COLOR_TYPE pixel = src->color[0]; - dst[0] = SW_TO_FLOAT_R(SW_UNPACK_R(pixel)); - dst[1] = SW_TO_FLOAT_G(SW_UNPACK_G(pixel)); - dst[2] = SW_TO_FLOAT_B(SW_UNPACK_B(pixel)); - dst[3] = 1.0f; -#else - sw_float_from_unorm8_simd(dst, src->color); -#endif -} - -static inline void sw_framebuffer_read_color8(uint8_t dst[4], const sw_pixel_t *src) -{ -#if SW_COLOR_IS_PACKED - SW_COLOR_TYPE pixel = src->color[0]; - dst[0] = SW_SCALE_R(SW_UNPACK_R(pixel)); - dst[1] = SW_SCALE_G(SW_UNPACK_G(pixel)); - dst[2] = SW_SCALE_B(SW_UNPACK_B(pixel)); - dst[3] = 255; -#else - const SW_COLOR_TYPE *p = src->color; - dst[0] = p[0]; - dst[1] = p[1]; - dst[2] = p[2]; - dst[3] = p[3]; -#endif -} - -static inline float sw_framebuffer_read_depth(const sw_pixel_t *src) -{ -#if SW_DEPTH_IS_PACKED - return src->depth[0]*SW_DEPTH_SCALE; -#else - return SW_UNPACK_DEPTH(src->depth)*SW_DEPTH_SCALE; -#endif -} - -static inline void sw_framebuffer_write_color(sw_pixel_t *dst, const float src[4]) -{ -#if SW_COLOR_IS_PACKED - dst->color[0] = SW_PACK_COLOR(src[0], src[1], src[2]); -#else - sw_float_to_unorm8_simd(dst->color, src); -#endif -} - -static inline void sw_framebuffer_write_depth(sw_pixel_t *dst, float depth) -{ - depth = sw_saturate(depth); // REVIEW: An overflow can occur in certain circumstances with clipping, and needs to be reviewed... - -#if SW_DEPTH_IS_PACKED - dst->depth[0] = SW_PACK_DEPTH(depth); -#else - dst->depth[0] = SW_PACK_DEPTH_0(depth); - dst->depth[1] = SW_PACK_DEPTH_1(depth); - dst->depth[2] = SW_PACK_DEPTH_2(depth); -#endif -} - -static inline void sw_framebuffer_fill_color(sw_pixel_t *ptr, int size, const SW_COLOR_TYPE color[SW_COLOR_PACK_COMP]) -{ - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) - { - int w = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) - { - sw_pixel_t *row = ptr + y*RLSW.framebuffer.width + RLSW.scMin[0]; - for (int x = 0; x < w; x++, row++) - { - for (int i = 0; i < SW_COLOR_PACK_COMP; i++) row->color[i] = color[i]; - } - } - } - else - { - for (int i = 0; i < size; i++, ptr++) - { - for (int j = 0; j < SW_COLOR_PACK_COMP; j++) ptr->color[j] = color[j]; - } - } -} - -static inline void sw_framebuffer_fill_depth(sw_pixel_t *ptr, int size, const SW_DEPTH_TYPE depth[SW_DEPTH_PACK_COMP]) -{ - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) - { - int w = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) - { - sw_pixel_t *row = ptr + y*RLSW.framebuffer.width + RLSW.scMin[0]; - for (int x = 0; x < w; x++, row++) - { - for (int i = 0; i < SW_DEPTH_PACK_COMP; i++) row->depth[i] = depth[i]; - } - } - } - else - { - for (int i = 0; i < size; i++, ptr++) - { - for (int j = 0; j < SW_DEPTH_PACK_COMP; j++) ptr->depth[j] = depth[j]; - } - } -} - -static inline void sw_framebuffer_fill(sw_pixel_t *ptr, int size, sw_pixel_t value) -{ - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) - { - int w = RLSW.scMax[0] - RLSW.scMin[0] + 1; - for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++) - { - sw_pixel_t *row = ptr + y*RLSW.framebuffer.width + RLSW.scMin[0]; - for (int x = 0; x < w; x++, row++) *row = value; - } - } - else - { - for (int i = 0; i < size; i++, ptr++) *ptr = value; - } -} - -static inline void sw_framebuffer_copy_fast(void* dst) -{ - int size = RLSW.framebuffer.width*RLSW.framebuffer.height; - const sw_pixel_t *pixels = RLSW.framebuffer.pixels; - -#if SW_COLOR_BUFFER_BITS == 8 - uint8_t *dst8 = (uint8_t*)dst; - for (int i = 0; i < size; i++) dst8[i] = pixels[i].color[0]; -#elif SW_COLOR_BUFFER_BITS == 16 - uint16_t *dst16 = (uint16_t*)dst; - for (int i = 0; i < size; i++) dst16[i] = *(uint16_t*)pixels[i].color; -#else // 32 bits - uint32_t *dst32 = (uint32_t*)dst; - #if SW_GL_FRAMEBUFFER_COPY_BGRA - for (int i = 0; i < size; i++) - { - const uint8_t *c = pixels[i].color; - dst32[i] = (uint32_t)c[2] | ((uint32_t)c[1] << 8) | ((uint32_t)c[0] << 16) | ((uint32_t)c[3] << 24); - } - #else // RGBA - for (int i = 0; i < size; i++) dst32[i] = *(uint32_t*)pixels[i].color; - #endif -#endif -} - -#define DEFINE_FRAMEBUFFER_COPY_BEGIN(name, DST_PTR_T) \ -static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T *dst) \ -{ \ - const int stride = RLSW.framebuffer.width; \ - const sw_pixel_t *src = RLSW.framebuffer.pixels + (y*stride + x); \ - \ - for (int iy = 0; iy < h; iy++) { \ - const sw_pixel_t *line = src; \ - for (int ix = 0; ix < w; ix++) { \ - uint8_t color[4]; \ - sw_framebuffer_read_color8(color, line); \ - -#define DEFINE_FRAMEBUFFER_COPY_END() \ - ++line; \ - } \ - src += stride; \ - } \ -} - -DEFINE_FRAMEBUFFER_COPY_BEGIN(GRAYSCALE, uint8_t) -{ - // NTSC grayscale conversion: Y = 0.299R + 0.587G + 0.114B - uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000); - *dst++ = gray; -} -DEFINE_FRAMEBUFFER_COPY_END() - -DEFINE_FRAMEBUFFER_COPY_BEGIN(GRAYALPHA, uint8_t) -{ - // Convert RGB to grayscale using NTSC formula - uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000); - - dst[0] = gray; - dst[1] = color[3]; // alpha - - dst += 2; -} -DEFINE_FRAMEBUFFER_COPY_END() - -DEFINE_FRAMEBUFFER_COPY_BEGIN(R5G6B5, uint16_t) -{ - // Convert 8-bit RGB to 5:6:5 format - uint8_t r5 = (color[0]*31 + 127)/255; - uint8_t g6 = (color[1]*63 + 127)/255; - uint8_t b5 = (color[2]*31 + 127)/255; - -#if SW_GL_FRAMEBUFFER_COPY_BGRA - uint16_t rgb565 = (b5 << 11) | (g6 << 5) | r5; -#else // RGBA - uint16_t rgb565 = (r5 << 11) | (g6 << 5) | b5; -#endif - - *dst++ = rgb565; -} -DEFINE_FRAMEBUFFER_COPY_END() - -DEFINE_FRAMEBUFFER_COPY_BEGIN(R8G8B8, uint8_t) -{ -#if SW_GL_FRAMEBUFFER_COPY_BGRA - dst[0] = color[2]; - dst[1] = color[1]; - dst[2] = color[0]; -#else // RGBA - dst[0] = color[0]; - dst[1] = color[1]; - dst[2] = color[2]; -#endif - - dst += 3; -} -DEFINE_FRAMEBUFFER_COPY_END() - -DEFINE_FRAMEBUFFER_COPY_BEGIN(R5G5B5A1, uint16_t) -{ - uint8_t r5 = (color[0]*31 + 127)/255; - uint8_t g5 = (color[1]*31 + 127)/255; - uint8_t b5 = (color[2]*31 + 127)/255; - uint8_t a1 = (color[3] >= 128)? 1 : 0; - -#if SW_GL_FRAMEBUFFER_COPY_BGRA - uint16_t pixel = (b5 << 11) | (g5 << 6) | (r5 << 1) | a1; -#else // RGBA - uint16_t pixel = (r5 << 11) | (g5 << 6) | (b5 << 1) | a1; -#endif - - *dst++ = pixel; -} -DEFINE_FRAMEBUFFER_COPY_END() - -DEFINE_FRAMEBUFFER_COPY_BEGIN(R4G4B4A4, uint16_t) -{ - uint8_t r4 = (color[0]*15 + 127)/255; - uint8_t g4 = (color[1]*15 + 127)/255; - uint8_t b4 = (color[2]*15 + 127)/255; - uint8_t a4 = (color[3]*15 + 127)/255; - -#if SW_GL_FRAMEBUFFER_COPY_BGRA - uint16_t pixel = (b4 << 12) | (g4 << 8) | (r4 << 4) | a4; -#else // RGBA - uint16_t pixel = (r4 << 12) | (g4 << 8) | (b4 << 4) | a4; -#endif - - *dst++ = pixel; -} -DEFINE_FRAMEBUFFER_COPY_END() - -DEFINE_FRAMEBUFFER_COPY_BEGIN(R8G8B8A8, uint8_t) -{ -#if SW_GL_FRAMEBUFFER_COPY_BGRA - dst[0] = color[2]; - dst[1] = color[1]; - dst[2] = color[0]; -#else // RGBA - dst[0] = color[0]; - dst[1] = color[1]; - dst[2] = color[2]; -#endif - dst[3] = color[3]; - - dst += 4; -} -DEFINE_FRAMEBUFFER_COPY_END() - -#define DEFINE_FRAMEBUFFER_BLIT_BEGIN(name, DST_PTR_T) \ -static inline void sw_framebuffer_blit_to_##name( \ - int xDst, int yDst, int wDst, int hDst, \ - int xSrc, int ySrc, int wSrc, int hSrc, \ - DST_PTR_T *dst) \ -{ \ - const sw_pixel_t *srcBase = RLSW.framebuffer.pixels; \ - const int fbWidth = RLSW.framebuffer.width; \ - \ - const uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \ - const uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \ - \ - for (int dy = 0; dy < hDst; dy++) { \ - uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \ - int sy = yFix >> 16; \ - const sw_pixel_t *srcLine = srcBase + sy*fbWidth + xSrc; \ - \ - const sw_pixel_t *srcPtr = srcLine; \ - for (int dx = 0; dx < wDst; dx++) { \ - uint32_t xFix = dx*xScale; \ - int sx = xFix >> 16; \ - const sw_pixel_t *pixel = srcPtr + sx; \ - uint8_t color[4]; \ - sw_framebuffer_read_color8(color, pixel); - -#define DEFINE_FRAMEBUFFER_BLIT_END() \ - } \ - } \ -} - -DEFINE_FRAMEBUFFER_BLIT_BEGIN(GRAYSCALE, uint8_t) -{ - uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000); - *dst++ = gray; -} -DEFINE_FRAMEBUFFER_BLIT_END() - -DEFINE_FRAMEBUFFER_BLIT_BEGIN(GRAYALPHA, uint8_t) -{ - uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000); - - dst[0] = gray; - dst[1] = color[3]; // alpha - - dst += 2; -} -DEFINE_FRAMEBUFFER_BLIT_END() - -DEFINE_FRAMEBUFFER_BLIT_BEGIN(R5G6B5, uint16_t) -{ - uint8_t r5 = (color[0]*31 + 127)/255; - uint8_t g6 = (color[1]*63 + 127)/255; - uint8_t b5 = (color[2]*31 + 127)/255; - -#if SW_GL_FRAMEBUFFER_COPY_BGRA - uint16_t rgb565 = (b5 << 11) | (g6 << 5) | r5; -#else // RGBA - uint16_t rgb565 = (r5 << 11) | (g6 << 5) | b5; -#endif - - *dst++ = rgb565; -} -DEFINE_FRAMEBUFFER_BLIT_END() - -DEFINE_FRAMEBUFFER_BLIT_BEGIN(R8G8B8, uint8_t) -{ -#if SW_GL_FRAMEBUFFER_COPY_BGRA - dst[0] = color[2]; - dst[1] = color[1]; - dst[2] = color[0]; -#else // RGBA - dst[0] = color[0]; - dst[1] = color[1]; - dst[2] = color[2]; -#endif - - dst += 3; -} -DEFINE_FRAMEBUFFER_BLIT_END() - -DEFINE_FRAMEBUFFER_BLIT_BEGIN(R5G5B5A1, uint16_t) -{ - uint8_t r5 = (color[0]*31 + 127)/255; - uint8_t g5 = (color[1]*31 + 127)/255; - uint8_t b5 = (color[2]*31 + 127)/255; - uint8_t a1 = (color[3] >= 128)? 1 : 0; - -#if SW_GL_FRAMEBUFFER_COPY_BGRA - uint16_t pixel = (b5 << 11) | (g5 << 6) | (r5 << 1) | a1; -#else // RGBA - uint16_t pixel = (r5 << 11) | (g5 << 6) | (b5 << 1) | a1; -#endif - - *dst++ = pixel; -} -DEFINE_FRAMEBUFFER_BLIT_END() - -DEFINE_FRAMEBUFFER_BLIT_BEGIN(R4G4B4A4, uint16_t) -{ - uint8_t r4 = (color[0]*15 + 127)/255; - uint8_t g4 = (color[1]*15 + 127)/255; - uint8_t b4 = (color[2]*15 + 127)/255; - uint8_t a4 = (color[3]*15 + 127)/255; - -#if SW_GL_FRAMEBUFFER_COPY_BGRA - uint16_t pixel = (b4 << 12) | (g4 << 8) | (r4 << 4) | a4; -#else // RGBA - uint16_t pixel = (r4 << 12) | (g4 << 8) | (b4 << 4) | a4; -#endif - - *dst++ = pixel; -} -DEFINE_FRAMEBUFFER_BLIT_END() - -DEFINE_FRAMEBUFFER_BLIT_BEGIN(R8G8B8A8, uint8_t) -{ -#if SW_GL_FRAMEBUFFER_COPY_BGRA - dst[0] = color[2]; - dst[1] = color[1]; - dst[2] = color[0]; -#else // RGBA - dst[0] = color[0]; - dst[1] = color[1]; - dst[2] = color[2]; -#endif - dst[3] = color[3]; - - dst += 4; -} -DEFINE_FRAMEBUFFER_BLIT_END() -//------------------------------------------------------------------------------------------- - -// Pixel format management functions -//------------------------------------------------------------------------------------------- -static inline int sw_get_pixel_format(SWformat format, SWtype type) -{ - int channels = 0; - int bitsPerChannel = 8; // Default: 8 bits per channel - - // Determine the number of channels (format) - switch (format) - { - case SW_LUMINANCE: channels = 1; break; - case SW_LUMINANCE_ALPHA: channels = 2; break; - case SW_RGB: channels = 3; break; - case SW_RGBA: channels = 4; break; - default: return SW_PIXELFORMAT_UNKNOWN; - } - - // Determine the depth of each channel (type) - switch (type) - { - case SW_UNSIGNED_BYTE: bitsPerChannel = 8; break; - case SW_BYTE: bitsPerChannel = 8; break; - case SW_UNSIGNED_SHORT: bitsPerChannel = 16; break; - case SW_SHORT: bitsPerChannel = 16; break; - case SW_UNSIGNED_INT: bitsPerChannel = 32; break; - case SW_INT: bitsPerChannel = 32; break; - case SW_FLOAT: bitsPerChannel = 32; break; - default: return SW_PIXELFORMAT_UNKNOWN; - } - - // Map the format and type to the correct internal format - if (bitsPerChannel == 8) - { - if (channels == 1) return SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; - if (channels == 2) return SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA; - if (channels == 3) return SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8; - if (channels == 4) return SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - } - else if (bitsPerChannel == 16) - { - if (channels == 1) return SW_PIXELFORMAT_UNCOMPRESSED_R16; - if (channels == 3) return SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16; - if (channels == 4) return SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16; - } - else if (bitsPerChannel == 32) - { - if (channels == 1) return SW_PIXELFORMAT_UNCOMPRESSED_R32; - if (channels == 3) return SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32; - if (channels == 4) return SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32; - } - - return SW_PIXELFORMAT_UNKNOWN; -} - -static inline void sw_get_pixel(uint8_t *color, const void *pixels, uint32_t offset, sw_pixelformat_t format) -{ - switch (format) - { - case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: - { - uint8_t gray = ((const uint8_t*)pixels)[offset]; - color[0] = gray; - color[1] = gray; - color[2] = gray; - color[3] = 255; - break; - } - case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: - { - const uint8_t *src = &((const uint8_t*)pixels)[offset*2]; - color[0] = src[0]; - color[1] = src[0]; - color[2] = src[0]; - color[3] = src[1]; - break; - } - case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: - { - uint16_t pixel = ((const uint16_t*)pixels)[offset]; - color[0] = ((pixel >> 11) & 0x1F)*255/31; // R (5 bits) - color[1] = ((pixel >> 5) & 0x3F)*255/63; // G (6 bits) - color[2] = (pixel & 0x1F)*255/31; // B (5 bits) - color[3] = 255; - break; - } - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: - { - const uint8_t *src = &((const uint8_t*)pixels)[offset*3]; - color[0] = src[0]; - color[1] = src[1]; - color[2] = src[2]; - color[3] = 255; - break; - } - case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: - { - uint16_t pixel = ((const uint16_t*)pixels)[offset]; - color[0] = ((pixel >> 11) & 0x1F)*255/31; // R (5 bits) - color[1] = ((pixel >> 6) & 0x1F)*255/31; // G (5 bits) - color[2] = ((pixel >> 1) & 0x1F)*255/31; // B (5 bits) - color[3] = (pixel & 0x01)*255; // A (1 bit) - break; - } - case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: - { - uint16_t pixel = ((const uint16_t*)pixels)[offset]; - color[0] = ((pixel >> 12) & 0x0F)*255/15; // R (4 bits) - color[1] = ((pixel >> 8) & 0x0F)*255/15; // G (4 bits) - color[2] = ((pixel >> 4) & 0x0F)*255/15; // B (4 bits) - color[3] = (pixel & 0x0F)*255/15; // A (4 bits) - break; - } - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: - { - const uint8_t *src = &((const uint8_t*)pixels)[offset*4]; - color[0] = src[0]; - color[1] = src[1]; - color[2] = src[2]; - color[3] = src[3]; - break; - } - case SW_PIXELFORMAT_UNCOMPRESSED_R32: - { - float val = ((const float*)pixels)[offset]; - uint8_t gray = (uint8_t)(val*255.0f); - color[0] = gray; - color[1] = gray; - color[2] = gray; - color[3] = 255; - break; - } - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: - { - const float *src = &((const float*)pixels)[offset*3]; - color[0] = (uint8_t)(src[0]*255.0f); - color[1] = (uint8_t)(src[1]*255.0f); - color[2] = (uint8_t)(src[2]*255.0f); - color[3] = 255; - break; - } - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: - { - const float *src = &((const float*)pixels)[offset*4]; - color[0] = (uint8_t)(src[0]*255.0f); - color[1] = (uint8_t)(src[1]*255.0f); - color[2] = (uint8_t)(src[2]*255.0f); - color[3] = (uint8_t)(src[3]*255.0f); - break; - } - case SW_PIXELFORMAT_UNCOMPRESSED_R16: - { - uint16_t val = ((const uint16_t*)pixels)[offset]; - uint8_t gray = sw_half_to_float(val)*SW_INV_255; - color[0] = gray; - color[1] = gray; - color[2] = gray; - color[3] = 255; - break; - } - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: - { - const uint16_t *src = &((const uint16_t*)pixels)[offset*3]; - color[0] = sw_half_to_float(src[0])*SW_INV_255; - color[1] = sw_half_to_float(src[1])*SW_INV_255; - color[2] = sw_half_to_float(src[2])*SW_INV_255; - color[3] = 255; - break; - } - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - { - const uint16_t *src = &((const uint16_t*)pixels)[offset*4]; - color[0] = sw_half_to_float(src[0])*SW_INV_255; - color[1] = sw_half_to_float(src[1])*SW_INV_255; - color[2] = sw_half_to_float(src[2])*SW_INV_255; - color[3] = sw_half_to_float(src[3])*SW_INV_255; - break; - } - case SW_PIXELFORMAT_UNKNOWN: - default: - { - color[0] = 0; - color[1] = 0; - color[2] = 0; - color[3] = 0; - break; - } - } -} -//------------------------------------------------------------------------------------------- - -// Texture sampling functionality -//------------------------------------------------------------------------------------------- -static inline void sw_texture_fetch(float* color, const sw_texture_t* tex, int x, int y) -{ - sw_float_from_unorm8_simd(color, &tex->pixels[4*(y*tex->width + x)]); -} - -static inline void sw_texture_sample_nearest(float *color, const sw_texture_t *tex, float u, float v) -{ - u = (tex->sWrap == SW_REPEAT)? sw_fract(u) : sw_saturate(u); - v = (tex->tWrap == SW_REPEAT)? sw_fract(v) : sw_saturate(v); - - int x = u*tex->width; - int y = v*tex->height; - - sw_texture_fetch(color, tex, x, y); -} - -static inline void sw_texture_sample_linear(float *color, const sw_texture_t *tex, float u, float v) -{ - // TODO: With a bit more cleverness thee number of operations can - // be clearly reduced, but for now it works fine - - float xf = (u*tex->width) - 0.5f; - float yf = (v*tex->height) - 0.5f; - - float fx = sw_fract(xf); - float fy = sw_fract(yf); - - int x0 = (int)xf; - int y0 = (int)yf; - - int x1 = x0 + 1; - int y1 = y0 + 1; - - // NOTE: If the textures are POT, avoid the division for SW_REPEAT - - if (tex->sWrap == SW_CLAMP) - { - x0 = (x0 > tex->wMinus1)? tex->wMinus1 : x0; - x1 = (x1 > tex->wMinus1)? tex->wMinus1 : x1; - } - else - { - x0 = (x0%tex->width + tex->width)%tex->width; - x1 = (x1%tex->width + tex->width)%tex->width; - } - - if (tex->tWrap == SW_CLAMP) - { - y0 = (y0 > tex->hMinus1)? tex->hMinus1 : y0; - y1 = (y1 > tex->hMinus1)? tex->hMinus1 : y1; - } - else - { - y0 = (y0%tex->height + tex->height)%tex->height; - y1 = (y1%tex->height + tex->height)%tex->height; - } - - float c00[4], c10[4], c01[4], c11[4]; - sw_texture_fetch(c00, tex, x0, y0); - sw_texture_fetch(c10, tex, x1, y0); - sw_texture_fetch(c01, tex, x0, y1); - sw_texture_fetch(c11, tex, x1, y1); - - for (int i = 0; i < 4; i++) - { - float t = c00[i] + fx*(c10[i] - c00[i]); - float b = c01[i] + fx*(c11[i] - c01[i]); - color[i] = t + fy*(b - t); - } -} - -static inline void sw_texture_sample(float *color, const sw_texture_t *tex, float u, float v, float dUdx, float dUdy, float dVdx, float dVdy) -{ - // Previous method: There is no need to compute the square root - // because using the squared value, the comparison remains (L2 > 1.0f*1.0f) - //float du = sqrtf(dUdx*dUdx + dUdy*dUdy); - //float dv = sqrtf(dVdx*dVdx + dVdy*dVdy); - //float L = (du > dv)? du : dv; - - // Calculate the derivatives for each axis - float dU2 = dUdx*dUdx + dUdy*dUdy; - float dV2 = dVdx*dVdx + dVdy*dVdy; - float L2 = (dU2 > dV2)? dU2 : dV2; - - SWfilter filter = (L2 > 1.0f)? tex->minFilter : tex->magFilter; - - switch (filter) - { - case SW_NEAREST: sw_texture_sample_nearest(color, tex, u, v); break; - case SW_LINEAR: sw_texture_sample_linear(color, tex, u, v); break; - default: break; - } -} -//------------------------------------------------------------------------------------------- - -// Color blending functionality -//------------------------------------------------------------------------------------------- -static inline void sw_factor_zero(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = factor[1] = factor[2] = factor[3] = 0.0f; -} - -static inline void sw_factor_one(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = factor[1] = factor[2] = factor[3] = 1.0f; -} - -static inline void sw_factor_src_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = src[0]; factor[1] = src[1]; factor[2] = src[2]; factor[3] = src[3]; -} - -static inline void sw_factor_one_minus_src_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = 1.0f - src[0]; factor[1] = 1.0f - src[1]; - factor[2] = 1.0f - src[2]; factor[3] = 1.0f - src[3]; -} - -static inline void sw_factor_src_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = factor[1] = factor[2] = factor[3] = src[3]; -} - -static inline void sw_factor_one_minus_src_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - float invAlpha = 1.0f - src[3]; - factor[0] = factor[1] = factor[2] = factor[3] = invAlpha; -} - -static inline void sw_factor_dst_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = factor[1] = factor[2] = factor[3] = dst[3]; -} - -static inline void sw_factor_one_minus_dst_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - float invAlpha = 1.0f - dst[3]; - factor[0] = factor[1] = factor[2] = factor[3] = invAlpha; -} - -static inline void sw_factor_dst_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = dst[0]; factor[1] = dst[1]; factor[2] = dst[2]; factor[3] = dst[3]; -} - -static inline void sw_factor_one_minus_dst_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = 1.0f - dst[0]; factor[1] = 1.0f - dst[1]; - factor[2] = 1.0f - dst[2]; factor[3] = 1.0f - dst[3]; -} - -static inline void sw_factor_src_alpha_saturate(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = factor[1] = factor[2] = 1.0f; - factor[3] = (src[3] < 1.0f)? src[3] : 1.0f; -} - -static inline void sw_blend_colors(float *SW_RESTRICT dst/*[4]*/, const float *SW_RESTRICT src/*[4]*/) -{ - float srcFactor[4], dstFactor[4]; - - RLSW.srcFactorFunc(srcFactor, src, dst); - RLSW.dstFactorFunc(dstFactor, src, dst); - - dst[0] = srcFactor[0]*src[0] + dstFactor[0]*dst[0]; - dst[1] = srcFactor[1]*src[1] + dstFactor[1]*dst[1]; - dst[2] = srcFactor[2]*src[2] + dstFactor[2]*dst[2]; - dst[3] = srcFactor[3]*src[3] + dstFactor[3]*dst[3]; -} -//------------------------------------------------------------------------------------------- - -// Projection helper functions -//------------------------------------------------------------------------------------------- -static inline void sw_project_ndc_to_screen(float screen[2], const float ndc[4]) -{ - screen[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalf[0] + 0.5f; - screen[1] = RLSW.vpCenter[1] - ndc[1]*RLSW.vpHalf[1] + 0.5f; -} -//------------------------------------------------------------------------------------------- - -// Polygon clipping management -//------------------------------------------------------------------------------------------- -#define DEFINE_CLIP_FUNC(name, FUNC_IS_INSIDE, FUNC_COMPUTE_T) \ -static inline int sw_clip_##name( \ - sw_vertex_t output[SW_MAX_CLIPPED_POLYGON_VERTICES], \ - const sw_vertex_t input[SW_MAX_CLIPPED_POLYGON_VERTICES], \ - int n) \ -{ \ - const sw_vertex_t *prev = &input[n - 1]; \ - int prevInside = FUNC_IS_INSIDE(prev->homogeneous); \ - int outputCount = 0; \ - \ - for (int i = 0; i < n; i++) { \ - const sw_vertex_t *curr = &input[i]; \ - int currInside = FUNC_IS_INSIDE(curr->homogeneous); \ - \ - /* If transition between interior/exterior, calculate intersection point */ \ - if (prevInside != currInside) { \ - float t = FUNC_COMPUTE_T(prev->homogeneous, curr->homogeneous); \ - sw_lerp_vertex_PTCH(&output[outputCount++], prev, curr, t); \ - } \ - \ - /* If current vertex inside, add it */ \ - if (currInside) { \ - output[outputCount++] = *curr; \ - } \ - \ - prev = curr; \ - prevInside = currInside; \ - } \ - \ - return outputCount; \ -} -//------------------------------------------------------------------------------------------- - -// Frustum cliping functions -//------------------------------------------------------------------------------------------- -#define IS_INSIDE_PLANE_W(h) ((h)[3] >= SW_CLIP_EPSILON) -#define IS_INSIDE_PLANE_X_POS(h) ( (h)[0] < (h)[3]) // Exclusive for +X -#define IS_INSIDE_PLANE_X_NEG(h) (-(h)[0] < (h)[3]) // Exclusive for -X -#define IS_INSIDE_PLANE_Y_POS(h) ( (h)[1] < (h)[3]) // Exclusive for +Y -#define IS_INSIDE_PLANE_Y_NEG(h) (-(h)[1] < (h)[3]) // Exclusive for -Y -#define IS_INSIDE_PLANE_Z_POS(h) ( (h)[2] <= (h)[3]) // Inclusive for +Z -#define IS_INSIDE_PLANE_Z_NEG(h) (-(h)[2] <= (h)[3]) // Inclusive for -Z - -#define COMPUTE_T_PLANE_W(hPrev, hCurr) ((SW_CLIP_EPSILON - (hPrev)[3])/((hCurr)[3] - (hPrev)[3])) -#define COMPUTE_T_PLANE_X_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[0])/(((hPrev)[3] - (hPrev)[0]) - ((hCurr)[3] - (hCurr)[0]))) -#define COMPUTE_T_PLANE_X_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[0])/(((hPrev)[3] + (hPrev)[0]) - ((hCurr)[3] + (hCurr)[0]))) -#define COMPUTE_T_PLANE_Y_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[1])/(((hPrev)[3] - (hPrev)[1]) - ((hCurr)[3] - (hCurr)[1]))) -#define COMPUTE_T_PLANE_Y_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[1])/(((hPrev)[3] + (hPrev)[1]) - ((hCurr)[3] + (hCurr)[1]))) -#define COMPUTE_T_PLANE_Z_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[2])/(((hPrev)[3] - (hPrev)[2]) - ((hCurr)[3] - (hCurr)[2]))) -#define COMPUTE_T_PLANE_Z_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[2])/(((hPrev)[3] + (hPrev)[2]) - ((hCurr)[3] + (hCurr)[2]))) - -DEFINE_CLIP_FUNC(w, IS_INSIDE_PLANE_W, COMPUTE_T_PLANE_W) -DEFINE_CLIP_FUNC(x_pos, IS_INSIDE_PLANE_X_POS, COMPUTE_T_PLANE_X_POS) -DEFINE_CLIP_FUNC(x_neg, IS_INSIDE_PLANE_X_NEG, COMPUTE_T_PLANE_X_NEG) -DEFINE_CLIP_FUNC(y_pos, IS_INSIDE_PLANE_Y_POS, COMPUTE_T_PLANE_Y_POS) -DEFINE_CLIP_FUNC(y_neg, IS_INSIDE_PLANE_Y_NEG, COMPUTE_T_PLANE_Y_NEG) -DEFINE_CLIP_FUNC(z_pos, IS_INSIDE_PLANE_Z_POS, COMPUTE_T_PLANE_Z_POS) -DEFINE_CLIP_FUNC(z_neg, IS_INSIDE_PLANE_Z_NEG, COMPUTE_T_PLANE_Z_NEG) -//------------------------------------------------------------------------------------------- - -// Scissor clip functions -//------------------------------------------------------------------------------------------- -#define COMPUTE_T_SCISSOR_X_MIN(hPrev, hCurr) (((RLSW.scClipMin[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMin[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMin[0])*(hPrev)[3]))) -#define COMPUTE_T_SCISSOR_X_MAX(hPrev, hCurr) (((RLSW.scClipMax[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMax[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMax[0])*(hPrev)[3]))) -#define COMPUTE_T_SCISSOR_Y_MIN(hPrev, hCurr) (((RLSW.scClipMin[1])*(hPrev)[3] - (hPrev)[1])/(((hCurr)[1] - (RLSW.scClipMin[1])*(hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMin[1])*(hPrev)[3]))) -#define COMPUTE_T_SCISSOR_Y_MAX(hPrev, hCurr) (((RLSW.scClipMax[1])*(hPrev)[3] - (hPrev)[1])/(((hCurr)[1] - (RLSW.scClipMax[1])*(hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMax[1])*(hPrev)[3]))) - -#define IS_INSIDE_SCISSOR_X_MIN(h) ((h)[0] >= (RLSW.scClipMin[0])*(h)[3]) -#define IS_INSIDE_SCISSOR_X_MAX(h) ((h)[0] <= (RLSW.scClipMax[0])*(h)[3]) -#define IS_INSIDE_SCISSOR_Y_MIN(h) ((h)[1] >= (RLSW.scClipMin[1])*(h)[3]) -#define IS_INSIDE_SCISSOR_Y_MAX(h) ((h)[1] <= (RLSW.scClipMax[1])*(h)[3]) - -DEFINE_CLIP_FUNC(scissor_x_min, IS_INSIDE_SCISSOR_X_MIN, COMPUTE_T_SCISSOR_X_MIN) -DEFINE_CLIP_FUNC(scissor_x_max, IS_INSIDE_SCISSOR_X_MAX, COMPUTE_T_SCISSOR_X_MAX) -DEFINE_CLIP_FUNC(scissor_y_min, IS_INSIDE_SCISSOR_Y_MIN, COMPUTE_T_SCISSOR_Y_MIN) -DEFINE_CLIP_FUNC(scissor_y_max, IS_INSIDE_SCISSOR_Y_MAX, COMPUTE_T_SCISSOR_Y_MAX) -//------------------------------------------------------------------------------------------- - -// Main polygon clip function -static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int *vertexCounter) -{ - static sw_vertex_t tmp[SW_MAX_CLIPPED_POLYGON_VERTICES]; - - int n = *vertexCounter; - - #define CLIP_AGAINST_PLANE(FUNC_CLIP) \ - { \ - n = FUNC_CLIP(tmp, polygon, n); \ - if (n < 3) \ - { \ - *vertexCounter = 0; \ - return false; \ - } \ - for (int i = 0; i < n; i++) polygon[i] = tmp[i]; \ - } - - CLIP_AGAINST_PLANE(sw_clip_w); - CLIP_AGAINST_PLANE(sw_clip_x_pos); - CLIP_AGAINST_PLANE(sw_clip_x_neg); - CLIP_AGAINST_PLANE(sw_clip_y_pos); - CLIP_AGAINST_PLANE(sw_clip_y_neg); - CLIP_AGAINST_PLANE(sw_clip_z_pos); - CLIP_AGAINST_PLANE(sw_clip_z_neg); - - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) - { - CLIP_AGAINST_PLANE(sw_clip_scissor_x_min); - CLIP_AGAINST_PLANE(sw_clip_scissor_x_max); - CLIP_AGAINST_PLANE(sw_clip_scissor_y_min); - CLIP_AGAINST_PLANE(sw_clip_scissor_y_max); - } - - *vertexCounter = n; - - return (n >= 3); -} - -// Triangle rendering logic -//------------------------------------------------------------------------------------------- -static inline bool sw_triangle_face_culling(void) -{ - // NOTE: Face culling is done before clipping to avoid unnecessary computations - // To handle triangles crossing the w=0 plane correctly, - // the winding order test is performeed in homogeneous coordinates directly, - // before the perspective division (division by w) - // This test determines the orientation of the triangle in the (x,y,w) plane, - // which corresponds to the projected 2D winding order sign, - // even with negative w values - - // Preload homogeneous coordinates into local variables - const float *h0 = RLSW.vertexBuffer[0].homogeneous; - const float *h1 = RLSW.vertexBuffer[1].homogeneous; - const float *h2 = RLSW.vertexBuffer[2].homogeneous; - - // Compute a value proportional to the signed area in the projected 2D plane, - // calculated directly using homogeneous coordinates BEFORE division by w - // This is the determinant of the matrix formed by the (x, y, w) components - // of the vertices, which correctly captures the winding order in homogeneous - // space and its relationship to the projected 2D winding order, even with - // negative w values - // The determinant formula used here is: - // h0.x*(h1.y*h2.w - h2.y*h1.w) + - // h1.x*(h2.y*h0.w - h0.y*h2.w) + - // h2.x*(h0.y*h1.w - h1.y*h0.w) - - const float hSgnArea = - h0[0]*(h1[1]*h2[3] - h2[1]*h1[3]) + - h1[0]*(h2[1]*h0[3] - h0[1]*h2[3]) + - h2[0]*(h0[1]*h1[3] - h1[1]*h0[3]); - - // Discard the triangle if its winding order (determined by the sign - // of the homogeneous area/determinant) matches the culled direction - // A positive hSgnArea typically corresponds to a counter-clockwise - // winding in the projected space when all w > 0 - // This test is robust for points with w > 0 or w < 0, correctly - // capturing the change in orientation when crossing the w=0 plane - - // The culling logic remains the same based on the signed area/determinant - // A value of 0 for hSgnArea means the points are collinear in (x, y, w) - // space, which corresponds to a degenerate triangle projection - // Such triangles are typically not culled by this test (0 < 0 is false, 0 > 0 is false) - // and should be handled by the clipper if necessary - return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0) : (hSgnArea > 0); // Cull if winding is "clockwise" : "counter-clockwise" -} - -static inline void sw_triangle_clip_and_project(void) -{ - sw_vertex_t *polygon = RLSW.vertexBuffer; - int *vertexCounter = &RLSW.vertexCounter; - - if (sw_polygon_clip(polygon, vertexCounter)) - { - // Transformation to screen space and normalization - for (int i = 0; i < *vertexCounter; i++) - { - sw_vertex_t *v = &polygon[i]; - - // Calculation of the reciprocal of W for normalization - // as well as perspective-correct attributes - const float wRcp = 1.0f/v->homogeneous[3]; - v->homogeneous[3] = wRcp; - - // Division of XYZ coordinates by weight - v->homogeneous[0] *= wRcp; - v->homogeneous[1] *= wRcp; - v->homogeneous[2] *= wRcp; - - // Division of texture coordinates (perspective-correct) - v->texcoord[0] *= wRcp; - v->texcoord[1] *= wRcp; - - // Division of colors (perspective-correct) - v->color[0] *= wRcp; - v->color[1] *= wRcp; - v->color[2] *= wRcp; - v->color[3] *= wRcp; - - // Transformation to screen space - sw_project_ndc_to_screen(v->screen, v->homogeneous); - } - } -} - -#define DEFINE_TRIANGLE_RASTER_SCANLINE(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \ -static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start, \ - const sw_vertex_t *end, float dUdy, float dVdy) \ -{ \ - /* Gets the start and end coordinates */ \ - int xStart = (int)start->screen[0]; \ - int xEnd = (int)end->screen[0]; \ - \ - /* Avoid empty lines */ \ - if (xStart == xEnd) return; \ - \ - /* Compute the subpixel distance to traverse before the first pixel */ \ - float xSubstep = 1.0f - sw_fract(start->screen[0]); \ - \ - /* Compute the inverse horizontal distance along the X axis */ \ - float dxRcp = 1.0f/(end->screen[0] - start->screen[0]); \ - \ - /* Compute the interpolation steps along the X axis */ \ - float dZdx = (end->homogeneous[2] - start->homogeneous[2])*dxRcp; \ - float dWdx = (end->homogeneous[3] - start->homogeneous[3])*dxRcp; \ - \ - float dCdx[4] = { \ - (end->color[0] - start->color[0])*dxRcp, \ - (end->color[1] - start->color[1])*dxRcp, \ - (end->color[2] - start->color[2])*dxRcp, \ - (end->color[3] - start->color[3])*dxRcp \ - }; \ - \ - float dUdx = 0.0f; \ - float dVdx = 0.0f; \ - if (ENABLE_TEXTURE) { \ - dUdx = (end->texcoord[0] - start->texcoord[0])*dxRcp; \ - dVdx = (end->texcoord[1] - start->texcoord[1])*dxRcp; \ - } \ - \ - /* Initializing the interpolation starting values */ \ - float z = start->homogeneous[2] + dZdx*xSubstep; \ - float w = start->homogeneous[3] + dWdx*xSubstep; \ - \ - float color[4] = { \ - start->color[0] + dCdx[0]*xSubstep, \ - start->color[1] + dCdx[1]*xSubstep, \ - start->color[2] + dCdx[2]*xSubstep, \ - start->color[3] + dCdx[3]*xSubstep \ - }; \ - \ - float u = 0.0f; \ - float v = 0.0f; \ - if (ENABLE_TEXTURE) { \ - u = start->texcoord[0] + dUdx*xSubstep; \ - v = start->texcoord[1] + dVdx*xSubstep; \ - } \ - \ - /* Pre-calculate the starting pointers for the framebuffer row */ \ - int y = (int)start->screen[1]; \ - sw_pixel_t *ptr = RLSW.framebuffer.pixels + y*RLSW.framebuffer.width + xStart; \ - \ - /* Scanline rasterization */ \ - for (int x = xStart; x < xEnd; x++) \ - { \ - float wRcp = 1.0f/w; \ - float srcColor[4] = { \ - color[0]*wRcp, \ - color[1]*wRcp, \ - color[2]*wRcp, \ - color[3]*wRcp \ - }; \ - \ - if (ENABLE_DEPTH_TEST) \ - { \ - /* TODO: Implement different depth funcs? */ \ - float depth = sw_framebuffer_read_depth(ptr); \ - if (z > depth) goto discard; \ - } \ - \ - /* TODO: Implement depth mask */ \ - sw_framebuffer_write_depth(ptr, z); \ - \ - if (ENABLE_TEXTURE) \ - { \ - float texColor[4]; \ - float s = u*wRcp; \ - float t = v*wRcp; \ - sw_texture_sample(texColor, tex, s, t, dUdx, dUdy, dVdx, dVdy); \ - srcColor[0] *= texColor[0]; \ - srcColor[1] *= texColor[1]; \ - srcColor[2] *= texColor[2]; \ - srcColor[3] *= texColor[3]; \ - } \ - \ - if (ENABLE_COLOR_BLEND) \ - { \ - float dstColor[4]; \ - sw_framebuffer_read_color(dstColor, ptr); \ - sw_blend_colors(dstColor, srcColor); \ - sw_framebuffer_write_color(ptr, dstColor); \ - } \ - else \ - { \ - sw_framebuffer_write_color(ptr, srcColor); \ - } \ - \ - /* Increment the interpolation parameter, UVs, and pointers */ \ - discard: \ - z += dZdx; \ - w += dWdx; \ - color[0] += dCdx[0]; \ - color[1] += dCdx[1]; \ - color[2] += dCdx[2]; \ - color[3] += dCdx[3]; \ - if (ENABLE_TEXTURE) \ - { \ - u += dUdx; \ - v += dVdx; \ - } \ - ++ptr; \ - } \ -} - -#define DEFINE_TRIANGLE_RASTER(FUNC_NAME, FUNC_SCANLINE, ENABLE_TEXTURE) \ -static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1, \ - const sw_vertex_t *v2, const sw_texture_t *tex) \ -{ \ - /* Swap vertices by increasing y */ \ - if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } \ - if (v1->screen[1] > v2->screen[1]) { const sw_vertex_t *tmp = v1; v1 = v2; v2 = tmp; } \ - if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } \ - \ - /* Extracting coordinates from the sorted vertices */ \ - float x0 = v0->screen[0], y0 = v0->screen[1]; \ - float x1 = v1->screen[0], y1 = v1->screen[1]; \ - float x2 = v2->screen[0], y2 = v2->screen[1]; \ - \ - /* Compute height differences */ \ - float h02 = y2 - y0; \ - float h01 = y1 - y0; \ - float h12 = y2 - y1; \ - \ - if (h02 < 1e-6f) return; \ - \ - /* Precompute the inverse values without additional checks */ \ - float h02Rcp = 1.0f/h02; \ - float h01Rcp = (h01 > 1e-6f)? 1.0f/h01 : 0.0f; \ - float h12Rcp = (h12 > 1e-6f)? 1.0f/h12 : 0.0f; \ - \ - /* Pre-calculation of slopes */ \ - float dXdy02 = (x2 - x0)*h02Rcp; \ - float dXdy01 = (x1 - x0)*h01Rcp; \ - float dXdy12 = (x2 - x1)*h12Rcp; \ - \ - /* Y subpixel correction */ \ - float y0Substep = 1.0f - sw_fract(y0); \ - float y1Substep = 1.0f - sw_fract(y1); \ - \ - /* Y bounds (vertical clipping) */ \ - int yTop = (int)y0; \ - int yMid = (int)y1; \ - int yBot = (int)y2; \ - \ - /* Compute gradients for each side of the triangle */ \ - sw_vertex_t dVXdy02, dVXdy01, dVXdy12; \ - sw_get_vertex_grad_PTCH(&dVXdy02, v0, v2, h02Rcp); \ - sw_get_vertex_grad_PTCH(&dVXdy01, v0, v1, h01Rcp); \ - sw_get_vertex_grad_PTCH(&dVXdy12, v1, v2, h12Rcp); \ - \ - /* Get a copy of vertices for interpolation and apply substep correction */ \ - sw_vertex_t vLeft = *v0, vRight = *v0; \ - sw_add_vertex_grad_scaled_PTCH(&vLeft, &dVXdy02, y0Substep); \ - sw_add_vertex_grad_scaled_PTCH(&vRight, &dVXdy01, y0Substep); \ - \ - vLeft.screen[0] += dXdy02*y0Substep; \ - vRight.screen[0] += dXdy01*y0Substep; \ - \ - /* Scanline for the upper part of the triangle */ \ - for (int y = yTop; y < yMid; y++) \ - { \ - vLeft.screen[1] = vRight.screen[1] = y; \ - \ - if (vLeft.screen[0] < vRight.screen[0]) FUNC_SCANLINE(tex, &vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \ - else FUNC_SCANLINE(tex, &vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \ - \ - sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02); \ - vLeft.screen[0] += dXdy02; \ - \ - sw_add_vertex_grad_PTCH(&vRight, &dVXdy01); \ - vRight.screen[0] += dXdy01; \ - } \ - \ - /* Get a copy of next right for interpolation and apply substep correction */ \ - vRight = *v1; \ - sw_add_vertex_grad_scaled_PTCH(&vRight, &dVXdy12, y1Substep); \ - vRight.screen[0] += dXdy12*y1Substep; \ - \ - /* Scanline for the lower part of the triangle */ \ - for (int y = yMid; y < yBot; y++) \ - { \ - vLeft.screen[1] = vRight.screen[1] = y; \ - \ - if (vLeft.screen[0] < vRight.screen[0]) FUNC_SCANLINE(tex, &vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \ - else FUNC_SCANLINE(tex, &vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \ - \ - sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02); \ - vLeft.screen[0] += dXdy02; \ - \ - sw_add_vertex_grad_PTCH(&vRight, &dVXdy12); \ - vRight.screen[0] += dXdy12; \ - } \ -} - -DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline, 0, 0, 0) -DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_TEX, 1, 0, 0) -DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_DEPTH, 0, 1, 0) -DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_BLEND, 0, 0, 1) -DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_TEX_DEPTH, 1, 1, 0) -DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_TEX_BLEND, 1, 0, 1) -DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_DEPTH_BLEND, 0, 1, 1) -DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_TEX_DEPTH_BLEND, 1, 1, 1) - -DEFINE_TRIANGLE_RASTER(sw_triangle_raster, sw_triangle_raster_scanline, false) -DEFINE_TRIANGLE_RASTER(sw_triangle_raster_TEX, sw_triangle_raster_scanline_TEX, true) -DEFINE_TRIANGLE_RASTER(sw_triangle_raster_DEPTH, sw_triangle_raster_scanline_DEPTH, false) -DEFINE_TRIANGLE_RASTER(sw_triangle_raster_BLEND, sw_triangle_raster_scanline_BLEND, false) -DEFINE_TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH, sw_triangle_raster_scanline_TEX_DEPTH, true) -DEFINE_TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND, sw_triangle_raster_scanline_TEX_BLEND, true) -DEFINE_TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND, sw_triangle_raster_scanline_DEPTH_BLEND, false) -DEFINE_TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND, sw_triangle_raster_scanline_TEX_DEPTH_BLEND, true) - -static inline void sw_triangle_render(void) -{ - if (RLSW.stateFlags & SW_STATE_CULL_FACE) - { - if (!sw_triangle_face_culling()) return; - } - - sw_triangle_clip_and_project(); - - if (RLSW.vertexCounter < 3) return; - - #define TRIANGLE_RASTER(RASTER_FUNC) \ - { \ - for (int i = 0; i < RLSW.vertexCounter - 2; i++) \ - { \ - RASTER_FUNC( \ - &RLSW.vertexBuffer[0], \ - &RLSW.vertexBuffer[i + 1], \ - &RLSW.vertexBuffer[i + 2], \ - &RLSW.loadedTextures[RLSW.currentTexture] \ - ); \ - } \ - } - - uint32_t state = RLSW.stateFlags; - if (RLSW.currentTexture == 0) state &= ~SW_STATE_TEXTURE_2D; - if ((RLSW.srcFactor == SW_ONE) && (RLSW.dstFactor == SW_ZERO)) state &= ~SW_STATE_BLEND; - - if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND) - else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND) - else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND) - else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH) - else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND) - else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH) - else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX) - else TRIANGLE_RASTER(sw_triangle_raster) - - #undef TRIANGLE_RASTER -} -//------------------------------------------------------------------------------------------- - -// Quad rendering logic -//------------------------------------------------------------------------------------------- -static inline bool sw_quad_face_culling(void) -{ - // NOTE: Face culling is done before clipping to avoid unnecessary computations - // To handle quads crossing the w=0 plane correctly, - // the winding order test is performed in homogeneous coordinates directly, - // before the perspective division (division by w) - // For a convex quad with vertices P0, P1, P2, P3 in sequential order, - // the winding order of the quad is the same as the winding order - // of the triangle P0 P1 P2. The homogeneous triangle is used on - // winding test on this first triangle - - // Preload homogeneous coordinates into local variables - const float *h0 = RLSW.vertexBuffer[0].homogeneous; - const float *h1 = RLSW.vertexBuffer[1].homogeneous; - const float *h2 = RLSW.vertexBuffer[2].homogeneous; - - // NOTE: h3 is not needed for this test - // const float *h3 = RLSW.vertexBuffer[3].homogeneous; - - // Compute a value proportional to the signed area of the triangle P0 P1 P2 - // in the projected 2D plane, calculated directly using homogeneous coordinates - // BEFORE division by w - // This is the determinant of the matrix formed by the (x, y, w) components - // of the vertices P0, P1, and P2. Its sign correctly indicates the winding order - // in homogeneous space and its relationship to the projected 2D winding order, - // even with negative w values - // The determinant formula used here is: - // h0.x*(h1.y*h2.w - h2.y*h1.w) + - // h1.x*(h2.y*h0.w - h0.y*h2.w) + - // h2.x*(h0.y*h1.w - h1.y*h0.w) - - const float hSgnArea = - h0[0]*(h1[1]*h2[3] - h2[1]*h1[3]) + - h1[0]*(h2[1]*h0[3] - h0[1]*h2[3]) + - h2[0]*(h0[1]*h1[3] - h1[1]*h0[3]); - - // Perform face culling based on the winding order determined by the sign - // of the homogeneous area/determinant of triangle P0 P1 P2 - // This test is robust for points with w > 0 or w < 0 within the triangle, - // correctly capturing the change in orientation when crossing the w=0 plane - - // A positive hSgnArea typically corresponds to a counter-clockwise - // winding in the projected space when all w > 0 - // A value of 0 for hSgnArea means P0, P1, P2 are collinear in (x, y, w) - // space, which corresponds to a degenerate triangle projection - // Such quads might also be degenerate or non-planar. They are typically - // not culled by this test (0 < 0 is false, 0 > 0 is false) - // and should be handled by the clipper if necessary - - return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0.0f) : (hSgnArea > 0.0f); // Cull if winding is "clockwise" : "counter-clockwise" -} - -static inline void sw_quad_clip_and_project(void) -{ - sw_vertex_t *polygon = RLSW.vertexBuffer; - int *vertexCounter = &RLSW.vertexCounter; - - if (sw_polygon_clip(polygon, vertexCounter)) - { - // Transformation to screen space and normalization - for (int i = 0; i < *vertexCounter; i++) - { - sw_vertex_t *v = &polygon[i]; - - // Calculation of the reciprocal of W for normalization - // as well as perspective-correct attributes - const float wRcp = 1.0f/v->homogeneous[3]; - v->homogeneous[3] = wRcp; - - // Division of XYZ coordinates by weight - v->homogeneous[0] *= wRcp; - v->homogeneous[1] *= wRcp; - v->homogeneous[2] *= wRcp; - - // Division of texture coordinates (perspective-correct) - v->texcoord[0] *= wRcp; - v->texcoord[1] *= wRcp; - - // Division of colors (perspective-correct) - v->color[0] *= wRcp; - v->color[1] *= wRcp; - v->color[2] *= wRcp; - v->color[3] *= wRcp; - - // Transformation to screen space - sw_project_ndc_to_screen(v->screen, v->homogeneous); - } - } -} - -static inline bool sw_quad_is_axis_aligned(void) -{ - // Reject quads with perspective projection - // The fast path assumes affine (non-perspective) quads, - // so it's required for all vertices to have homogeneous w = 1.0 - for (int i = 0; i < 4; i++) - { - if (RLSW.vertexBuffer[i].homogeneous[3] != 1.0f) return false; - } - - // Epsilon tolerance in screen space (pixels) - const float epsilon = 0.5f; - - // Fetch screen-space positions for the four quad vertices - const float *p0 = RLSW.vertexBuffer[0].screen; - const float *p1 = RLSW.vertexBuffer[1].screen; - const float *p2 = RLSW.vertexBuffer[2].screen; - const float *p3 = RLSW.vertexBuffer[3].screen; - - // Compute edge vectors between consecutive vertices - // These define the four sides of the quad in screen space - float dx01 = p1[0] - p0[0], dy01 = p1[1] - p0[1]; - float dx12 = p2[0] - p1[0], dy12 = p2[1] - p1[1]; - float dx23 = p3[0] - p2[0], dy23 = p3[1] - p2[1]; - float dx30 = p0[0] - p3[0], dy30 = p0[1] - p3[1]; - - // Each edge must be either horizontal or vertical within epsilon tolerance - // If any edge deviates significantly from either axis, the quad is not axis-aligned - if (!((fabsf(dy01) < epsilon) || (fabsf(dx01) < epsilon))) return false; - if (!((fabsf(dy12) < epsilon) || (fabsf(dx12) < epsilon))) return false; - if (!((fabsf(dy23) < epsilon) || (fabsf(dx23) < epsilon))) return false; - if (!((fabsf(dy30) < epsilon) || (fabsf(dx30) < epsilon))) return false; - - return true; -} - -static inline void sw_quad_sort_cw(const sw_vertex_t* *output) -{ - const sw_vertex_t *input = RLSW.vertexBuffer; - - // Calculate the centroid of the quad - float cx = (input[0].screen[0] + input[1].screen[0] + - input[2].screen[0] + input[3].screen[0])*0.25f; - float cy = (input[0].screen[1] + input[1].screen[1] + - input[2].screen[1] + input[3].screen[1])*0.25f; - - // Calculate the angle of each vertex relative to the center - // and assign them directly to their correct position - const sw_vertex_t *corners[4] = { 0 }; - - for (int i = 0; i < 4; i++) - { - float dx = input[i].screen[0] - cx; - float dy = input[i].screen[1] - cy; - - // Determine the quadrant (clockwise from top-left) - // top-left: dx < 0, dy < 0 - // top-right: dx >= 0, dy < 0 - // bottom-right: dx >= 0, dy >= 0 - // bottom-left: dx < 0, dy >= 0 - - int idx; - if (dy < 0) idx = (dx < 0)? 0 : 1; // Top row - else idx = (dx < 0)? 3 : 2; // Bottom row - - corners[idx] = &input[i]; - } - - output[0] = corners[0]; // top-left - output[1] = corners[1]; // top-right - output[2] = corners[2]; // bottom-right - output[3] = corners[3]; // bottom-left -} - -// TODO: REVIEW: Could a perfectly aligned quad, where one of the four points has a different depth, -// still appear perfectly aligned from a certain point of view? -// Because in that case, it's still needed to perform perspective division for textures and colors... -#define DEFINE_QUAD_RASTER_AXIS_ALIGNED(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \ -static inline void FUNC_NAME(void) \ -{ \ - const sw_vertex_t *sortedVerts[4]; \ - sw_quad_sort_cw(sortedVerts); \ - \ - const sw_vertex_t *v0 = sortedVerts[0]; \ - const sw_vertex_t *v1 = sortedVerts[1]; \ - const sw_vertex_t *v2 = sortedVerts[2]; \ - const sw_vertex_t *v3 = sortedVerts[3]; \ - \ - /* Screen bounds (axis-aligned) */ \ - int xMin = (int)v0->screen[0]; \ - int yMin = (int)v0->screen[1]; \ - int xMax = (int)v2->screen[0]; \ - int yMax = (int)v2->screen[1]; \ - \ - float w = v2->screen[0] - v0->screen[0]; \ - float h = v2->screen[1] - v0->screen[1]; \ - \ - if ((w == 0) || (h == 0)) return; \ - \ - float wRcp = (w > 0.0f)? 1.0f/w : 0.0f; \ - float hRcp = (h > 0.0f)? 1.0f/h : 0.0f; \ - \ - /* Subpixel corrections */ \ - float xSubstep = 1.0f - sw_fract(v0->screen[0]); \ - float ySubstep = 1.0f - sw_fract(v0->screen[1]); \ - \ - /* Calculation of vertex gradients in X and Y */ \ - float dUdx = 0.0f, dVdx = 0.0f; \ - float dUdy = 0.0f, dVdy = 0.0f; \ - if (ENABLE_TEXTURE) { \ - dUdx = (v1->texcoord[0] - v0->texcoord[0])*wRcp; \ - dVdx = (v1->texcoord[1] - v0->texcoord[1])*wRcp; \ - dUdy = (v3->texcoord[0] - v0->texcoord[0])*hRcp; \ - dVdy = (v3->texcoord[1] - v0->texcoord[1])*hRcp; \ - } \ - \ - float dCdx[4], dCdy[4]; \ - dCdx[0] = (v1->color[0] - v0->color[0])*wRcp; \ - dCdx[1] = (v1->color[1] - v0->color[1])*wRcp; \ - dCdx[2] = (v1->color[2] - v0->color[2])*wRcp; \ - dCdx[3] = (v1->color[3] - v0->color[3])*wRcp; \ - dCdy[0] = (v3->color[0] - v0->color[0])*hRcp; \ - dCdy[1] = (v3->color[1] - v0->color[1])*hRcp; \ - dCdy[2] = (v3->color[2] - v0->color[2])*hRcp; \ - dCdy[3] = (v3->color[3] - v0->color[3])*hRcp; \ - \ - float dZdx, dZdy; \ - dZdx = (v1->homogeneous[2] - v0->homogeneous[2])*wRcp; \ - dZdy = (v3->homogeneous[2] - v0->homogeneous[2])*hRcp; \ - \ - /* Start of quad rasterization */ \ - const sw_texture_t *tex; \ - if (ENABLE_TEXTURE) tex = &RLSW.loadedTextures[RLSW.currentTexture]; \ - \ - sw_pixel_t *pixels = RLSW.framebuffer.pixels; \ - int wDst = RLSW.framebuffer.width; \ - \ - float zScanline = v0->homogeneous[2] + dZdx*xSubstep + dZdy*ySubstep; \ - float uScanline = v0->texcoord[0] + dUdx*xSubstep + dUdy*ySubstep; \ - float vScanline = v0->texcoord[1] + dVdx*xSubstep + dVdy*ySubstep; \ - \ - float colorScanline[4] = { \ - v0->color[0] + dCdx[0]*xSubstep + dCdy[0]*ySubstep, \ - v0->color[1] + dCdx[1]*xSubstep + dCdy[1]*ySubstep, \ - v0->color[2] + dCdx[2]*xSubstep + dCdy[2]*ySubstep, \ - v0->color[3] + dCdx[3]*xSubstep + dCdy[3]*ySubstep \ - }; \ - \ - for (int y = yMin; y < yMax; y++) \ - { \ - sw_pixel_t *ptr = pixels + y*wDst + xMin; \ - \ - float z = zScanline; \ - float u = uScanline; \ - float v = vScanline; \ - \ - float color[4] = { \ - colorScanline[0], \ - colorScanline[1], \ - colorScanline[2], \ - colorScanline[3] \ - }; \ - \ - /* Scanline rasterization */ \ - for (int x = xMin; x < xMax; x++) \ - { \ - /* Pixel color computation */ \ - float srcColor[4] = { \ - color[0], \ - color[1], \ - color[2], \ - color[3] \ - }; \ - \ - /* Test and write depth */ \ - if (ENABLE_DEPTH_TEST) \ - { \ - /* TODO: Implement different depth funcs? */ \ - float depth = sw_framebuffer_read_depth(ptr); \ - if (z > depth) goto discard; \ - } \ - \ - /* TODO: Implement depth mask */ \ - sw_framebuffer_write_depth(ptr, z); \ - \ - if (ENABLE_TEXTURE) \ - { \ - float texColor[4]; \ - sw_texture_sample(texColor, tex, u, v, dUdx, dUdy, dVdx, dVdy); \ - srcColor[0] *= texColor[0]; \ - srcColor[1] *= texColor[1]; \ - srcColor[2] *= texColor[2]; \ - srcColor[3] *= texColor[3]; \ - } \ - \ - if (ENABLE_COLOR_BLEND) \ - { \ - float dstColor[4]; \ - sw_framebuffer_read_color(dstColor, ptr); \ - sw_blend_colors(dstColor, srcColor); \ - sw_framebuffer_write_color(ptr, dstColor); \ - } \ - else sw_framebuffer_write_color(ptr, srcColor); \ - \ - discard: \ - z += dZdx; \ - color[0] += dCdx[0]; \ - color[1] += dCdx[1]; \ - color[2] += dCdx[2]; \ - color[3] += dCdx[3]; \ - if (ENABLE_TEXTURE) \ - { \ - u += dUdx; \ - v += dVdx; \ - } \ - ++ptr; \ - } \ - \ - zScanline += dZdy; \ - colorScanline[0] += dCdy[0]; \ - colorScanline[1] += dCdy[1]; \ - colorScanline[2] += dCdy[2]; \ - colorScanline[3] += dCdy[3]; \ - \ - if (ENABLE_TEXTURE) \ - { \ - uScanline += dUdy; \ - vScanline += dVdy; \ - } \ - } \ -} - -DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned, 0, 0, 0) -DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_TEX, 1, 0, 0) -DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_DEPTH, 0, 1, 0) -DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_BLEND, 0, 0, 1) -DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_TEX_DEPTH, 1, 1, 0) -DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_TEX_BLEND, 1, 0, 1) -DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_DEPTH_BLEND, 0, 1, 1) -DEFINE_QUAD_RASTER_AXIS_ALIGNED(sw_quad_raster_axis_aligned_TEX_DEPTH_BLEND, 1, 1, 1) - -static inline void sw_quad_render(void) -{ - if (RLSW.stateFlags & SW_STATE_CULL_FACE) - { - if (!sw_quad_face_culling()) return; - } - - sw_quad_clip_and_project(); - - if (RLSW.vertexCounter < 3) return; - - uint32_t state = RLSW.stateFlags; - if (RLSW.currentTexture == 0) state &= ~SW_STATE_TEXTURE_2D; - if ((RLSW.srcFactor == SW_ONE) && (RLSW.dstFactor == SW_ZERO)) state &= ~SW_STATE_BLEND; - - if ((RLSW.vertexCounter == 4) && sw_quad_is_axis_aligned()) - { - if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_DEPTH_BLEND(); - else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_DEPTH_BLEND(); - else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_BLEND(); - else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_TEX_DEPTH(); - else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) sw_quad_raster_axis_aligned_BLEND(); - else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_DEPTH(); - else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) sw_quad_raster_axis_aligned_TEX(); - else sw_quad_raster_axis_aligned(); - return; - } - - #define TRIANGLE_RASTER(RASTER_FUNC) \ - { \ - for (int i = 0; i < RLSW.vertexCounter - 2; i++) \ - { \ - RASTER_FUNC( \ - &RLSW.vertexBuffer[0], \ - &RLSW.vertexBuffer[i + 1], \ - &RLSW.vertexBuffer[i + 2], \ - &RLSW.loadedTextures[RLSW.currentTexture] \ - ); \ - } \ - } - - if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND) - else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND) - else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND) - else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH) - else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND) - else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH) - else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX) - else TRIANGLE_RASTER(sw_triangle_raster) - - #undef TRIANGLE_RASTER -} -//------------------------------------------------------------------------------------------- - -// Line rendering logic -//------------------------------------------------------------------------------------------- -static inline bool sw_line_clip_coord(float q, float p, float *t0, float *t1) -{ - if (fabsf(p) < SW_CLIP_EPSILON) - { - // Check if the line is entirely outside the window - if (q < -SW_CLIP_EPSILON) return 0; // Completely outside - return 1; // Completely inside or on the edges - } - - const float r = q/p; - - if (p < 0) - { - if (r > *t1) return 0; - if (r > *t0) *t0 = r; - } - else - { - if (r < *t0) return 0; - if (r < *t1) *t1 = r; - } - - return 1; -} - -static inline bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1) -{ - float t0 = 0.0f, t1 = 1.0f; - float dH[4], dC[4]; - - for (int i = 0; i < 4; i++) - { - dH[i] = v1->homogeneous[i] - v0->homogeneous[i]; - dC[i] = v1->color[i] - v0->color[i]; - } - - // Clipping Liang-Barsky - if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[0], -dH[3] + dH[0], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[0], -dH[3] - dH[0], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[1], -dH[3] + dH[1], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[1], -dH[3] - dH[1], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[2], -dH[3] + dH[2], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[2], -dH[3] - dH[2], &t0, &t1)) return false; - - // Clipping Scissor - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) - { - if (!sw_line_clip_coord(v0->homogeneous[0] - RLSW.scClipMin[0]*v0->homogeneous[3], RLSW.scClipMin[0]*dH[3] - dH[0], &t0, &t1)) return false; - if (!sw_line_clip_coord(RLSW.scClipMax[0]*v0->homogeneous[3] - v0->homogeneous[0], dH[0] - RLSW.scClipMax[0]*dH[3], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->homogeneous[1] - RLSW.scClipMin[1]*v0->homogeneous[3], RLSW.scClipMin[1]*dH[3] - dH[1], &t0, &t1)) return false; - if (!sw_line_clip_coord(RLSW.scClipMax[1]*v0->homogeneous[3] - v0->homogeneous[1], dH[1] - RLSW.scClipMax[1]*dH[3], &t0, &t1)) return false; - } - - // Interpolation of new coordinates - if (t1 < 1.0f) - { - for (int i = 0; i < 4; i++) - { - v1->homogeneous[i] = v0->homogeneous[i] + t1*dH[i]; - v1->color[i] = v0->color[i] + t1*dC[i]; - } - } - - if (t0 > 0.0f) - { - for (int i = 0; i < 4; i++) - { - v0->homogeneous[i] += t0*dH[i]; - v0->color[i] += t0*dC[i]; - } - } - - return true; -} - -static inline bool sw_line_clip_and_project(sw_vertex_t *v0, sw_vertex_t *v1) -{ - if (!sw_line_clip(v0, v1)) return false; - - // Convert homogeneous coordinates to NDC - v0->homogeneous[3] = 1.0f/v0->homogeneous[3]; - v1->homogeneous[3] = 1.0f/v1->homogeneous[3]; - for (int i = 0; i < 3; i++) - { - v0->homogeneous[i] *= v0->homogeneous[3]; - v1->homogeneous[i] *= v1->homogeneous[3]; - } - - // Convert NDC coordinates to screen space - sw_project_ndc_to_screen(v0->screen, v0->homogeneous); - sw_project_ndc_to_screen(v1->screen, v1->homogeneous); - - return true; -} - -#define DEFINE_LINE_RASTER(FUNC_NAME, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \ -static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \ -{ \ - float x0 = v0->screen[0]; \ - float y0 = v0->screen[1]; \ - float x1 = v1->screen[0]; \ - float y1 = v1->screen[1]; \ - \ - float dx = x1 - x0; \ - float dy = y1 - y0; \ - \ - /* Compute dominant axis and subpixel offset */ \ - float steps, substep; \ - if (fabsf(dx) > fabsf(dy)) \ - { \ - steps = fabsf(dx); \ - if (steps < 1.0f) return; \ - substep = (dx >= 0.0f)? (1.0f - sw_fract(x0)) : sw_fract(x0); \ - } \ - else \ - { \ - steps = fabsf(dy); \ - if (steps < 1.0f) return; \ - substep = (dy >= 0.0f)? (1.0f - sw_fract(y0)) : sw_fract(y0); \ - } \ - \ - /* Compute per pixel increments */ \ - float xInc = dx/steps; \ - float yInc = dy/steps; \ - float stepRcp = 1.0f/steps; \ - \ - float zInc = (v1->homogeneous[2] - v0->homogeneous[2])*stepRcp; \ - float rInc = (v1->color[0] - v0->color[0])*stepRcp; \ - float gInc = (v1->color[1] - v0->color[1])*stepRcp; \ - float bInc = (v1->color[2] - v0->color[2])*stepRcp; \ - float aInc = (v1->color[3] - v0->color[3])*stepRcp; \ - \ - /* Initializing the interpolation starting values */ \ - float x = x0 + xInc*substep; \ - float y = y0 + yInc*substep; \ - float z = v0->homogeneous[2] + zInc*substep; \ - float r = v0->color[0] + rInc*substep; \ - float g = v0->color[1] + gInc*substep; \ - float b = v0->color[2] + bInc*substep; \ - float a = v0->color[3] + aInc*substep; \ - \ - const int fbWidth = RLSW.framebuffer.width; \ - sw_pixel_t *pixels = RLSW.framebuffer.pixels; \ - \ - int numPixels = (int)(steps - substep) + 1; \ - \ - for (int i = 0; i < numPixels; i++) \ - { \ - /* TODO: REVIEW: May require reviewing projection details */ \ - int px = (int)(x - 0.5f); \ - int py = (int)(y - 0.5f); \ - \ - sw_pixel_t *ptr = pixels + py*fbWidth + px; \ - \ - if (ENABLE_DEPTH_TEST) \ - { \ - float depth = sw_framebuffer_read_depth(ptr); \ - if (z > depth) goto discard; \ - } \ - \ - sw_framebuffer_write_depth(ptr, z); \ - \ - float color[4] = {r, g, b, a}; \ - \ - if (ENABLE_COLOR_BLEND) \ - { \ - float dstColor[4]; \ - sw_framebuffer_read_color(dstColor, ptr); \ - sw_blend_colors(dstColor, color); \ - sw_framebuffer_write_color(ptr, dstColor); \ - } \ - else sw_framebuffer_write_color(ptr, color); \ - \ - discard: \ - x += xInc; y += yInc; z += zInc; \ - r += rInc; g += gInc; b += bInc; a += aInc; \ - } \ -} - -#define DEFINE_LINE_THICK_RASTER(FUNC_NAME, RASTER_FUNC) \ -void FUNC_NAME(const sw_vertex_t *v1, const sw_vertex_t *v2) \ -{ \ - sw_vertex_t tv1, tv2; \ - \ - int x1 = (int)v1->screen[0]; \ - int y1 = (int)v1->screen[1]; \ - int x2 = (int)v2->screen[0]; \ - int y2 = (int)v2->screen[1]; \ - \ - int dx = x2 - x1; \ - int dy = y2 - y1; \ - \ - RASTER_FUNC(v1, v2); \ - \ - if ((dx != 0) && (abs(dy/dx) < 1)) \ - { \ - int wy = (int)((RLSW.lineWidth - 1.0f)*abs(dx)/sqrtf(dx*dx + dy*dy)); \ - wy >>= 1; \ - for (int i = 1; i <= wy; i++) \ - { \ - tv1 = *v1, tv2 = *v2; \ - tv1.screen[1] -= i; \ - tv2.screen[1] -= i; \ - RASTER_FUNC(&tv1, &tv2); \ - tv1 = *v1, tv2 = *v2; \ - tv1.screen[1] += i; \ - tv2.screen[1] += i; \ - RASTER_FUNC(&tv1, &tv2); \ - } \ - } \ - else if (dy != 0) \ - { \ - int wx = (int)((RLSW.lineWidth - 1.0f)*abs(dy)/sqrtf(dx*dx + dy*dy)); \ - wx >>= 1; \ - for (int i = 1; i <= wx; i++) \ - { \ - tv1 = *v1, tv2 = *v2; \ - tv1.screen[0] -= i; \ - tv2.screen[0] -= i; \ - RASTER_FUNC(&tv1, &tv2); \ - tv1 = *v1, tv2 = *v2; \ - tv1.screen[0] += i; \ - tv2.screen[0] += i; \ - RASTER_FUNC(&tv1, &tv2); \ - } \ - } \ -} - -DEFINE_LINE_RASTER(sw_line_raster, 0, 0) -DEFINE_LINE_RASTER(sw_line_raster_DEPTH, 1, 0) -DEFINE_LINE_RASTER(sw_line_raster_BLEND, 0, 1) -DEFINE_LINE_RASTER(sw_line_raster_DEPTH_BLEND, 1, 1) - -DEFINE_LINE_THICK_RASTER(sw_line_thick_raster, sw_line_raster) -DEFINE_LINE_THICK_RASTER(sw_line_thick_raster_DEPTH, sw_line_raster_DEPTH) -DEFINE_LINE_THICK_RASTER(sw_line_thick_raster_BLEND, sw_line_raster_BLEND) -DEFINE_LINE_THICK_RASTER(sw_line_thick_raster_DEPTH_BLEND, sw_line_raster_DEPTH_BLEND) - -static inline void sw_line_render(sw_vertex_t *vertices) -{ - if (!sw_line_clip_and_project(&vertices[0], &vertices[1])) return; - - if (RLSW.lineWidth >= 2.0f) - { - if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_line_thick_raster_DEPTH_BLEND(&vertices[0], &vertices[1]); - else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_line_thick_raster_BLEND(&vertices[0], &vertices[1]); - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_line_thick_raster_DEPTH(&vertices[0], &vertices[1]); - else sw_line_thick_raster(&vertices[0], &vertices[1]); - } - else - { - if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_line_raster_DEPTH_BLEND(&vertices[0], &vertices[1]); - else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_line_raster_BLEND(&vertices[0], &vertices[1]); - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_line_raster_DEPTH(&vertices[0], &vertices[1]); - else sw_line_raster(&vertices[0], &vertices[1]); - } -} -//------------------------------------------------------------------------------------------- - -// Point rendering logic -//------------------------------------------------------------------------------------------- -static inline bool sw_point_clip_and_project(sw_vertex_t *v) -{ - if (v->homogeneous[3] != 1.0f) - { - for (int_fast8_t i = 0; i < 3; i++) - { - if ((v->homogeneous[i] < -v->homogeneous[3]) || (v->homogeneous[i] > v->homogeneous[3])) return false; - } - - v->homogeneous[3] = 1.0f/v->homogeneous[3]; - v->homogeneous[0] *= v->homogeneous[3]; - v->homogeneous[1] *= v->homogeneous[3]; - v->homogeneous[2] *= v->homogeneous[3]; - } - - sw_project_ndc_to_screen(v->screen, v->homogeneous); - - const int *min = NULL, *max = NULL; - - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) - { - min = RLSW.scMin; - max = RLSW.scMax; - } - else - { - min = RLSW.vpMin; - max = RLSW.vpMax; - } - - bool insideX = (v->screen[0] - RLSW.pointRadius < max[0]) && (v->screen[0] + RLSW.pointRadius > min[0]); - bool insideY = (v->screen[1] - RLSW.pointRadius < max[1]) && (v->screen[1] + RLSW.pointRadius > min[1]); - - return (insideX && insideY); -} - -#define DEFINE_POINT_RASTER(FUNC_NAME, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND, CHECK_BOUNDS) \ -static inline void FUNC_NAME(int x, int y, float z, const float color[4]) \ -{ \ - if (CHECK_BOUNDS == 1) \ - { \ - if ((x < RLSW.vpMin[0]) || (x >= RLSW.vpMax[0])) return; \ - if ((y < RLSW.vpMin[1]) || (y >= RLSW.vpMax[1])) return; \ - } \ - else if (CHECK_BOUNDS == SW_SCISSOR_TEST) \ - { \ - if ((x < RLSW.scMin[0]) || (x >= RLSW.scMax[0])) return; \ - if ((y < RLSW.scMin[1]) || (y >= RLSW.scMax[1])) return; \ - } \ - \ - int offset = y*RLSW.framebuffer.width + x; \ - sw_pixel_t *ptr = RLSW.framebuffer.pixels + offset; \ - \ - if (ENABLE_DEPTH_TEST) \ - { \ - float depth = sw_framebuffer_read_depth(ptr); \ - if (z > depth) return; \ - } \ - \ - sw_framebuffer_write_depth(ptr, z); \ - \ - if (ENABLE_COLOR_BLEND) \ - { \ - float dstColor[4]; \ - sw_framebuffer_read_color(dstColor, ptr); \ - sw_blend_colors(dstColor, color); \ - sw_framebuffer_write_color(ptr, dstColor); \ - } \ - else sw_framebuffer_write_color(ptr, color); \ -} - -#define DEFINE_POINT_THICK_RASTER(FUNC_NAME, RASTER_FUNC) \ -static inline void FUNC_NAME(sw_vertex_t *v) \ -{ \ - int cx = v->screen[0]; \ - int cy = v->screen[1]; \ - float cz = v->homogeneous[2]; \ - int radius = RLSW.pointRadius; \ - const float *color = v->color; \ - \ - int x = 0; \ - int y = radius; \ - int d = 3 - 2*radius; \ - \ - while (x <= y) \ - { \ - for (int i = -x; i <= x; i++) \ - { \ - RASTER_FUNC(cx + i, cy + y, cz, color); \ - RASTER_FUNC(cx + i, cy - y, cz, color); \ - } \ - for (int i = -y; i <= y; i++) \ - { \ - RASTER_FUNC(cx + i, cy + x, cz, color); \ - RASTER_FUNC(cx + i, cy - x, cz, color); \ - } \ - if (d > 0) \ - { \ - y--; \ - d = d + 4*(x - y) + 10; \ - } \ - else d = d + 4*x + 6; \ - x++; \ - } \ -} - -DEFINE_POINT_RASTER(sw_point_raster, 0, 0, 0) -DEFINE_POINT_RASTER(sw_point_raster_DEPTH, 1, 0, 0) -DEFINE_POINT_RASTER(sw_point_raster_BLEND, 0, 1, 0) -DEFINE_POINT_RASTER(sw_point_raster_DEPTH_BLEND, 1, 1, 0) - -DEFINE_POINT_RASTER(sw_point_raster_CHECK, 0, 0, 1) -DEFINE_POINT_RASTER(sw_point_raster_DEPTH_CHECK, 1, 0, 1) -DEFINE_POINT_RASTER(sw_point_raster_BLEND_CHECK, 0, 1, 1) -DEFINE_POINT_RASTER(sw_point_raster_DEPTH_BLEND_CHECK, 1, 1, 1) - -DEFINE_POINT_RASTER(sw_point_raster_CHECK_SCISSOR, 0, 0, SW_SCISSOR_TEST) -DEFINE_POINT_RASTER(sw_point_raster_DEPTH_CHECK_SCISSOR, 1, 0, SW_SCISSOR_TEST) -DEFINE_POINT_RASTER(sw_point_raster_BLEND_CHECK_SCISSOR, 0, 1, SW_SCISSOR_TEST) -DEFINE_POINT_RASTER(sw_point_raster_DEPTH_BLEND_CHECK_SCISSOR, 1, 1, SW_SCISSOR_TEST) - -DEFINE_POINT_THICK_RASTER(sw_point_thick_raster, sw_point_raster_CHECK) -DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_DEPTH, sw_point_raster_DEPTH_CHECK) -DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_BLEND, sw_point_raster_BLEND_CHECK) -DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_DEPTH_BLEND, sw_point_raster_DEPTH_BLEND_CHECK) - -DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_SCISSOR, sw_point_raster_CHECK_SCISSOR) -DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_DEPTH_SCISSOR, sw_point_raster_DEPTH_CHECK_SCISSOR) -DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_BLEND_SCISSOR, sw_point_raster_BLEND_CHECK_SCISSOR) -DEFINE_POINT_THICK_RASTER(sw_point_thick_raster_DEPTH_BLEND_SCISSOR, sw_point_raster_DEPTH_BLEND_CHECK_SCISSOR) - -static inline void sw_point_render(sw_vertex_t *v) -{ - if (!sw_point_clip_and_project(v)) return; - - if (RLSW.pointRadius >= 1.0f) - { - if (SW_STATE_CHECK(SW_STATE_SCISSOR_TEST)) - { - if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_point_thick_raster_DEPTH_BLEND_SCISSOR(v); - else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_point_thick_raster_BLEND_SCISSOR(v); - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_point_thick_raster_DEPTH_SCISSOR(v); - else sw_point_thick_raster_SCISSOR(v); - } - else - { - if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_point_thick_raster_DEPTH_BLEND(v); - else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_point_thick_raster_BLEND(v); - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_point_thick_raster_DEPTH(v); - else sw_point_thick_raster(v); - } - } - else - { - if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_point_raster_DEPTH_BLEND(v->screen[0], v->screen[1], v->homogeneous[2], v->color); - else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_point_raster_BLEND(v->screen[0], v->screen[1], v->homogeneous[2], v->color); - else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_point_raster_DEPTH(v->screen[0], v->screen[1], v->homogeneous[2], v->color); - else sw_point_raster(v->screen[0], v->screen[1], v->homogeneous[2], v->color); - } -} -//------------------------------------------------------------------------------------------- - -// Polygon modes rendering logic -//------------------------------------------------------------------------------------------- -static inline void sw_poly_point_render(void) -{ - for (int i = 0; i < RLSW.vertexCounter; i++) sw_point_render(&RLSW.vertexBuffer[i]); -} - -static inline void sw_poly_line_render(void) -{ - const sw_vertex_t *vertices = RLSW.vertexBuffer; - int cm1 = RLSW.vertexCounter - 1; - - for (int i = 0; i < cm1; i++) - { - sw_vertex_t verts[2] = { vertices[i], vertices[i + 1] }; - sw_line_render(verts); - } - - sw_vertex_t verts[2] = { vertices[cm1], vertices[0] }; - sw_line_render(verts); -} - -static inline void sw_poly_fill_render(void) -{ - switch (RLSW.drawMode) - { - case SW_POINTS: sw_point_render(&RLSW.vertexBuffer[0]); break; - case SW_LINES: sw_line_render(RLSW.vertexBuffer); break; - case SW_TRIANGLES: sw_triangle_render(); break; - case SW_QUADS: sw_quad_render(); break; - } -} -//------------------------------------------------------------------------------------------- - -// Immediate rendering logic -//------------------------------------------------------------------------------------------- -void sw_immediate_push_vertex(const float position[4], const float color[4], const float texcoord[2]) -{ - // Copy the attributes in the current vertex - sw_vertex_t *vertex = &RLSW.vertexBuffer[RLSW.vertexCounter++]; - for (int i = 0; i < 4; i++) - { - vertex->position[i] = position[i]; - if (i < 2) vertex->texcoord[i] = texcoord[i]; - vertex->color[i] = color[i]; - } - - // Calculate homogeneous coordinates - const float *m = RLSW.matMVP, *v = vertex->position; - vertex->homogeneous[0] = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3]; - vertex->homogeneous[1] = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3]; - vertex->homogeneous[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3]; - vertex->homogeneous[3] = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3]; - - // Immediate rendering of the primitive if the required number is reached - if (RLSW.vertexCounter == RLSW.reqVertices) - { - switch (RLSW.polyMode) - { - case SW_FILL: sw_poly_fill_render(); break; - case SW_LINE: sw_poly_line_render(); break; - case SW_POINT: sw_poly_point_render(); break; - default: break; - } - - RLSW.vertexCounter = 0; - } -} - //------------------------------------------------------------------------------------------- // Validity check helper functions //------------------------------------------------------------------------------------------- -static inline bool sw_is_texture_valid(uint32_t id) +static inline bool sw_is_texture_valid(sw_handle_t id) { - bool valid = true; + return sw_pool_valid(&RLSW.texturePool, id); +} - if (id == 0) valid = false; - else if (id >= SW_MAX_TEXTURES) valid = false; - else if (RLSW.loadedTextures[id].pixels == NULL) valid = false; - - return valid; +static inline bool sw_is_texture_complete(sw_texture_t* tex) +{ + return (tex != NULL) && (tex->pixels != NULL); } static inline bool sw_is_texture_filter_valid(int filter) @@ -3539,6 +1535,2381 @@ static inline bool sw_is_blend_dst_factor_valid(int blend) return result; } + +static inline bool sw_is_ready_to_render(void) +{ + return (swCheckFramebufferStatus() == SW_FRAMEBUFFER_COMPLETE); +} +//------------------------------------------------------------------------------------------- + +// Pixel management functions +//------------------------------------------------------------------------------------------- +static inline int sw_pixel_get_format(SWformat format, SWtype type) +{ + int channels = 0; + int bitsPerChannel = 8; // Default: 8 bits per channel + + // Handle case where format is a depth component + if (format == SW_DEPTH_COMPONENT) + { + switch (type) + { + case SW_UNSIGNED_BYTE: return SW_PIXELFORMAT_DEPTH_D8; + case SW_BYTE: return SW_PIXELFORMAT_DEPTH_D8; + case SW_UNSIGNED_SHORT: return SW_PIXELFORMAT_DEPTH_D16; + case SW_SHORT: return SW_PIXELFORMAT_DEPTH_D16; + case SW_UNSIGNED_INT: return SW_PIXELFORMAT_DEPTH_D32; + case SW_INT: return SW_PIXELFORMAT_DEPTH_D32; + case SW_FLOAT: return SW_PIXELFORMAT_DEPTH_D32; + default: return SW_PIXELFORMAT_UNKNOWN; + } + } + + // Handle case where the type is a packed color + switch (type) + { + case SW_UNSIGNED_BYTE_3_3_2: return SW_PIXELFORMAT_COLOR_R3G3B2; + case SW_UNSIGNED_SHORT_5_6_5: return SW_PIXELFORMAT_COLOR_R5G6B5; + case SW_UNSIGNED_SHORT_4_4_4_4: return SW_PIXELFORMAT_COLOR_R4G4B4A4; + case SW_UNSIGNED_SHORT_5_5_5_1: return SW_PIXELFORMAT_COLOR_R5G5B5A1; + default: break; + } + + // Determine the number of channels (format) + switch (format) + { + case SW_LUMINANCE: channels = 1; break; + case SW_LUMINANCE_ALPHA: channels = 2; break; + case SW_RGB: channels = 3; break; + case SW_RGBA: channels = 4; break; + default: return SW_PIXELFORMAT_UNKNOWN; + } + + // Determine the depth of each channel (type) + switch (type) + { + case SW_UNSIGNED_BYTE: bitsPerChannel = 8; break; + case SW_BYTE: bitsPerChannel = 8; break; + case SW_UNSIGNED_SHORT: bitsPerChannel = 16; break; + case SW_SHORT: bitsPerChannel = 16; break; + case SW_UNSIGNED_INT: bitsPerChannel = 32; break; + case SW_INT: bitsPerChannel = 32; break; + case SW_FLOAT: bitsPerChannel = 32; break; + default: return SW_PIXELFORMAT_UNKNOWN; + } + + // Map the format and type to the correct internal format + if (bitsPerChannel == 8) + { + if (channels == 1) return SW_PIXELFORMAT_COLOR_GRAYSCALE; + if (channels == 2) return SW_PIXELFORMAT_COLOR_GRAYALPHA; + if (channels == 3) return SW_PIXELFORMAT_COLOR_R8G8B8; + if (channels == 4) return SW_PIXELFORMAT_COLOR_R8G8B8A8; + } + else if (bitsPerChannel == 16) + { + if (channels == 1) return SW_PIXELFORMAT_COLOR_R16; + if (channels == 3) return SW_PIXELFORMAT_COLOR_R16G16B16; + if (channels == 4) return SW_PIXELFORMAT_COLOR_R16G16B16A16; + } + else if (bitsPerChannel == 32) + { + if (channels == 1) return SW_PIXELFORMAT_COLOR_R32; + if (channels == 3) return SW_PIXELFORMAT_COLOR_R32G32B32; + if (channels == 4) return SW_PIXELFORMAT_COLOR_R32G32B32A32; + } + + return SW_PIXELFORMAT_UNKNOWN; +} + +static inline void sw_pixel_get_color8_GRAYSCALE(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + uint8_t gray = ((const uint8_t *)pixels)[offset]; + color[0] = gray; + color[1] = gray; + color[2] = gray; + color[3] = 255; +} + +static inline void sw_pixel_get_color8_GRAYALPHA(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + const uint8_t *src = &((const uint8_t *)pixels)[offset*2]; + color[0] = src[0]; + color[1] = src[0]; + color[2] = src[0]; + color[3] = src[1]; +} + +static inline void sw_pixel_get_color8_R3G3B2(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + uint8_t pixel = ((const uint8_t *)pixels)[offset]; + color[0] = sw_expand_3to8((pixel >> 5) & 0x07); + color[1] = sw_expand_3to8((pixel >> 2) & 0x07); + color[2] = sw_expand_2to8( pixel & 0x03); + color[3] = 255; +} + +static inline void sw_pixel_get_color8_R5G6B5(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + uint16_t pixel = ((const uint16_t *)pixels)[offset]; + color[0] = sw_expand_5to8((pixel >> 11) & 0x1F); + color[1] = sw_expand_6to8((pixel >> 5) & 0x3F); + color[2] = sw_expand_5to8( pixel & 0x1F); + color[3] = 255; +} + +static inline void sw_pixel_get_color8_R8G8B8(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + const uint8_t *src = &((const uint8_t *)pixels)[offset*3]; + color[0] = src[0]; + color[1] = src[1]; + color[2] = src[2]; + color[3] = 255; +} + +static inline void sw_pixel_get_color8_R5G5B5A1(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + uint16_t pixel = ((const uint16_t *)pixels)[offset]; + color[0] = sw_expand_5to8((pixel >> 11) & 0x1F); + color[1] = sw_expand_5to8((pixel >> 6) & 0x1F); + color[2] = sw_expand_5to8((pixel >> 1) & 0x1F); + color[3] = sw_expand_1to8( pixel & 0x01); +} + +static inline void sw_pixel_get_color8_R4G4B4A4(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + uint16_t pixel = ((const uint16_t *)pixels)[offset]; + color[0] = sw_expand_4to8((pixel >> 12) & 0x0F); + color[1] = sw_expand_4to8((pixel >> 8) & 0x0F); + color[2] = sw_expand_4to8((pixel >> 4) & 0x0F); + color[3] = sw_expand_4to8( pixel & 0x0F); +} + +static inline void sw_pixel_get_color8_R8G8B8A8(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + const uint8_t *src = &((const uint8_t *)pixels)[offset*4]; + color[0] = src[0]; + color[1] = src[1]; + color[2] = src[2]; + color[3] = src[3]; +} + +static inline void sw_pixel_get_color8_R32(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + uint8_t gray = (uint8_t)(((const float *)pixels)[offset]*255.0f); + color[0] = gray; + color[1] = gray; + color[2] = gray; + color[3] = 255; +} + +static inline void sw_pixel_get_color8_R32G32B32(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + const float *src = &((const float *)pixels)[offset*3]; + color[0] = (uint8_t)(src[0]*255.0f); + color[1] = (uint8_t)(src[1]*255.0f); + color[2] = (uint8_t)(src[2]*255.0f); + color[3] = 255; +} + +static inline void sw_pixel_get_color8_R32G32B32A32(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + const float *src = &((const float *)pixels)[offset*4]; + color[0] = (uint8_t)(src[0]*255.0f); + color[1] = (uint8_t)(src[1]*255.0f); + color[2] = (uint8_t)(src[2]*255.0f); + color[3] = (uint8_t)(src[3]*255.0f); +} + +static inline void sw_pixel_get_color8_R16(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + uint8_t gray = (uint8_t)(sw_half_to_float(((const uint16_t *)pixels)[offset])*255.0f); + color[0] = gray; + color[1] = gray; + color[2] = gray; + color[3] = 255; +} + +static inline void sw_pixel_get_color8_R16G16B16(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + const uint16_t *src = &((const uint16_t *)pixels)[offset*3]; + color[0] = (uint8_t)(sw_half_to_float(src[0])*255.0f); + color[1] = (uint8_t)(sw_half_to_float(src[1])*255.0f); + color[2] = (uint8_t)(sw_half_to_float(src[2])*255.0f); + color[3] = 255; +} + +static inline void sw_pixel_get_color8_R16G16B16A16(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + const uint16_t *src = &((const uint16_t *)pixels)[offset*4]; + color[0] = (uint8_t)(sw_half_to_float(src[0])*255.0f); + color[1] = (uint8_t)(sw_half_to_float(src[1])*255.0f); + color[2] = (uint8_t)(sw_half_to_float(src[2])*255.0f); + color[3] = (uint8_t)(sw_half_to_float(src[3])*255.0f); +} + +static inline void sw_pixel_get_color8(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset, sw_pixelformat_t format) +{ + switch (format) + { + case SW_PIXELFORMAT_COLOR_GRAYSCALE: + sw_pixel_get_color8_GRAYSCALE(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_GRAYALPHA: + sw_pixel_get_color8_GRAYALPHA(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R3G3B2: + sw_pixel_get_color8_R3G3B2(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R5G6B5: + sw_pixel_get_color8_R5G6B5(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R8G8B8: + sw_pixel_get_color8_R8G8B8(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R5G5B5A1: + sw_pixel_get_color8_R5G5B5A1(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R4G4B4A4: + sw_pixel_get_color8_R4G4B4A4(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R8G8B8A8: + sw_pixel_get_color8_R8G8B8A8(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R32: + sw_pixel_get_color8_R32(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R32G32B32: + sw_pixel_get_color8_R32G32B32(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R32G32B32A32: + sw_pixel_get_color8_R32G32B32A32(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R16: + sw_pixel_get_color8_R16(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R16G16B16: + sw_pixel_get_color8_R16G16B16(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R16G16B16A16: + sw_pixel_get_color8_R16G16B16A16(color, pixels, offset); + break; + + case SW_PIXELFORMAT_UNKNOWN: + case SW_PIXELFORMAT_DEPTH_D8: + case SW_PIXELFORMAT_DEPTH_D16: + case SW_PIXELFORMAT_DEPTH_D32: + case SW_PIXELFORMAT_COUNT: + { + color[0] = 0.0f; + color[1] = 0.0f; + color[2] = 0.0f; + color[3] = 0.0f; + break; + } + } +} + +static inline void sw_pixel_set_color8_GRAYSCALE(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +{ + ((uint8_t *)pixels)[offset] = sw_luminance8(color); +} + +static inline void sw_pixel_set_color8_GRAYALPHA(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +{ + uint8_t *dst = &((uint8_t *)pixels)[offset*2]; + dst[0] = sw_luminance8(color); + dst[1] = color[3]; +} + +static inline void sw_pixel_set_color8_R3G3B2(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +{ + uint8_t pixel = (sw_compress_8to3(color[0]) << 5) + | (sw_compress_8to3(color[1]) << 2) + | sw_compress_8to2(color[2]); + ((uint8_t *)pixels)[offset] = pixel; +} + +static inline void sw_pixel_set_color8_R5G6B5(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +{ + uint16_t pixel = (sw_compress_8to5(color[0]) << 11) + | (sw_compress_8to6(color[1]) << 5) + | sw_compress_8to5(color[2]); + ((uint16_t *)pixels)[offset] = pixel; +} + +static inline void sw_pixel_set_color8_R8G8B8(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +{ + uint8_t *dst = &((uint8_t *)pixels)[offset*3]; + dst[0] = color[0]; + dst[1] = color[1]; + dst[2] = color[2]; +} + +static inline void sw_pixel_set_color8_R5G5B5A1(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +{ + uint16_t pixel = (sw_compress_8to5(color[0]) << 11) + | (sw_compress_8to5(color[1]) << 6) + | (sw_compress_8to5(color[2]) << 1) + | sw_compress_8to1(color[3]); + ((uint16_t *)pixels)[offset] = pixel; +} + +static inline void sw_pixel_set_color8_R4G4B4A4(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +{ + uint16_t pixel = (sw_compress_8to4(color[0]) << 12) + | (sw_compress_8to4(color[1]) << 8) + | (sw_compress_8to4(color[2]) << 4) + | sw_compress_8to4(color[3]); + ((uint16_t *)pixels)[offset] = pixel; +} + +static inline void sw_pixel_set_color8_R8G8B8A8(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +{ + uint8_t *dst = &((uint8_t *)pixels)[offset*4]; + dst[0] = color[0]; + dst[1] = color[1]; + dst[2] = color[2]; + dst[3] = color[3]; +} + +static inline void sw_pixel_set_color8_R32(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +{ + ((float *)pixels)[offset] = sw_luminance8(color)*SW_INV_255; +} + +static inline void sw_pixel_set_color8_R32G32B32(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +{ + float *dst = &((float *)pixels)[offset*3]; + dst[0] = color[0]*SW_INV_255; + dst[1] = color[1]*SW_INV_255; + dst[2] = color[2]*SW_INV_255; +} + +static inline void sw_pixel_set_color8_R32G32B32A32(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +{ + float *dst = &((float *)pixels)[offset*4]; + dst[0] = color[0]*SW_INV_255; + dst[1] = color[1]*SW_INV_255; + dst[2] = color[2]*SW_INV_255; + dst[3] = color[3]*SW_INV_255; +} + +static inline void sw_pixel_set_color8_R16(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +{ + ((uint16_t *)pixels)[offset] = sw_float_to_half(sw_luminance8(color)*SW_INV_255); +} + +static inline void sw_pixel_set_color8_R16G16B16(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +{ + uint16_t *dst = &((uint16_t *)pixels)[offset*3]; + dst[0] = sw_float_to_half(color[0]*SW_INV_255); + dst[1] = sw_float_to_half(color[1]*SW_INV_255); + dst[2] = sw_float_to_half(color[2]*SW_INV_255); +} + +static inline void sw_pixel_set_color8_R16G16B16A16(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +{ + uint16_t *dst = &((uint16_t *)pixels)[offset*4]; + dst[0] = sw_float_to_half(color[0]*SW_INV_255); + dst[1] = sw_float_to_half(color[1]*SW_INV_255); + dst[2] = sw_float_to_half(color[2]*SW_INV_255); + dst[3] = sw_float_to_half(color[3]*SW_INV_255); +} + +static inline void sw_pixel_set_color8(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset, sw_pixelformat_t format) +{ + switch (format) + { + case SW_PIXELFORMAT_COLOR_GRAYSCALE: + sw_pixel_set_color8_GRAYSCALE(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_GRAYALPHA: + sw_pixel_set_color8_GRAYALPHA(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R3G3B2: + sw_pixel_set_color8_R3G3B2(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R5G6B5: + sw_pixel_set_color8_R5G6B5(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R8G8B8: + sw_pixel_set_color8_R8G8B8(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R5G5B5A1: + sw_pixel_set_color8_R5G5B5A1(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R4G4B4A4: + sw_pixel_set_color8_R4G4B4A4(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R8G8B8A8: + sw_pixel_set_color8_R8G8B8A8(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R32: + sw_pixel_set_color8_R32(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R32G32B32: + sw_pixel_set_color8_R32G32B32(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R32G32B32A32: + sw_pixel_set_color8_R32G32B32A32(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R16: + sw_pixel_set_color8_R16(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R16G16B16: + sw_pixel_set_color8_R16G16B16(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R16G16B16A16: + sw_pixel_set_color8_R16G16B16A16(pixels, color, offset); + break; + + case SW_PIXELFORMAT_UNKNOWN: + case SW_PIXELFORMAT_DEPTH_D8: + case SW_PIXELFORMAT_DEPTH_D16: + case SW_PIXELFORMAT_DEPTH_D32: + case SW_PIXELFORMAT_COUNT: + break; + } +} + +static inline void sw_pixel_get_color_GRAYSCALE(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + float gray = ((const uint8_t *)pixels)[offset]*SW_INV_255; + color[0] = gray; + color[1] = gray; + color[2] = gray; + color[3] = 1.0f; +} + +static inline void sw_pixel_get_color_GRAYALPHA(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + const uint8_t *src = &((const uint8_t *)pixels)[offset*2]; + float gray = src[0]*SW_INV_255; + color[0] = gray; + color[1] = gray; + color[2] = gray; + color[3] = src[1]*SW_INV_255; +} + +static inline void sw_pixel_get_color_R3G3B2(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + uint8_t pixel = ((const uint8_t *)pixels)[offset]; + color[0] = sw_expand_3tof((pixel >> 5) & 0x07); + color[1] = sw_expand_3tof((pixel >> 2) & 0x07); + color[2] = sw_expand_2tof( pixel & 0x03); + color[3] = 1.0f; +} + +static inline void sw_pixel_get_color_R5G6B5(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + uint16_t pixel = ((const uint16_t *)pixels)[offset]; + color[0] = sw_expand_5tof((pixel >> 11) & 0x1F); + color[1] = sw_expand_6tof((pixel >> 5) & 0x3F); + color[2] = sw_expand_5tof( pixel & 0x1F); + color[3] = 1.0f; +} + +static inline void sw_pixel_get_color_R8G8B8(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + const uint8_t *src = &((const uint8_t *)pixels)[offset*3]; + color[0] = src[0]*SW_INV_255; + color[1] = src[1]*SW_INV_255; + color[2] = src[2]*SW_INV_255; + color[3] = 1.0f; +} + +static inline void sw_pixel_get_color_R5G5B5A1(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + uint16_t pixel = ((const uint16_t *)pixels)[offset]; + color[0] = sw_expand_5tof((pixel >> 11) & 0x1F); + color[1] = sw_expand_5tof((pixel >> 6) & 0x1F); + color[2] = sw_expand_5tof((pixel >> 1) & 0x1F); + color[3] = sw_expand_1tof( pixel & 0x01); +} + +static inline void sw_pixel_get_color_R4G4B4A4(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + uint16_t pixel = ((const uint16_t *)pixels)[offset]; + color[0] = sw_expand_4tof((pixel >> 12) & 0x0F); + color[1] = sw_expand_4tof((pixel >> 8) & 0x0F); + color[2] = sw_expand_4tof((pixel >> 4) & 0x0F); + color[3] = sw_expand_4tof( pixel & 0x0F); +} + +static inline void sw_pixel_get_color_R8G8B8A8(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + const uint8_t *src = &((const uint8_t *)pixels)[offset*4]; + +#if defined(SW_HAS_NEON) + uint32_t tmp = (uint32_t)src[0] | ((uint32_t)src[1] << 8) | ((uint32_t)src[2] << 16) | ((uint32_t)src[3] << 24); + uint8x8_t bytes = vreinterpret_u8_u32(vdup_n_u32(tmp)); + uint16x8_t words = vmovl_u8(bytes); + uint32x4_t dwords = vmovl_u16(vget_low_u16(words)); + float32x4_t fvals = vmulq_f32(vcvtq_f32_u32(dwords), vdupq_n_f32(SW_INV_255)); + vst1q_f32(color, fvals); + +#elif defined(SW_HAS_SSE41) + __m128i bytes = _mm_loadu_si32(src); + __m128 fvals = _mm_mul_ps(_mm_cvtepi32_ps(_mm_cvtepu8_epi32(bytes)), _mm_set1_ps(SW_INV_255)); + _mm_storeu_ps(color, fvals); + +#elif defined(SW_HAS_SSE2) + __m128i bytes = _mm_loadu_si32(src); + __m128i words = _mm_unpacklo_epi8(bytes, _mm_setzero_si128()); + __m128i dwords = _mm_unpacklo_epi16(words, _mm_setzero_si128()); + __m128 fvals = _mm_mul_ps(_mm_cvtepi32_ps(dwords), _mm_set1_ps(SW_INV_255)); + _mm_storeu_ps(color, fvals); + +#elif defined(SW_HAS_RVV) + // TODO: Sample code generated by AI, needs testing and review + size_t vl = __riscv_vsetvl_e8m1(4); // Set vector length for 8-bit input elements + vuint8m1_t vsrc_u8 = __riscv_vle8_v_u8m1(src, vl); // Load 4 unsigned 8-bit integers + vuint32m1_t vsrc_u32 = __riscv_vwcvt_xu_u_v_u32m1(vsrc_u8, vl); // Widen to 32-bit unsigned integers + vfloat32m1_t vsrc_f32 = __riscv_vfcvt_f_xu_v_f32m1(vsrc_u32, vl); // Convert to float32 + vfloat32m1_t vnorm = __riscv_vfmul_vf_f32m1(vsrc_f32, SW_INV_255, vl); // Multiply by 1/255.0 to normalize + __riscv_vse32_v_f32m1(color, vnorm, vl); // Store result + +#else + color[0] = (float)src[0]*SW_INV_255; + color[1] = (float)src[1]*SW_INV_255; + color[2] = (float)src[2]*SW_INV_255; + color[3] = (float)src[3]*SW_INV_255; +#endif +} + +static inline void sw_pixel_get_color_R32(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + float val = ((const float *)pixels)[offset]; + color[0] = val; + color[1] = val; + color[2] = val; + color[3] = 1.0f; +} + +static inline void sw_pixel_get_color_R32G32B32(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + const float *src = &((const float *)pixels)[offset*3]; + color[0] = src[0]; + color[1] = src[1]; + color[2] = src[2]; + color[3] = 1.0f; +} + +static inline void sw_pixel_get_color_R32G32B32A32(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + const float *src = &((const float *)pixels)[offset*4]; + color[0] = src[0]; + color[1] = src[1]; + color[2] = src[2]; + color[3] = src[3]; +} + +static inline void sw_pixel_get_color_R16(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + float val = sw_half_to_float(((const uint16_t *)pixels)[offset]); + color[0] = val; + color[1] = val; + color[2] = val; + color[3] = 1.0f; +} + +static inline void sw_pixel_get_color_R16G16B16(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + const uint16_t *src = &((const uint16_t *)pixels)[offset*3]; + color[0] = sw_half_to_float(src[0]); + color[1] = sw_half_to_float(src[1]); + color[2] = sw_half_to_float(src[2]); + color[3] = 1.0f; +} + +static inline void sw_pixel_get_color_R16G16B16A16(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +{ + const uint16_t *src = &((const uint16_t *)pixels)[offset*4]; + color[0] = sw_half_to_float(src[0]); + color[1] = sw_half_to_float(src[1]); + color[2] = sw_half_to_float(src[2]); + color[3] = sw_half_to_float(src[3]); +} + +static inline void sw_pixel_get_color(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset, sw_pixelformat_t format) +{ + switch (format) + { + case SW_PIXELFORMAT_COLOR_GRAYSCALE: + sw_pixel_get_color_GRAYSCALE(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_GRAYALPHA: + sw_pixel_get_color_GRAYALPHA(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R3G3B2: + sw_pixel_get_color_R3G3B2(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R5G6B5: + sw_pixel_get_color_R5G6B5(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R8G8B8: + sw_pixel_get_color_R8G8B8(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R5G5B5A1: + sw_pixel_get_color_R5G5B5A1(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R4G4B4A4: + sw_pixel_get_color_R4G4B4A4(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R8G8B8A8: + sw_pixel_get_color_R8G8B8A8(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R32: + sw_pixel_get_color_R32(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R32G32B32: + sw_pixel_get_color_R32G32B32(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R32G32B32A32: + sw_pixel_get_color_R32G32B32A32(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R16: + sw_pixel_get_color_R16(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R16G16B16: + sw_pixel_get_color_R16G16B16(color, pixels, offset); + break; + case SW_PIXELFORMAT_COLOR_R16G16B16A16: + sw_pixel_get_color_R16G16B16A16(color, pixels, offset); + break; + + case SW_PIXELFORMAT_UNKNOWN: + case SW_PIXELFORMAT_DEPTH_D8: + case SW_PIXELFORMAT_DEPTH_D16: + case SW_PIXELFORMAT_DEPTH_D32: + case SW_PIXELFORMAT_COUNT: + { + color[0] = 0.0f; + color[1] = 0.0f; + color[2] = 0.0f; + color[3] = 0.0f; + break; + } + } +} + +static inline void sw_pixel_set_color_GRAYSCALE(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +{ + ((uint8_t *)pixels)[offset] = (uint8_t)(sw_luminance(color)*255.0f); +} + +static inline void sw_pixel_set_color_GRAYALPHA(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +{ + uint8_t *dst = &((uint8_t *)pixels)[offset*2]; + dst[0] = (uint8_t)(sw_luminance(color)*255.0f); + dst[1] = (uint8_t)(color[3]*255.0f); +} + +static inline void sw_pixel_set_color_R3G3B2(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +{ + uint8_t pixel = (sw_compress_fto3(color[0]) << 5) + | (sw_compress_fto3(color[1]) << 2) + | sw_compress_fto2(color[2]); + ((uint8_t *)pixels)[offset] = pixel; +} + +static inline void sw_pixel_set_color_R5G6B5(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +{ + uint16_t pixel = (sw_compress_fto5(color[0]) << 11) + | (sw_compress_fto6(color[1]) << 5) + | sw_compress_fto5(color[2]); + ((uint16_t *)pixels)[offset] = pixel; +} + +static inline void sw_pixel_set_color_R8G8B8(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +{ + uint8_t *dst = &((uint8_t *)pixels)[offset*3]; + dst[0] = (uint8_t)(color[0]*255.0f); + dst[1] = (uint8_t)(color[1]*255.0f); + dst[2] = (uint8_t)(color[2]*255.0f); +} + +static inline void sw_pixel_set_color_R5G5B5A1(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +{ + uint16_t pixel = (sw_compress_fto5(color[0]) << 11) + | (sw_compress_fto5(color[1]) << 6) + | (sw_compress_fto5(color[2]) << 1) + | sw_compress_fto1(color[3]); + ((uint16_t *)pixels)[offset] = pixel; +} + +static inline void sw_pixel_set_color_R4G4B4A4(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +{ + uint16_t pixel = (sw_compress_fto4(color[0]) << 12) + | (sw_compress_fto4(color[1]) << 8) + | (sw_compress_fto4(color[2]) << 4) + | sw_compress_fto4(color[3]); + ((uint16_t *)pixels)[offset] = pixel; +} + +static inline void sw_pixel_set_color_R8G8B8A8(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +{ + uint8_t *dst = &((uint8_t *)pixels)[offset*4]; + +#if defined(SW_HAS_NEON) + float32x4_t fvals = vmulq_f32(vld1q_f32(color), vdupq_n_f32(255.0f)); + uint32x4_t i32 = vcvtq_u32_f32(fvals); + uint16x4_t i16 = vmovn_u32(i32); + uint8x8_t i8 = vmovn_u16(vcombine_u16(i16, i16)); + dst[0] = vget_lane_u8(i8, 0); + dst[1] = vget_lane_u8(i8, 1); + dst[2] = vget_lane_u8(i8, 2); + dst[3] = vget_lane_u8(i8, 3); + +#elif defined(SW_HAS_SSE41) + __m128 fvals = _mm_mul_ps(_mm_loadu_ps(color), _mm_set1_ps(255.0f)); + __m128i i32 = _mm_cvttps_epi32(fvals); + __m128i i16 = _mm_packus_epi32(i32, i32); + __m128i i8 = _mm_packus_epi16(i16, i16); + _mm_storeu_si32(dst, i8); + +#elif defined(SW_HAS_SSE2) + __m128 fvals = _mm_mul_ps(_mm_loadu_ps(color), _mm_set1_ps(255.0f)); + __m128i i32 = _mm_cvttps_epi32(fvals); + __m128i i16 = _mm_packs_epi32(i32, i32); + __m128i i8 = _mm_packus_epi16(i16, i16); + _mm_storeu_si32(dst, i8); + +#elif defined(SW_HAS_RVV) + // TODO: Sample code generated by AI, needs testing and review + // REVIEW: It shouldn't perform so many operations; take inspiration from other versions + // NOTE: RVV 1.0 specs define the use of __riscv_ prefix for instrinsic functions + size_t vl = __riscv_vsetvl_e32m1(4); // Load up to 4 floats into a vector register + vfloat32m1_t vsrc = __riscv_vle32_v_f32m1(src, vl); // Load float32 values + + // Multiply by 255.0f and add 0.5f for rounding + vfloat32m1_t vscaled = __riscv_vfmul_vf_f32m1(vsrc, 255.0f, vl); + vscaled = __riscv_vfadd_vf_f32m1(vscaled, 0.5f, vl); + + // Convert to unsigned integer (truncate toward zero) + vuint32m1_t vu32 = __riscv_vfcvt_xu_f_v_u32m1(vscaled, vl); + + // Narrow from u32 -> u8 + vuint8m1_t vu8 = __riscv_vnclipu_wx_u8m1(vu32, 0, vl); // Round toward zero + __riscv_vse8_v_u8m1(dst, vu8, vl); // Store result + +#else + dst[0] = (uint8_t)(color[0]*255.0f); + dst[1] = (uint8_t)(color[1]*255.0f); + dst[2] = (uint8_t)(color[2]*255.0f); + dst[3] = (uint8_t)(color[3]*255.0f); +#endif +} + +static inline void sw_pixel_set_color_R32(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +{ + ((float *)pixels)[offset] = sw_luminance(color); +} + +static inline void sw_pixel_set_color_R32G32B32(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +{ + float *dst = &((float *)pixels)[offset*3]; + dst[0] = color[0]; + dst[1] = color[1]; + dst[2] = color[2]; +} + +static inline void sw_pixel_set_color_R32G32B32A32(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +{ + float *dst = &((float *)pixels)[offset*4]; + dst[0] = color[0]; + dst[1] = color[1]; + dst[2] = color[2]; + dst[3] = color[3]; +} + +static inline void sw_pixel_set_color_R16(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +{ + ((uint16_t *)pixels)[offset] = sw_float_to_half(sw_luminance(color)); +} + +static inline void sw_pixel_set_color_R16G16B16(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +{ + uint16_t *dst = &((uint16_t *)pixels)[offset*3]; + dst[0] = sw_float_to_half(color[0]); + dst[1] = sw_float_to_half(color[1]); + dst[2] = sw_float_to_half(color[2]); +} + +static inline void sw_pixel_set_color_R16G16B16A16(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +{ + uint16_t *dst = &((uint16_t *)pixels)[offset*4]; + dst[0] = sw_float_to_half(color[0]); + dst[1] = sw_float_to_half(color[1]); + dst[2] = sw_float_to_half(color[2]); + dst[3] = sw_float_to_half(color[3]); +} + +static inline void sw_pixel_set_color(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset, sw_pixelformat_t format) +{ + switch (format) + { + case SW_PIXELFORMAT_COLOR_GRAYSCALE: + sw_pixel_set_color_GRAYSCALE(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_GRAYALPHA: + sw_pixel_set_color_GRAYALPHA(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R3G3B2: + sw_pixel_set_color_R3G3B2(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R5G6B5: + sw_pixel_set_color_R5G6B5(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R8G8B8: + sw_pixel_set_color_R8G8B8(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R5G5B5A1: + sw_pixel_set_color_R5G5B5A1(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R4G4B4A4: + sw_pixel_set_color_R4G4B4A4(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R8G8B8A8: + sw_pixel_set_color_R8G8B8A8(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R32: + sw_pixel_set_color_R32(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R32G32B32: + sw_pixel_set_color_R32G32B32(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R32G32B32A32: + sw_pixel_set_color_R32G32B32A32(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R16: + sw_pixel_set_color_R16(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R16G16B16: + sw_pixel_set_color_R16G16B16(pixels, color, offset); + break; + case SW_PIXELFORMAT_COLOR_R16G16B16A16: + sw_pixel_set_color_R16G16B16A16(pixels, color, offset); + break; + + case SW_PIXELFORMAT_UNKNOWN: + case SW_PIXELFORMAT_DEPTH_D8: + case SW_PIXELFORMAT_DEPTH_D16: + case SW_PIXELFORMAT_DEPTH_D32: + case SW_PIXELFORMAT_COUNT: + break; + } +} + +static inline float sw_pixel_get_depth_D8(const void *pixels, uint32_t offset) +{ + return (float)((uint8_t *)pixels)[offset]*SW_INV_255; +} + +static inline float sw_pixel_get_depth_D16(const void *pixels, uint32_t offset) +{ + return (float)((uint16_t *)pixels)[offset]/UINT16_MAX; +} + +static inline float sw_pixel_get_depth_D32(const void *pixels, uint32_t offset) +{ + return ((float *)pixels)[offset]; +} + +static inline float sw_pixel_get_depth(const void *pixels, uint32_t offset, sw_pixelformat_t format) +{ + switch (format) + { + case SW_PIXELFORMAT_DEPTH_D8: + return sw_pixel_get_depth_D8(pixels, offset); + case SW_PIXELFORMAT_DEPTH_D16: + return sw_pixel_get_depth_D16(pixels, offset); + case SW_PIXELFORMAT_DEPTH_D32: + return sw_pixel_get_depth_D32(pixels, offset); + + case SW_PIXELFORMAT_UNKNOWN: + case SW_PIXELFORMAT_COLOR_GRAYSCALE: + case SW_PIXELFORMAT_COLOR_GRAYALPHA: + case SW_PIXELFORMAT_COLOR_R3G3B2: + case SW_PIXELFORMAT_COLOR_R5G6B5: + case SW_PIXELFORMAT_COLOR_R8G8B8: + case SW_PIXELFORMAT_COLOR_R5G5B5A1: + case SW_PIXELFORMAT_COLOR_R4G4B4A4: + case SW_PIXELFORMAT_COLOR_R8G8B8A8: + case SW_PIXELFORMAT_COLOR_R32: + case SW_PIXELFORMAT_COLOR_R32G32B32: + case SW_PIXELFORMAT_COLOR_R32G32B32A32: + case SW_PIXELFORMAT_COLOR_R16: + case SW_PIXELFORMAT_COLOR_R16G16B16: + case SW_PIXELFORMAT_COLOR_R16G16B16A16: + case SW_PIXELFORMAT_COUNT: + break; + } + + return 0.0f; +} + +static inline void sw_pixel_set_depth_D8(void *pixels, float depth, uint32_t offset) +{ + ((uint8_t *)pixels)[offset] = (uint8_t)(depth*UINT8_MAX); +} + +static inline void sw_pixel_set_depth_D16(void *pixels, float depth, uint32_t offset) +{ + ((uint16_t *)pixels)[offset] = (uint16_t)(depth*UINT16_MAX); +} + +static inline void sw_pixel_set_depth_D32(void *pixels, float depth, uint32_t offset) +{ + ((float *)pixels)[offset] = depth; +} + +static inline void sw_pixel_set_depth(void *pixels, float depth, uint32_t offset, sw_pixelformat_t format) +{ + switch (format) + { + case SW_PIXELFORMAT_DEPTH_D8: + sw_pixel_set_depth_D8(pixels, depth, offset); + break; + case SW_PIXELFORMAT_DEPTH_D16: + sw_pixel_set_depth_D16(pixels, depth, offset); + break; + case SW_PIXELFORMAT_DEPTH_D32: + sw_pixel_set_depth_D32(pixels, depth, offset); + break; + + case SW_PIXELFORMAT_UNKNOWN: + case SW_PIXELFORMAT_COLOR_GRAYSCALE: + case SW_PIXELFORMAT_COLOR_GRAYALPHA: + case SW_PIXELFORMAT_COLOR_R3G3B2: + case SW_PIXELFORMAT_COLOR_R5G6B5: + case SW_PIXELFORMAT_COLOR_R8G8B8: + case SW_PIXELFORMAT_COLOR_R5G5B5A1: + case SW_PIXELFORMAT_COLOR_R4G4B4A4: + case SW_PIXELFORMAT_COLOR_R8G8B8A8: + case SW_PIXELFORMAT_COLOR_R32: + case SW_PIXELFORMAT_COLOR_R32G32B32: + case SW_PIXELFORMAT_COLOR_R32G32B32A32: + case SW_PIXELFORMAT_COLOR_R16: + case SW_PIXELFORMAT_COLOR_R16G16B16: + case SW_PIXELFORMAT_COLOR_R16G16B16A16: + case SW_PIXELFORMAT_COUNT: + break; + } +} +//------------------------------------------------------------------------------------------- + +// Texture functionality +//------------------------------------------------------------------------------------------- +static inline bool sw_texture_alloc(sw_texture_t *texture, const void *data, int w, int h, sw_pixelformat_t format) +{ + int bpp = SW_PIXELFORMAT_SIZE[format]; + int newSize = w*h*bpp; + + if (newSize > texture->allocSz) + { + void* ptr = SW_REALLOC(texture->pixels, newSize); + if (!ptr) { RLSW.errCode = SW_OUT_OF_MEMORY; return false; } + texture->allocSz = newSize; + texture->pixels = ptr; + } + + uint8_t* dst = texture->pixels; + const uint8_t* src = data; + + if (data) for (int i = 0; i < newSize; i++) dst[i] = src[i]; + else for (int i = 0; i < newSize; i++) dst[i] = 0; + + texture->format = format; + texture->width = w; + texture->height = h; + texture->wMinus1 = w - 1; + texture->hMinus1 = h - 1; + texture->tx = 1.0f/w; + texture->ty = 1.0f/h; + + return true; +} + +static inline void sw_texture_free(sw_texture_t *texture) +{ + SW_FREE(texture->pixels); +} + +static inline void sw_texture_fetch(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, int x, int y) +{ + sw_pixel_get_color(color, tex->pixels, y*tex->width + x, tex->format); +} + +static inline void sw_texture_sample_nearest(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, float u, float v) +{ + u = (tex->sWrap == SW_REPEAT)? sw_fract(u) : sw_saturate(u); + v = (tex->tWrap == SW_REPEAT)? sw_fract(v) : sw_saturate(v); + + int x = u*tex->width; + int y = v*tex->height; + + sw_texture_fetch(color, tex, x, y); +} + +static inline void sw_texture_sample_linear(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, float u, float v) +{ + // TODO: With a bit more cleverness thee number of operations can + // be clearly reduced, but for now it works fine + + float xf = (u*tex->width) - 0.5f; + float yf = (v*tex->height) - 0.5f; + + float fx = sw_fract(xf); + float fy = sw_fract(yf); + + int x0 = (int)xf; + int y0 = (int)yf; + + int x1 = x0 + 1; + int y1 = y0 + 1; + + // NOTE: If the textures are POT, avoid the division for SW_REPEAT + + if (tex->sWrap == SW_CLAMP) + { + x0 = (x0 > tex->wMinus1)? tex->wMinus1 : x0; + x1 = (x1 > tex->wMinus1)? tex->wMinus1 : x1; + } + else + { + x0 = (x0%tex->width + tex->width)%tex->width; + x1 = (x1%tex->width + tex->width)%tex->width; + } + + if (tex->tWrap == SW_CLAMP) + { + y0 = (y0 > tex->hMinus1)? tex->hMinus1 : y0; + y1 = (y1 > tex->hMinus1)? tex->hMinus1 : y1; + } + else + { + y0 = (y0%tex->height + tex->height)%tex->height; + y1 = (y1%tex->height + tex->height)%tex->height; + } + + float c00[4], c10[4], c01[4], c11[4]; + sw_texture_fetch(c00, tex, x0, y0); + sw_texture_fetch(c10, tex, x1, y0); + sw_texture_fetch(c01, tex, x0, y1); + sw_texture_fetch(c11, tex, x1, y1); + + for (int i = 0; i < 4; i++) + { + float t = c00[i] + fx*(c10[i] - c00[i]); + float b = c01[i] + fx*(c11[i] - c01[i]); + color[i] = t + fy*(b - t); + } +} + +static inline void sw_texture_sample(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, + float u, float v, float dUdx, float dUdy, float dVdx, float dVdy) +{ + // Previous method: There is no need to compute the square root + // because using the squared value, the comparison remains (L2 > 1.0f*1.0f) + //float du = sqrtf(dUdx*dUdx + dUdy*dUdy); + //float dv = sqrtf(dVdx*dVdx + dVdy*dVdy); + //float L = (du > dv)? du : dv; + + // Calculate the derivatives for each axis + float dU2 = dUdx*dUdx + dUdy*dUdy; + float dV2 = dVdx*dVdx + dVdy*dVdy; + float L2 = (dU2 > dV2)? dU2 : dV2; + + SWfilter filter = (L2 > 1.0f)? tex->minFilter : tex->magFilter; + + switch (filter) + { + case SW_NEAREST: sw_texture_sample_nearest(color, tex, u, v); break; + case SW_LINEAR: sw_texture_sample_linear(color, tex, u, v); break; + default: break; + } +} +//------------------------------------------------------------------------------------------- + +// Framebuffer management functions +//------------------------------------------------------------------------------------------- +static inline bool sw_default_framebuffer_alloc(sw_default_framebuffer_t* fb, int w, int h) +{ + if (!sw_texture_alloc(&fb->color, NULL, w, h, SW_FRAMEBUFFER_COLOR_FORMAT)) + { + return false; + } + + if (!sw_texture_alloc(&fb->depth, NULL, w, h, SW_FRAMEBUFFER_DEPTH_FORMAT)) + { + return false; + } + + return true; +} + +static inline void sw_default_framebuffer_free(sw_default_framebuffer_t* fb) +{ + sw_texture_free(&fb->color); + sw_texture_free(&fb->depth); +} + +static inline void sw_framebuffer_fill_color(sw_texture_t *colorBuffer, const float color[4]) +{ + // NOTE: MSVC doesn't support VLA, so we allocate the largest possible size + //uint8_t pixel[SW_FRAMEBUFFER_COLOR_SIZE]; + + uint8_t pixel[16]; + SW_FRAMEBUFFER_COLOR_SET(pixel, color, 0); + + uint8_t *dst = (uint8_t *)colorBuffer->pixels; + + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { + int xMin = sw_clamp_int(RLSW.scMin[0], 0, colorBuffer->width - 1); + int xMax = sw_clamp_int(RLSW.scMax[0], 0, colorBuffer->width - 1); + int yMin = sw_clamp_int(RLSW.scMin[1], 0, colorBuffer->height - 1); + int yMax = sw_clamp_int(RLSW.scMax[1], 0, colorBuffer->height - 1); + + int w = xMax - xMin; + for (int y = yMin; y <= yMax; y++) + { + uint8_t *row = dst + (y*colorBuffer->width + xMin)*SW_FRAMEBUFFER_COLOR_SIZE; + for (int x = 0; x <= w; x++, row += SW_FRAMEBUFFER_COLOR_SIZE) + { + for (int b = 0; b < SW_FRAMEBUFFER_COLOR_SIZE; b++) row[b] = pixel[b]; + } + } + } + else + { + int size = colorBuffer->width*colorBuffer->height; + for (int i = 0; i < size; i++) + { + for (int b = 0; b < SW_FRAMEBUFFER_COLOR_SIZE; b++) + { + dst[i*SW_FRAMEBUFFER_COLOR_SIZE + b] = pixel[b]; + } + } + } +} + +static inline void sw_framebuffer_fill_depth(sw_texture_t *depthBuffer, float depth) +{ + // NOTE: MSVC doesn't support VLA, so we allocate the largest possible size + //uint8_t pixel[SW_FRAMEBUFFER_DEPTH_SIZE]; + + uint8_t pixel[4]; + SW_FRAMEBUFFER_DEPTH_SET(pixel, depth, 0); + + uint8_t *dst = (uint8_t *)depthBuffer->pixels; + + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { + int xMin = sw_clamp_int(RLSW.scMin[0], 0, depthBuffer->width - 1); + int xMax = sw_clamp_int(RLSW.scMax[0], 0, depthBuffer->width - 1); + int yMin = sw_clamp_int(RLSW.scMin[1], 0, depthBuffer->height - 1); + int yMax = sw_clamp_int(RLSW.scMax[1], 0, depthBuffer->height - 1); + + int w = xMax - xMin; + for (int y = yMin; y <= yMax; y++) + { + uint8_t *row = dst + (y*depthBuffer->width + xMin)*SW_FRAMEBUFFER_DEPTH_SIZE; + for (int x = 0; x <= w; x++, row += SW_FRAMEBUFFER_DEPTH_SIZE) + { + for (int b = 0; b < SW_FRAMEBUFFER_DEPTH_SIZE; b++) row[b] = pixel[b]; + } + } + } + else + { + int size = depthBuffer->width*depthBuffer->height; + for (int i = 0; i < size; i++) + { + for (int b = 0; b < SW_FRAMEBUFFER_DEPTH_SIZE; b++) + { + dst[i*SW_FRAMEBUFFER_DEPTH_SIZE + b] = pixel[b]; + } + } + } +} + +static inline void sw_framebuffer_output_fast(void* dst, const sw_texture_t* buffer) +{ + int width = buffer->width; + int height = buffer->height; + + uint8_t *d = (uint8_t *)dst; + +#if SW_FRAMEBUFFER_OUTPUT_BGRA && (SW_FRAMEBUFFER_COLOR_FORMAT == SW_PIXELFORMAT_COLOR_R8G8B8A8) + for (int y = height - 1; y >= 0; y--) + { + const uint8_t *src = (uint8_t *)(buffer->pixels) + y*width*4; + for (int x = 0; x < width; x++, src += 4, d += 4) + { + d[0] = src[2]; + d[1] = src[1]; + d[2] = src[0]; + d[3] = src[3]; + } + } +#elif SW_FRAMEBUFFER_OUTPUT_BGRA && (SW_FRAMEBUFFER_COLOR_FORMAT == SW_PIXELFORMAT_COLOR_R8G8B8) + for (int y = height - 1; y >= 0; y--) + { + const uint8_t *src = (uint8_t *)(buffer->pixels) + y*width*3; + for (int x = 0; x < width; x++, src += 3, d += 3) + { + d[0] = src[2]; + d[1] = src[1]; + d[2] = src[0]; + } + } +#else + int rowBytes = width*SW_FRAMEBUFFER_COLOR_SIZE; + for (int y = height - 1; y >= 0; y--) + { + const uint8_t *src = (uint8_t *)(buffer->pixels) + y*rowBytes; + for (int i = 0; i < rowBytes; i++) d[i] = src[i]; + d += rowBytes; + } +#endif +} + +static inline void sw_framebuffer_output_copy(void* dst, const sw_texture_t* buffer, int x, int y, int w, int h, sw_pixelformat_t format) +{ + int dstPixelSize = SW_PIXELFORMAT_SIZE[format]; + int stride = buffer->width; + + const uint8_t *src = (uint8_t *)(buffer->pixels) + ((y + h - 1)*stride + x)*SW_FRAMEBUFFER_COLOR_SIZE; + uint8_t *d = dst; + + for (int iy = 0; iy < h; iy++) + { + const uint8_t *line = src; + uint8_t *dline = d; + + for (int ix = 0; ix < w; ix++) + { + uint8_t color[4]; + SW_FRAMEBUFFER_COLOR8_GET(color, line, 0); + + #if SW_FRAMEBUFFER_OUTPUT_BGRA + if (format == SW_PIXELFORMAT_COLOR_R8G8B8A8 || format == SW_PIXELFORMAT_COLOR_R8G8B8) + { + uint8_t tmp = color[0]; color[0] = color[2]; color[2] = tmp; + } + #endif + + sw_pixel_set_color8(dline, color, 0, format); + line += SW_FRAMEBUFFER_COLOR_SIZE; + dline += dstPixelSize; + } + + src -= stride*SW_FRAMEBUFFER_COLOR_SIZE; + d += w*dstPixelSize; + } +} + +static inline void sw_framebuffer_output_blit( + void* dst, const sw_texture_t* buffer, + int xDst, int yDst, int wDst, int hDst, + int xSrc, int ySrc, int wSrc, int hSrc, + sw_pixelformat_t format) +{ + const uint8_t *srcBase = buffer->pixels; + + int fbWidth = buffer->width; + int dstPixelSize = SW_PIXELFORMAT_SIZE[format]; + + uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; + uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; + + int ySrcLast = ySrc + hSrc - 1; + + uint8_t *d = (uint8_t *)dst; + + for (int dy = 0; dy < hDst; dy++) + { + int sy = ySrcLast - (int)(dy*yScale >> 16); + const uint8_t *srcLine = srcBase + (sy*fbWidth + xSrc)*SW_FRAMEBUFFER_COLOR_SIZE; + uint8_t *dline = d; + + for (int dx = 0; dx < wDst; dx++) + { + int sx = (int)(dx*xScale >> 16); + const uint8_t *pixel = srcLine + sx*SW_FRAMEBUFFER_COLOR_SIZE; + + uint8_t color[4]; + SW_FRAMEBUFFER_COLOR8_GET(color, pixel, 0); + + #if SW_FRAMEBUFFER_OUTPUT_BGRA + if (format == SW_PIXELFORMAT_COLOR_R8G8B8A8 || format == SW_PIXELFORMAT_COLOR_R8G8B8) + { + uint8_t tmp = color[0]; color[0] = color[2]; color[2] = tmp; + } + #endif + + sw_pixel_set_color8(dline, color, 0, format); + dline += dstPixelSize; + } + + d += wDst*dstPixelSize; + } +} +//------------------------------------------------------------------------------------------- + +// Color blending functionality +//------------------------------------------------------------------------------------------- +static inline void sw_factor_zero(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) +{ + factor[0] = factor[1] = factor[2] = factor[3] = 0.0f; +} + +static inline void sw_factor_one(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) +{ + factor[0] = factor[1] = factor[2] = factor[3] = 1.0f; +} + +static inline void sw_factor_src_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) +{ + factor[0] = src[0]; factor[1] = src[1]; factor[2] = src[2]; factor[3] = src[3]; +} + +static inline void sw_factor_one_minus_src_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) +{ + factor[0] = 1.0f - src[0]; factor[1] = 1.0f - src[1]; + factor[2] = 1.0f - src[2]; factor[3] = 1.0f - src[3]; +} + +static inline void sw_factor_src_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) +{ + factor[0] = factor[1] = factor[2] = factor[3] = src[3]; +} + +static inline void sw_factor_one_minus_src_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) +{ + float invAlpha = 1.0f - src[3]; + factor[0] = factor[1] = factor[2] = factor[3] = invAlpha; +} + +static inline void sw_factor_dst_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) +{ + factor[0] = factor[1] = factor[2] = factor[3] = dst[3]; +} + +static inline void sw_factor_one_minus_dst_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) +{ + float invAlpha = 1.0f - dst[3]; + factor[0] = factor[1] = factor[2] = factor[3] = invAlpha; +} + +static inline void sw_factor_dst_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) +{ + factor[0] = dst[0]; factor[1] = dst[1]; factor[2] = dst[2]; factor[3] = dst[3]; +} + +static inline void sw_factor_one_minus_dst_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) +{ + factor[0] = 1.0f - dst[0]; factor[1] = 1.0f - dst[1]; + factor[2] = 1.0f - dst[2]; factor[3] = 1.0f - dst[3]; +} + +static inline void sw_factor_src_alpha_saturate(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) +{ + factor[0] = factor[1] = factor[2] = 1.0f; + factor[3] = (src[3] < 1.0f)? src[3] : 1.0f; +} + +static inline void sw_blend_colors(float *SW_RESTRICT dst/*[4]*/, const float *SW_RESTRICT src/*[4]*/) +{ + float srcFactor[4], dstFactor[4]; + + RLSW.srcFactorFunc(srcFactor, src, dst); + RLSW.dstFactorFunc(dstFactor, src, dst); + + dst[0] = srcFactor[0]*src[0] + dstFactor[0]*dst[0]; + dst[1] = srcFactor[1]*src[1] + dstFactor[1]*dst[1]; + dst[2] = srcFactor[2]*src[2] + dstFactor[2]*dst[2]; + dst[3] = srcFactor[3]*src[3] + dstFactor[3]*dst[3]; +} +//------------------------------------------------------------------------------------------- + +// Projection helper functions +//------------------------------------------------------------------------------------------- +static inline void sw_project_ndc_to_screen(float screen[2], const float ndc[4]) +{ + screen[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalf[0] + 0.5f; + screen[1] = RLSW.vpCenter[1] + ndc[1]*RLSW.vpHalf[1] + 0.5f; +} +//------------------------------------------------------------------------------------------- + +// Polygon clipping management +//------------------------------------------------------------------------------------------- +#define DEFINE_CLIP_FUNC(name, FUNC_IS_INSIDE, FUNC_COMPUTE_T) \ +static int sw_clip_##name( \ + sw_vertex_t output[SW_MAX_CLIPPED_POLYGON_VERTICES], \ + const sw_vertex_t input[SW_MAX_CLIPPED_POLYGON_VERTICES], \ + int n) \ +{ \ + const sw_vertex_t *prev = &input[n - 1]; \ + int prevInside = FUNC_IS_INSIDE(prev->homogeneous); \ + int outputCount = 0; \ + \ + for (int i = 0; i < n; i++) { \ + const sw_vertex_t *curr = &input[i]; \ + int currInside = FUNC_IS_INSIDE(curr->homogeneous); \ + \ + /* If transition between interior/exterior, calculate intersection point */ \ + if (prevInside != currInside) { \ + float t = FUNC_COMPUTE_T(prev->homogeneous, curr->homogeneous); \ + sw_lerp_vertex_PTCH(&output[outputCount++], prev, curr, t); \ + } \ + \ + /* If current vertex inside, add it */ \ + if (currInside) { \ + output[outputCount++] = *curr; \ + } \ + \ + prev = curr; \ + prevInside = currInside; \ + } \ + \ + return outputCount; \ +} +//------------------------------------------------------------------------------------------- + +// Frustum cliping functions +//------------------------------------------------------------------------------------------- +#define IS_INSIDE_PLANE_W(h) ((h)[3] >= SW_CLIP_EPSILON) +#define IS_INSIDE_PLANE_X_POS(h) ( (h)[0] < (h)[3]) // Exclusive for +X +#define IS_INSIDE_PLANE_X_NEG(h) (-(h)[0] < (h)[3]) // Exclusive for -X +#define IS_INSIDE_PLANE_Y_POS(h) ( (h)[1] < (h)[3]) // Exclusive for +Y +#define IS_INSIDE_PLANE_Y_NEG(h) (-(h)[1] < (h)[3]) // Exclusive for -Y +#define IS_INSIDE_PLANE_Z_POS(h) ( (h)[2] <= (h)[3]) // Inclusive for +Z +#define IS_INSIDE_PLANE_Z_NEG(h) (-(h)[2] <= (h)[3]) // Inclusive for -Z + +#define COMPUTE_T_PLANE_W(hPrev, hCurr) ((SW_CLIP_EPSILON - (hPrev)[3])/((hCurr)[3] - (hPrev)[3])) +#define COMPUTE_T_PLANE_X_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[0])/(((hPrev)[3] - (hPrev)[0]) - ((hCurr)[3] - (hCurr)[0]))) +#define COMPUTE_T_PLANE_X_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[0])/(((hPrev)[3] + (hPrev)[0]) - ((hCurr)[3] + (hCurr)[0]))) +#define COMPUTE_T_PLANE_Y_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[1])/(((hPrev)[3] - (hPrev)[1]) - ((hCurr)[3] - (hCurr)[1]))) +#define COMPUTE_T_PLANE_Y_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[1])/(((hPrev)[3] + (hPrev)[1]) - ((hCurr)[3] + (hCurr)[1]))) +#define COMPUTE_T_PLANE_Z_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[2])/(((hPrev)[3] - (hPrev)[2]) - ((hCurr)[3] - (hCurr)[2]))) +#define COMPUTE_T_PLANE_Z_NEG(hPrev, hCurr) (((hPrev)[3] + (hPrev)[2])/(((hPrev)[3] + (hPrev)[2]) - ((hCurr)[3] + (hCurr)[2]))) + +DEFINE_CLIP_FUNC(w, IS_INSIDE_PLANE_W, COMPUTE_T_PLANE_W) +DEFINE_CLIP_FUNC(x_pos, IS_INSIDE_PLANE_X_POS, COMPUTE_T_PLANE_X_POS) +DEFINE_CLIP_FUNC(x_neg, IS_INSIDE_PLANE_X_NEG, COMPUTE_T_PLANE_X_NEG) +DEFINE_CLIP_FUNC(y_pos, IS_INSIDE_PLANE_Y_POS, COMPUTE_T_PLANE_Y_POS) +DEFINE_CLIP_FUNC(y_neg, IS_INSIDE_PLANE_Y_NEG, COMPUTE_T_PLANE_Y_NEG) +DEFINE_CLIP_FUNC(z_pos, IS_INSIDE_PLANE_Z_POS, COMPUTE_T_PLANE_Z_POS) +DEFINE_CLIP_FUNC(z_neg, IS_INSIDE_PLANE_Z_NEG, COMPUTE_T_PLANE_Z_NEG) +//------------------------------------------------------------------------------------------- + +// Scissor clip functions +//------------------------------------------------------------------------------------------- +#define COMPUTE_T_SCISSOR_X_MIN(hPrev, hCurr) (((RLSW.scClipMin[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMin[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMin[0])*(hPrev)[3]))) +#define COMPUTE_T_SCISSOR_X_MAX(hPrev, hCurr) (((RLSW.scClipMax[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMax[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMax[0])*(hPrev)[3]))) +#define COMPUTE_T_SCISSOR_Y_MIN(hPrev, hCurr) (((RLSW.scClipMin[1])*(hPrev)[3] - (hPrev)[1])/(((hCurr)[1] - (RLSW.scClipMin[1])*(hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMin[1])*(hPrev)[3]))) +#define COMPUTE_T_SCISSOR_Y_MAX(hPrev, hCurr) (((RLSW.scClipMax[1])*(hPrev)[3] - (hPrev)[1])/(((hCurr)[1] - (RLSW.scClipMax[1])*(hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMax[1])*(hPrev)[3]))) + +#define IS_INSIDE_SCISSOR_X_MIN(h) ((h)[0] >= (RLSW.scClipMin[0])*(h)[3]) +#define IS_INSIDE_SCISSOR_X_MAX(h) ((h)[0] <= (RLSW.scClipMax[0])*(h)[3]) +#define IS_INSIDE_SCISSOR_Y_MIN(h) ((h)[1] >= (RLSW.scClipMin[1])*(h)[3]) +#define IS_INSIDE_SCISSOR_Y_MAX(h) ((h)[1] <= (RLSW.scClipMax[1])*(h)[3]) + +DEFINE_CLIP_FUNC(scissor_x_min, IS_INSIDE_SCISSOR_X_MIN, COMPUTE_T_SCISSOR_X_MIN) +DEFINE_CLIP_FUNC(scissor_x_max, IS_INSIDE_SCISSOR_X_MAX, COMPUTE_T_SCISSOR_X_MAX) +DEFINE_CLIP_FUNC(scissor_y_min, IS_INSIDE_SCISSOR_Y_MIN, COMPUTE_T_SCISSOR_Y_MIN) +DEFINE_CLIP_FUNC(scissor_y_max, IS_INSIDE_SCISSOR_Y_MAX, COMPUTE_T_SCISSOR_Y_MAX) +//------------------------------------------------------------------------------------------- + +// Main polygon clip function +static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int *vertexCounter) +{ + static sw_vertex_t tmp[SW_MAX_CLIPPED_POLYGON_VERTICES]; + + int n = *vertexCounter; + + #define CLIP_AGAINST_PLANE(FUNC_CLIP) \ + { \ + n = FUNC_CLIP(tmp, polygon, n); \ + if (n < 3) \ + { \ + *vertexCounter = 0; \ + return false; \ + } \ + for (int i = 0; i < n; i++) polygon[i] = tmp[i]; \ + } + + CLIP_AGAINST_PLANE(sw_clip_w); + CLIP_AGAINST_PLANE(sw_clip_x_pos); + CLIP_AGAINST_PLANE(sw_clip_x_neg); + CLIP_AGAINST_PLANE(sw_clip_y_pos); + CLIP_AGAINST_PLANE(sw_clip_y_neg); + CLIP_AGAINST_PLANE(sw_clip_z_pos); + CLIP_AGAINST_PLANE(sw_clip_z_neg); + + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { + CLIP_AGAINST_PLANE(sw_clip_scissor_x_min); + CLIP_AGAINST_PLANE(sw_clip_scissor_x_max); + CLIP_AGAINST_PLANE(sw_clip_scissor_y_min); + CLIP_AGAINST_PLANE(sw_clip_scissor_y_max); + } + + *vertexCounter = n; + + return (n >= 3); +} + +// Triangle rasterizer variant dispatch +//------------------------------------------------------------------------------------------- +#ifndef RLSW_TEMPLATE_RASTER_TRIANGLE_EXPANDING +#define RLSW_TEMPLATE_RASTER_TRIANGLE_EXPANDING + + // State mask to apply before indexing the dispatch table + #define SW_RASTER_TRIANGLE_STATE_MASK \ + (SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND) + + // Single source of truth for all rasterizer specializations + // X(NAME, STATE_FLAGS) + #define SW_RASTER_VARIANTS(X) \ + X(BASE, 0) \ + X(TEX, SW_STATE_TEXTURE_2D) \ + X(DEPTH, SW_STATE_DEPTH_TEST) \ + X(BLEND, SW_STATE_BLEND) \ + X(TEX_DEPTH, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST) \ + X(TEX_BLEND, SW_STATE_TEXTURE_2D | SW_STATE_BLEND) \ + X(DEPTH_BLEND, SW_STATE_DEPTH_TEST | SW_STATE_BLEND) \ + X(TEX_DEPTH_BLEND, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND) + + // Forward declarations because clangd does not follow #include __FILE__ to avoid infinite recursion + // These declarations make all variants visible to static analysis tools without affecting compilation + #define SW_FWD_DECL(NAME, _FLAGS) \ + static void sw_raster_triangle_##NAME(const sw_vertex_t*, const sw_vertex_t*, const sw_vertex_t*); + SW_RASTER_VARIANTS(SW_FWD_DECL) // NOLINT + #undef SW_FWD_DECL + + // Specialization generation via self-inclusion + + #define RLSW_TEMPLATE_RASTER_TRIANGLE BASE + #include __FILE__ // IWYU pragma: keep + #undef RLSW_TEMPLATE_RASTER_TRIANGLE + + #define RLSW_TEMPLATE_RASTER_TRIANGLE TEX + #define SW_ENABLE_TEXTURE + #include __FILE__ + #undef SW_ENABLE_TEXTURE + #undef RLSW_TEMPLATE_RASTER_TRIANGLE + + #define RLSW_TEMPLATE_RASTER_TRIANGLE DEPTH + #define SW_ENABLE_DEPTH_TEST + #include __FILE__ + #undef SW_ENABLE_DEPTH_TEST + #undef RLSW_TEMPLATE_RASTER_TRIANGLE + + #define RLSW_TEMPLATE_RASTER_TRIANGLE BLEND + #define SW_ENABLE_BLEND + #include __FILE__ + #undef SW_ENABLE_BLEND + #undef RLSW_TEMPLATE_RASTER_TRIANGLE + + #define RLSW_TEMPLATE_RASTER_TRIANGLE TEX_DEPTH + #define SW_ENABLE_TEXTURE + #define SW_ENABLE_DEPTH_TEST + #include __FILE__ + #undef SW_ENABLE_DEPTH_TEST + #undef SW_ENABLE_TEXTURE + #undef RLSW_TEMPLATE_RASTER_TRIANGLE + + #define RLSW_TEMPLATE_RASTER_TRIANGLE TEX_BLEND + #define SW_ENABLE_TEXTURE + #define SW_ENABLE_BLEND + #include __FILE__ + #undef SW_ENABLE_BLEND + #undef SW_ENABLE_TEXTURE + #undef RLSW_TEMPLATE_RASTER_TRIANGLE + + #define RLSW_TEMPLATE_RASTER_TRIANGLE DEPTH_BLEND + #define SW_ENABLE_DEPTH_TEST + #define SW_ENABLE_BLEND + #include __FILE__ + #undef SW_ENABLE_BLEND + #undef SW_ENABLE_DEPTH_TEST + #undef RLSW_TEMPLATE_RASTER_TRIANGLE + + #define RLSW_TEMPLATE_RASTER_TRIANGLE TEX_DEPTH_BLEND + #define SW_ENABLE_TEXTURE + #define SW_ENABLE_DEPTH_TEST + #define SW_ENABLE_BLEND + #include __FILE__ + #undef SW_ENABLE_BLEND + #undef SW_ENABLE_DEPTH_TEST + #undef SW_ENABLE_TEXTURE + #undef RLSW_TEMPLATE_RASTER_TRIANGLE + + // Dispatch table (auto-generated from SW_RASTER_VARIANTS) + #define SW_TABLE_ENTRY(NAME, FLAGS) [FLAGS] = sw_raster_triangle_##NAME, + static const sw_raster_triangle_f SW_RASTER_TRIANGLE_FUNCS[] = { + SW_RASTER_VARIANTS(SW_TABLE_ENTRY) + }; + #undef SW_TABLE_ENTRY + +#undef SW_RASTER_VARIANTS +#undef RLSW_TEMPLATE_RASTER_TRIANGLE_EXPANDING + +#endif // RLSW_TEMPLATE_RASTER_TRIANGLE_EXPANDING +//------------------------------------------------------------------------------------------- + +// Quad rasterizer variant dispatch +//------------------------------------------------------------------------------------------- +#ifndef RLSW_TEMPLATE_RASTER_QUAD_EXPANDING +#define RLSW_TEMPLATE_RASTER_QUAD_EXPANDING + + // State mask to apply before indexing the dispatch table + #define SW_RASTER_QUAD_STATE_MASK \ + (SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND) + + // Single source of truth for all rasterizer specializations + // X(NAME, STATE_FLAGS) + #define SW_RASTER_VARIANTS(X) \ + X(BASE, 0) \ + X(TEX, SW_STATE_TEXTURE_2D) \ + X(DEPTH, SW_STATE_DEPTH_TEST) \ + X(BLEND, SW_STATE_BLEND) \ + X(TEX_DEPTH, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST) \ + X(TEX_BLEND, SW_STATE_TEXTURE_2D | SW_STATE_BLEND) \ + X(DEPTH_BLEND, SW_STATE_DEPTH_TEST | SW_STATE_BLEND) \ + X(TEX_DEPTH_BLEND, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND) + + // Forward declarations because clangd does not follow #include __FILE__ to avoid infinite recursion + // These declarations make all variants visible to static analysis tools without affecting compilation + #define SW_FWD_DECL(NAME, _FLAGS) \ + static void sw_raster_quad_##NAME(const sw_vertex_t *v0, const sw_vertex_t *v1, const sw_vertex_t *v2, const sw_vertex_t *v3); + SW_RASTER_VARIANTS(SW_FWD_DECL) // NOLINT + #undef SW_FWD_DECL + + // Specialization generation via self-inclusion + + #define RLSW_TEMPLATE_RASTER_QUAD BASE + #include __FILE__ // IWYU pragma: keep + #undef RLSW_TEMPLATE_RASTER_QUAD + + #define RLSW_TEMPLATE_RASTER_QUAD TEX + #define SW_ENABLE_TEXTURE + #include __FILE__ + #undef SW_ENABLE_TEXTURE + #undef RLSW_TEMPLATE_RASTER_QUAD + + #define RLSW_TEMPLATE_RASTER_QUAD DEPTH + #define SW_ENABLE_DEPTH_TEST + #include __FILE__ + #undef SW_ENABLE_DEPTH_TEST + #undef RLSW_TEMPLATE_RASTER_QUAD + + #define RLSW_TEMPLATE_RASTER_QUAD BLEND + #define SW_ENABLE_BLEND + #include __FILE__ + #undef SW_ENABLE_BLEND + #undef RLSW_TEMPLATE_RASTER_QUAD + + #define RLSW_TEMPLATE_RASTER_QUAD TEX_DEPTH + #define SW_ENABLE_TEXTURE + #define SW_ENABLE_DEPTH_TEST + #include __FILE__ + #undef SW_ENABLE_DEPTH_TEST + #undef SW_ENABLE_TEXTURE + #undef RLSW_TEMPLATE_RASTER_QUAD + + #define RLSW_TEMPLATE_RASTER_QUAD TEX_BLEND + #define SW_ENABLE_TEXTURE + #define SW_ENABLE_BLEND + #include __FILE__ + #undef SW_ENABLE_BLEND + #undef SW_ENABLE_TEXTURE + #undef RLSW_TEMPLATE_RASTER_QUAD + + #define RLSW_TEMPLATE_RASTER_QUAD DEPTH_BLEND + #define SW_ENABLE_DEPTH_TEST + #define SW_ENABLE_BLEND + #include __FILE__ + #undef SW_ENABLE_BLEND + #undef SW_ENABLE_DEPTH_TEST + #undef RLSW_TEMPLATE_RASTER_QUAD + + #define RLSW_TEMPLATE_RASTER_QUAD TEX_DEPTH_BLEND + #define SW_ENABLE_TEXTURE + #define SW_ENABLE_DEPTH_TEST + #define SW_ENABLE_BLEND + #include __FILE__ + #undef SW_ENABLE_BLEND + #undef SW_ENABLE_DEPTH_TEST + #undef SW_ENABLE_TEXTURE + #undef RLSW_TEMPLATE_RASTER_QUAD + + // Dispatch table (auto-generated from SW_RASTER_VARIANTS) + #define SW_TABLE_ENTRY(NAME, FLAGS) [FLAGS] = sw_raster_quad_##NAME, + static const sw_raster_quad_f SW_RASTER_QUAD_FUNCS[] = { + SW_RASTER_VARIANTS(SW_TABLE_ENTRY) + }; + #undef SW_TABLE_ENTRY + +#undef SW_RASTER_VARIANTS +#undef RLSW_TEMPLATE_RASTER_QUAD_EXPANDING + +#endif // RLSW_TEMPLATE_RASTER_QUAD_EXPANDING +//------------------------------------------------------------------------------------------- + +// Line rasterizer variant dispatch +//------------------------------------------------------------------------------------------- +#ifndef RLSW_TEMPLATE_RASTER_LINE_EXPANDING +#define RLSW_TEMPLATE_RASTER_LINE_EXPANDING + + // State mask to apply before indexing the dispatch table + #define SW_RASTER_LINE_STATE_MASK \ + (SW_STATE_DEPTH_TEST | SW_STATE_BLEND) + + // Single source of truth for all rasterizer specializations + // X(NAME, STATE_FLAGS) + #define SW_RASTER_VARIANTS(X) \ + X(BASE, 0) \ + X(DEPTH, SW_STATE_DEPTH_TEST) \ + X(BLEND, SW_STATE_BLEND) \ + X(DEPTH_BLEND, SW_STATE_DEPTH_TEST | SW_STATE_BLEND) + + // Forward declarations because clangd does not follow #include __FILE__ to avoid infinite recursion + // These declarations make all variants visible to static analysis tools without affecting compilation + #define SW_FWD_DECL(NAME, _FLAGS) \ + static void sw_raster_line_##NAME(const sw_vertex_t *v0, const sw_vertex_t *v1); \ + static void sw_raster_line_thick_##NAME(const sw_vertex_t *v0, const sw_vertex_t *v1); + SW_RASTER_VARIANTS(SW_FWD_DECL) // NOLINT + #undef SW_FWD_DECL + + // Specialization generation via self-inclusion + + #define RLSW_TEMPLATE_RASTER_LINE BASE + #include __FILE__ // IWYU pragma: keep + #undef RLSW_TEMPLATE_RASTER_LINE + + #define RLSW_TEMPLATE_RASTER_LINE DEPTH + #define SW_ENABLE_DEPTH_TEST + #include __FILE__ + #undef SW_ENABLE_DEPTH_TEST + #undef RLSW_TEMPLATE_RASTER_LINE + + #define RLSW_TEMPLATE_RASTER_LINE BLEND + #define SW_ENABLE_BLEND + #include __FILE__ + #undef SW_ENABLE_BLEND + #undef RLSW_TEMPLATE_RASTER_LINE + + #define RLSW_TEMPLATE_RASTER_LINE DEPTH_BLEND + #define SW_ENABLE_DEPTH_TEST + #define SW_ENABLE_BLEND + #include __FILE__ + #undef SW_ENABLE_BLEND + #undef SW_ENABLE_DEPTH_TEST + #undef RLSW_TEMPLATE_RASTER_LINE + + // Dispatch table (auto-generated from SW_RASTER_VARIANTS) + #define SW_TABLE_ENTRY0(NAME, FLAGS) [FLAGS] = sw_raster_line_##NAME, + #define SW_TABLE_ENTRY1(NAME, FLAGS) [FLAGS] = sw_raster_line_thick_##NAME, + static const sw_raster_line_f SW_RASTER_LINE_FUNCS[] = { SW_RASTER_VARIANTS(SW_TABLE_ENTRY0) }; + static const sw_raster_line_f SW_RASTER_LINE_THICK_FUNCS[] = { SW_RASTER_VARIANTS(SW_TABLE_ENTRY1) }; + #undef SW_TABLE_ENTRY0 + #undef SW_TABLE_ENTRY1 + +#undef SW_RASTER_VARIANTS +#undef RLSW_TEMPLATE_RASTER_LINE_EXPANDING + +#endif // RLSW_TEMPLATE_RASTER_LINE_EXPANDING +//------------------------------------------------------------------------------------------- + +// Point rasterizer variant dispatch +//------------------------------------------------------------------------------------------- +#ifndef RLSW_TEMPLATE_RASTER_POINT_EXPANDING +#define RLSW_TEMPLATE_RASTER_POINT_EXPANDING + + // State mask to apply before indexing the dispatch table + #define SW_RASTER_POINT_STATE_MASK \ + (SW_STATE_DEPTH_TEST | SW_STATE_BLEND) + + // Single source of truth for all rasterizer specializations + // X(NAME, STATE_FLAGS) + #define SW_RASTER_VARIANTS(X) \ + X(BASE, 0) \ + X(DEPTH, SW_STATE_DEPTH_TEST) \ + X(BLEND, SW_STATE_BLEND) \ + X(DEPTH_BLEND, SW_STATE_DEPTH_TEST | SW_STATE_BLEND) + + // Forward declarations because clangd does not follow #include __FILE__ to avoid infinite recursion + // These declarations make all variants visible to static analysis tools without affecting compilation + #define SW_FWD_DECL(NAME, _FLAGS) \ + static void sw_raster_point_##NAME(const sw_vertex_t *v); + SW_RASTER_VARIANTS(SW_FWD_DECL) // NOLINT + #undef SW_FWD_DECL + + // Specialization generation via self-inclusion + + #define RLSW_TEMPLATE_RASTER_POINT BASE + #include __FILE__ // IWYU pragma: keep + #undef RLSW_TEMPLATE_RASTER_POINT + + #define RLSW_TEMPLATE_RASTER_POINT DEPTH + #define SW_ENABLE_DEPTH_TEST + #include __FILE__ + #undef SW_ENABLE_DEPTH_TEST + #undef RLSW_TEMPLATE_RASTER_POINT + + #define RLSW_TEMPLATE_RASTER_POINT BLEND + #define SW_ENABLE_BLEND + #include __FILE__ + #undef SW_ENABLE_BLEND + #undef RLSW_TEMPLATE_RASTER_POINT + + #define RLSW_TEMPLATE_RASTER_POINT DEPTH_BLEND + #define SW_ENABLE_DEPTH_TEST + #define SW_ENABLE_BLEND + #include __FILE__ + #undef SW_ENABLE_BLEND + #undef SW_ENABLE_DEPTH_TEST + #undef RLSW_TEMPLATE_RASTER_POINT + + // Dispatch table (auto-generated from SW_RASTER_VARIANTS) + #define SW_TABLE_ENTRY(NAME, FLAGS) [FLAGS] = sw_raster_point_##NAME, + static const sw_raster_point_f SW_RASTER_POINT_FUNCS[] = { + SW_RASTER_VARIANTS(SW_TABLE_ENTRY) + }; + #undef SW_TABLE_ENTRY + +#undef SW_RASTER_VARIANTS +#undef RLSW_TEMPLATE_RASTER_POINT_EXPANDING + +#endif // RLSW_TEMPLATE_RASTER_POINT_EXPANDING +//------------------------------------------------------------------------------------------- + +// Triangle rendering logic +//------------------------------------------------------------------------------------------- +static inline bool sw_triangle_face_culling(void) +{ + // NOTE: Face culling is done before clipping to avoid unnecessary computations + // To handle triangles crossing the w=0 plane correctly, + // the winding order test is performeed in homogeneous coordinates directly, + // before the perspective division (division by w) + // This test determines the orientation of the triangle in the (x,y,w) plane, + // which corresponds to the projected 2D winding order sign, + // even with negative w values + + // Preload homogeneous coordinates into local variables + const float *h0 = RLSW.vertexBuffer[0].homogeneous; + const float *h1 = RLSW.vertexBuffer[1].homogeneous; + const float *h2 = RLSW.vertexBuffer[2].homogeneous; + + // Compute a value proportional to the signed area in the projected 2D plane, + // calculated directly using homogeneous coordinates BEFORE division by w + // This is the determinant of the matrix formed by the (x, y, w) components + // of the vertices, which correctly captures the winding order in homogeneous + // space and its relationship to the projected 2D winding order, even with + // negative w values + // The determinant formula used here is: + // h0.x*(h1.y*h2.w - h2.y*h1.w) + + // h1.x*(h2.y*h0.w - h0.y*h2.w) + + // h2.x*(h0.y*h1.w - h1.y*h0.w) + + const float hSgnArea = + h0[0]*(h1[1]*h2[3] - h2[1]*h1[3]) + + h1[0]*(h2[1]*h0[3] - h0[1]*h2[3]) + + h2[0]*(h0[1]*h1[3] - h1[1]*h0[3]); + + // Discard the triangle if its winding order (determined by the sign + // of the homogeneous area/determinant) matches the culled direction + // A positive hSgnArea typically corresponds to a counter-clockwise + // winding in the projected space when all w > 0 + // This test is robust for points with w > 0 or w < 0, correctly + // capturing the change in orientation when crossing the w=0 plane + + // The culling logic remains the same based on the signed area/determinant + // A value of 0 for hSgnArea means the points are collinear in (x, y, w) + // space, which corresponds to a degenerate triangle projection + // Such triangles are typically not culled by this test (0 < 0 is false, 0 > 0 is false) + // and should be handled by the clipper if necessary + return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0) : (hSgnArea > 0); // Cull if winding is "clockwise" : "counter-clockwise" +} + +static void sw_triangle_clip_and_project(void) +{ + sw_vertex_t *polygon = RLSW.vertexBuffer; + int *vertexCounter = &RLSW.vertexCounter; + + if (sw_polygon_clip(polygon, vertexCounter)) + { + // Transformation to screen space and normalization + for (int i = 0; i < *vertexCounter; i++) + { + sw_vertex_t *v = &polygon[i]; + + // Calculation of the reciprocal of W for normalization + // as well as perspective-correct attributes + const float wRcp = 1.0f/v->homogeneous[3]; + v->homogeneous[3] = wRcp; + + // Division of XYZ coordinates by weight + v->homogeneous[0] *= wRcp; + v->homogeneous[1] *= wRcp; + v->homogeneous[2] *= wRcp; + + // Division of texture coordinates (perspective-correct) + v->texcoord[0] *= wRcp; + v->texcoord[1] *= wRcp; + + // Division of colors (perspective-correct) + v->color[0] *= wRcp; + v->color[1] *= wRcp; + v->color[2] *= wRcp; + v->color[3] *= wRcp; + + // Transformation to screen space + sw_project_ndc_to_screen(v->screen, v->homogeneous); + } + } +} + +static void sw_triangle_render(uint32_t state) +{ + if (RLSW.stateFlags & SW_STATE_CULL_FACE) + { + if (!sw_triangle_face_culling()) return; + } + + sw_triangle_clip_and_project(); + if (RLSW.vertexCounter < 3) return; + + state &= SW_RASTER_TRIANGLE_STATE_MASK; + + for (int i = 0; i < RLSW.vertexCounter - 2; i++) + { + SW_RASTER_TRIANGLE_FUNCS[state]( + &RLSW.vertexBuffer[0], + &RLSW.vertexBuffer[i + 1], + &RLSW.vertexBuffer[i + 2] + ); + } +} +//------------------------------------------------------------------------------------------- + +// Quad rendering logic +//------------------------------------------------------------------------------------------- +static inline bool sw_quad_face_culling(void) +{ + // NOTE: Face culling is done before clipping to avoid unnecessary computations + // To handle quads crossing the w=0 plane correctly, + // the winding order test is performed in homogeneous coordinates directly, + // before the perspective division (division by w) + // For a convex quad with vertices P0, P1, P2, P3 in sequential order, + // the winding order of the quad is the same as the winding order + // of the triangle P0 P1 P2. The homogeneous triangle is used on + // winding test on this first triangle + + // Preload homogeneous coordinates into local variables + const float *h0 = RLSW.vertexBuffer[0].homogeneous; + const float *h1 = RLSW.vertexBuffer[1].homogeneous; + const float *h2 = RLSW.vertexBuffer[2].homogeneous; + + // NOTE: h3 is not needed for this test + // const float *h3 = RLSW.vertexBuffer[3].homogeneous; + + // Compute a value proportional to the signed area of the triangle P0 P1 P2 + // in the projected 2D plane, calculated directly using homogeneous coordinates + // BEFORE division by w + // This is the determinant of the matrix formed by the (x, y, w) components + // of the vertices P0, P1, and P2. Its sign correctly indicates the winding order + // in homogeneous space and its relationship to the projected 2D winding order, + // even with negative w values + // The determinant formula used here is: + // h0.x*(h1.y*h2.w - h2.y*h1.w) + + // h1.x*(h2.y*h0.w - h0.y*h2.w) + + // h2.x*(h0.y*h1.w - h1.y*h0.w) + + const float hSgnArea = + h0[0]*(h1[1]*h2[3] - h2[1]*h1[3]) + + h1[0]*(h2[1]*h0[3] - h0[1]*h2[3]) + + h2[0]*(h0[1]*h1[3] - h1[1]*h0[3]); + + // Perform face culling based on the winding order determined by the sign + // of the homogeneous area/determinant of triangle P0 P1 P2 + // This test is robust for points with w > 0 or w < 0 within the triangle, + // correctly capturing the change in orientation when crossing the w=0 plane + + // A positive hSgnArea typically corresponds to a counter-clockwise + // winding in the projected space when all w > 0 + // A value of 0 for hSgnArea means P0, P1, P2 are collinear in (x, y, w) + // space, which corresponds to a degenerate triangle projection + // Such quads might also be degenerate or non-planar. They are typically + // not culled by this test (0 < 0 is false, 0 > 0 is false) + // and should be handled by the clipper if necessary + + return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0.0f) : (hSgnArea > 0.0f); // Cull if winding is "clockwise" : "counter-clockwise" +} + +static void sw_quad_clip_and_project(void) +{ + sw_vertex_t *polygon = RLSW.vertexBuffer; + int *vertexCounter = &RLSW.vertexCounter; + + if (sw_polygon_clip(polygon, vertexCounter)) + { + // Transformation to screen space and normalization + for (int i = 0; i < *vertexCounter; i++) + { + sw_vertex_t *v = &polygon[i]; + + // Calculation of the reciprocal of W for normalization + // as well as perspective-correct attributes + const float wRcp = 1.0f/v->homogeneous[3]; + v->homogeneous[3] = wRcp; + + // Division of XYZ coordinates by weight + v->homogeneous[0] *= wRcp; + v->homogeneous[1] *= wRcp; + v->homogeneous[2] *= wRcp; + + // Division of texture coordinates (perspective-correct) + v->texcoord[0] *= wRcp; + v->texcoord[1] *= wRcp; + + // Division of colors (perspective-correct) + v->color[0] *= wRcp; + v->color[1] *= wRcp; + v->color[2] *= wRcp; + v->color[3] *= wRcp; + + // Transformation to screen space + sw_project_ndc_to_screen(v->screen, v->homogeneous); + } + } +} + +static bool sw_quad_is_axis_aligned(void) +{ + // Reject quads with perspective projection + // The fast path assumes affine (non-perspective) quads, + // so it's required for all vertices to have homogeneous w = 1.0 + for (int i = 0; i < 4; i++) + { + if (RLSW.vertexBuffer[i].homogeneous[3] != 1.0f) return false; + } + + // Epsilon tolerance in screen space (pixels) + const float epsilon = 0.5f; + + // Fetch screen-space positions for the four quad vertices + const float *p0 = RLSW.vertexBuffer[0].screen; + const float *p1 = RLSW.vertexBuffer[1].screen; + const float *p2 = RLSW.vertexBuffer[2].screen; + const float *p3 = RLSW.vertexBuffer[3].screen; + + // Compute edge vectors between consecutive vertices + // These define the four sides of the quad in screen space + float dx01 = p1[0] - p0[0], dy01 = p1[1] - p0[1]; + float dx12 = p2[0] - p1[0], dy12 = p2[1] - p1[1]; + float dx23 = p3[0] - p2[0], dy23 = p3[1] - p2[1]; + float dx30 = p0[0] - p3[0], dy30 = p0[1] - p3[1]; + + // Each edge must be either horizontal or vertical within epsilon tolerance + // If any edge deviates significantly from either axis, the quad is not axis-aligned + if (!((fabsf(dy01) < epsilon) || (fabsf(dx01) < epsilon))) return false; + if (!((fabsf(dy12) < epsilon) || (fabsf(dx12) < epsilon))) return false; + if (!((fabsf(dy23) < epsilon) || (fabsf(dx23) < epsilon))) return false; + if (!((fabsf(dy30) < epsilon) || (fabsf(dx30) < epsilon))) return false; + + return true; +} + +static void sw_quad_render(uint32_t state) +{ + if (RLSW.stateFlags & SW_STATE_CULL_FACE) + { + if (!sw_quad_face_culling()) return; + } + + sw_quad_clip_and_project(); + if (RLSW.vertexCounter < 3) return; + + state &= SW_RASTER_QUAD_STATE_MASK; + + if ((RLSW.vertexCounter == 4) && sw_quad_is_axis_aligned()) + { + SW_RASTER_QUAD_FUNCS[state]( + &RLSW.vertexBuffer[0], + &RLSW.vertexBuffer[1], + &RLSW.vertexBuffer[2], + &RLSW.vertexBuffer[3] + ); + } + else + { + for (int i = 0; i < RLSW.vertexCounter - 2; i++) + { + SW_RASTER_TRIANGLE_FUNCS[state]( + &RLSW.vertexBuffer[0], + &RLSW.vertexBuffer[i + 1], + &RLSW.vertexBuffer[i + 2] + ); + } + } +} +//------------------------------------------------------------------------------------------- + +// Line rendering logic +//------------------------------------------------------------------------------------------- +static inline bool sw_line_clip_coord(float q, float p, float *t0, float *t1) +{ + if (fabsf(p) < SW_CLIP_EPSILON) + { + // Check if the line is entirely outside the window + if (q < -SW_CLIP_EPSILON) return 0; // Completely outside + return 1; // Completely inside or on the edges + } + + const float r = q/p; + + if (p < 0) + { + if (r > *t1) return 0; + if (r > *t0) *t0 = r; + } + else + { + if (r < *t0) return 0; + if (r < *t1) *t1 = r; + } + + return 1; +} + +static bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1) +{ + float t0 = 0.0f, t1 = 1.0f; + float dH[4], dC[4]; + + for (int i = 0; i < 4; i++) + { + dH[i] = v1->homogeneous[i] - v0->homogeneous[i]; + dC[i] = v1->color[i] - v0->color[i]; + } + + // Clipping Liang-Barsky + if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[0], -dH[3] + dH[0], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[0], -dH[3] - dH[0], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[1], -dH[3] + dH[1], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[1], -dH[3] - dH[1], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[2], -dH[3] + dH[2], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[2], -dH[3] - dH[2], &t0, &t1)) return false; + + // Clipping Scissor + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { + if (!sw_line_clip_coord(v0->homogeneous[0] - RLSW.scClipMin[0]*v0->homogeneous[3], RLSW.scClipMin[0]*dH[3] - dH[0], &t0, &t1)) return false; + if (!sw_line_clip_coord(RLSW.scClipMax[0]*v0->homogeneous[3] - v0->homogeneous[0], dH[0] - RLSW.scClipMax[0]*dH[3], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->homogeneous[1] - RLSW.scClipMin[1]*v0->homogeneous[3], RLSW.scClipMin[1]*dH[3] - dH[1], &t0, &t1)) return false; + if (!sw_line_clip_coord(RLSW.scClipMax[1]*v0->homogeneous[3] - v0->homogeneous[1], dH[1] - RLSW.scClipMax[1]*dH[3], &t0, &t1)) return false; + } + + // Interpolation of new coordinates + if (t1 < 1.0f) + { + for (int i = 0; i < 4; i++) + { + v1->homogeneous[i] = v0->homogeneous[i] + t1*dH[i]; + v1->color[i] = v0->color[i] + t1*dC[i]; + } + } + + if (t0 > 0.0f) + { + for (int i = 0; i < 4; i++) + { + v0->homogeneous[i] += t0*dH[i]; + v0->color[i] += t0*dC[i]; + } + } + + return true; +} + +static bool sw_line_clip_and_project(sw_vertex_t *v0, sw_vertex_t *v1) +{ + if (!sw_line_clip(v0, v1)) return false; + + // Convert homogeneous coordinates to NDC + v0->homogeneous[3] = 1.0f/v0->homogeneous[3]; + v1->homogeneous[3] = 1.0f/v1->homogeneous[3]; + for (int i = 0; i < 3; i++) + { + v0->homogeneous[i] *= v0->homogeneous[3]; + v1->homogeneous[i] *= v1->homogeneous[3]; + } + + // Convert NDC coordinates to screen space + sw_project_ndc_to_screen(v0->screen, v0->homogeneous); + sw_project_ndc_to_screen(v1->screen, v1->homogeneous); + + // NDC +1.0 projects to exactly (width + 0.5f), which truncates out of bounds + // The clamp is at most 0.5px on a boundary endpoint, it's visually imperceptible + v0->screen[0] = sw_clamp(v0->screen[0], 0.0f, (float)(RLSW.colorBuffer->width - 1) + 0.5f); + v0->screen[1] = sw_clamp(v0->screen[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f); + v1->screen[0] = sw_clamp(v1->screen[0], 0.0f, (float)(RLSW.colorBuffer->width - 1) + 0.5f); + v1->screen[1] = sw_clamp(v1->screen[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f); + + return true; +} + +static void sw_line_render(uint32_t state, sw_vertex_t *vertices) +{ + if (!sw_line_clip_and_project(&vertices[0], &vertices[1])) return; + + state &= SW_RASTER_LINE_STATE_MASK; + + if (RLSW.lineWidth >= 2.0f) + { + SW_RASTER_LINE_THICK_FUNCS[state](&vertices[0], &vertices[1]); + } + else + { + SW_RASTER_LINE_FUNCS[state](&vertices[0], &vertices[1]); + } +} +//------------------------------------------------------------------------------------------- + +// Point rendering logic +//------------------------------------------------------------------------------------------- +static bool sw_point_clip_and_project(sw_vertex_t *v) +{ + if (v->homogeneous[3] != 1.0f) + { + for (int_fast8_t i = 0; i < 3; i++) + { + if ((v->homogeneous[i] < -v->homogeneous[3]) || (v->homogeneous[i] > v->homogeneous[3])) return false; + } + + v->homogeneous[3] = 1.0f/v->homogeneous[3]; + v->homogeneous[0] *= v->homogeneous[3]; + v->homogeneous[1] *= v->homogeneous[3]; + v->homogeneous[2] *= v->homogeneous[3]; + } + + sw_project_ndc_to_screen(v->screen, v->homogeneous); + + int min[2] = { 0, 0 }; + int max[2] = { RLSW.colorBuffer->width, RLSW.colorBuffer->height }; + + if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + { + min[0] = sw_clamp_int(RLSW.scMin[0], 0, RLSW.colorBuffer->width); + min[1] = sw_clamp_int(RLSW.scMin[1], 0, RLSW.colorBuffer->height); + max[0] = sw_clamp_int(RLSW.scMax[0], 0, RLSW.colorBuffer->width); + max[1] = sw_clamp_int(RLSW.scMax[1], 0, RLSW.colorBuffer->height); + } + + bool insideX = (v->screen[0] - RLSW.pointRadius < max[0]) && (v->screen[0] + RLSW.pointRadius > min[0]); + bool insideY = (v->screen[1] - RLSW.pointRadius < max[1]) && (v->screen[1] + RLSW.pointRadius > min[1]); + + return (insideX && insideY); +} + +static void sw_point_render(uint32_t state, sw_vertex_t *v) +{ + if (!sw_point_clip_and_project(v)) return; + state &= SW_RASTER_POINT_STATE_MASK; + SW_RASTER_POINT_FUNCS[state](v); +} +//------------------------------------------------------------------------------------------- + +// Polygon modes rendering logic +//------------------------------------------------------------------------------------------- +static inline void sw_poly_point_render(uint32_t state) +{ + for (int i = 0; i < RLSW.vertexCounter; i++) sw_point_render(state, &RLSW.vertexBuffer[i]); +} + +static inline void sw_poly_line_render(uint32_t state) +{ + const sw_vertex_t *vertices = RLSW.vertexBuffer; + int cm1 = RLSW.vertexCounter - 1; + + for (int i = 0; i < cm1; i++) + { + sw_vertex_t verts[2] = { vertices[i], vertices[i + 1] }; + sw_line_render(state, verts); + } + + sw_vertex_t verts[2] = { vertices[cm1], vertices[0] }; + sw_line_render(state, verts); +} + +static inline void sw_poly_fill_render(uint32_t state) +{ + switch (RLSW.drawMode) + { + case SW_POINTS: sw_point_render(state, &RLSW.vertexBuffer[0]); break; + case SW_LINES: sw_line_render(state, RLSW.vertexBuffer); break; + case SW_TRIANGLES: sw_triangle_render(state); break; + case SW_QUADS: sw_quad_render(state); break; + default: break; + } +} +//------------------------------------------------------------------------------------------- + +// Immediate rendering logic +//------------------------------------------------------------------------------------------- +static void sw_immediate_push_vertex(const float position[4], const float color[4], const float texcoord[2]) +{ + // Check if we are in a valid draw mode + if (!sw_is_draw_mode_valid(RLSW.drawMode)) + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + + // Copy the attributes in the current vertex + sw_vertex_t *vertex = &RLSW.vertexBuffer[RLSW.vertexCounter++]; + for (int i = 0; i < 4; i++) + { + vertex->position[i] = position[i]; + if (i < 2) vertex->texcoord[i] = texcoord[i]; + vertex->color[i] = color[i]; + } + + // Calculate homogeneous coordinates + const float *m = RLSW.matMVP, *v = vertex->position; + vertex->homogeneous[0] = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3]; + vertex->homogeneous[1] = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3]; + vertex->homogeneous[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3]; + vertex->homogeneous[3] = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3]; + + // Immediate rendering of the primitive if the required number is reached + if (RLSW.vertexCounter == SW_PRIMITIVE_VERTEX_COUNT[RLSW.drawMode]) + { + // Restricts the pipeline state to the minimum required + uint32_t state = RLSW.stateFlags; + if (!sw_is_texture_complete(RLSW.depthBuffer)) state &= ~SW_STATE_DEPTH_TEST; + if (!sw_is_texture_complete(RLSW.boundTexture)) state &= ~SW_STATE_TEXTURE_2D; + if ((RLSW.srcFactor == SW_ONE) && (RLSW.dstFactor == SW_ZERO)) state &= ~SW_STATE_BLEND; + + switch (RLSW.polyMode) + { + case SW_FILL: sw_poly_fill_render(state); break; + case SW_LINE: sw_poly_line_render(state); break; + case SW_POINT: sw_poly_point_render(state); break; + default: break; + } + + RLSW.vertexCounter = 0; + } +} + //------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- @@ -3546,20 +3917,35 @@ static inline bool sw_is_blend_dst_factor_valid(int blend) //---------------------------------------------------------------------------------- bool swInit(int w, int h) { - if (!sw_framebuffer_load(w, h)) { swClose(); return false; } + if (!sw_default_framebuffer_alloc(&RLSW.framebuffer, w, h)) + { + swClose(); + return false; + } + + if (!sw_pool_init(&RLSW.framebufferPool, SW_MAX_FRAMEBUFFERS, sizeof(sw_framebuffer_t))) + { + swClose(); + return false; + } + + if (!sw_pool_init(&RLSW.texturePool, SW_MAX_TEXTURES, sizeof(sw_texture_t))) + { + swClose(); + return false; + } + + RLSW.colorBuffer = &RLSW.framebuffer.color; + RLSW.depthBuffer = &RLSW.framebuffer.depth; swViewport(0, 0, w, h); swScissor(0, 0, w, h); - RLSW.loadedTextures = (sw_texture_t *)SW_MALLOC(SW_MAX_TEXTURES*sizeof(sw_texture_t)); - if (RLSW.loadedTextures == NULL) { swClose(); return false; } - - RLSW.freeTextureIds = (uint32_t *)SW_MALLOC(SW_MAX_TEXTURES*sizeof(uint32_t)); - if (RLSW.loadedTextures == NULL) { swClose(); return false; } - - const float clearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; - sw_framebuffer_write_color(&RLSW.clearValue, clearColor); - sw_framebuffer_write_depth(&RLSW.clearValue, 1.0f); + RLSW.clearColor[0] = 0.0f; + RLSW.clearColor[1] = 0.0f; + RLSW.clearColor[2] = 0.0f; + RLSW.clearColor[3] = 1.0f; + RLSW.clearDepth = 1.0f; RLSW.currentMatrixMode = SW_MODELVIEW; RLSW.currentMatrix = &RLSW.stackModelview[0]; @@ -3588,30 +3974,10 @@ bool swInit(int w, int h) RLSW.srcFactorFunc = sw_factor_src_alpha; RLSW.dstFactorFunc = sw_factor_one_minus_src_alpha; + RLSW.drawMode = SW_DRAW_INVALID; RLSW.polyMode = SW_FILL; RLSW.cullFace = SW_BACK; - static uint32_t defaultTex[3*2*2] = { - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF, - 0xFFFFFFFF - }; - - RLSW.loadedTextures[0].pixels = (uint8_t*)defaultTex; - RLSW.loadedTextures[0].width = 2; - RLSW.loadedTextures[0].height = 2; - RLSW.loadedTextures[0].wMinus1 = 1; - RLSW.loadedTextures[0].hMinus1 = 1; - RLSW.loadedTextures[0].minFilter = SW_NEAREST; - RLSW.loadedTextures[0].magFilter = SW_NEAREST; - RLSW.loadedTextures[0].sWrap = SW_REPEAT; - RLSW.loadedTextures[0].tWrap = SW_REPEAT; - RLSW.loadedTextures[0].tx = 0.5f; - RLSW.loadedTextures[0].ty = 0.5f; - - RLSW.loadedTextureCount = 1; - SW_LOG("INFO: RLSW: Software renderer initialized successfully\n"); #if defined(SW_HAS_FMA_AVX) && defined(SW_HAS_FMA_AVX2) SW_LOG("INFO: RLSW: Using SIMD instructions: FMA AVX\n"); @@ -3634,118 +4000,81 @@ bool swInit(int w, int h) void swClose(void) { - // NOTE: Starts at texture 1, texture 0 does not have to be freed - for (int i = 1; i < RLSW.loadedTextureCount; i++) + for (int i = 1; i < RLSW.texturePool.watermark; i++) { - if (sw_is_texture_valid(i)) + if (RLSW.texturePool.gen[i] & SW_POOL_SLOT_LIVE) { - SW_FREE(RLSW.loadedTextures[i].pixels); + sw_texture_free((sw_texture_t *)RLSW.texturePool.data + i); } } - SW_FREE(RLSW.framebuffer.pixels); - SW_FREE(RLSW.loadedTextures); - SW_FREE(RLSW.freeTextureIds); + sw_pool_destroy(&RLSW.texturePool); + sw_pool_destroy(&RLSW.framebufferPool); + sw_default_framebuffer_free(&RLSW.framebuffer); RLSW = SW_CURLY_INIT(sw_context_t) { 0 }; } -bool swResizeFramebuffer(int w, int h) +bool swResize(int w, int h) { - return sw_framebuffer_resize(w, h); + return sw_default_framebuffer_alloc(&RLSW.framebuffer, w, h); } -void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels) +void swReadPixels(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels) { - sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_get_pixel_format(format, type); + // REVIEW: Handle depth buffer copy here or consider it as an error ? + if (format == SW_DEPTH_COMPONENT) { RLSW.errCode = SW_INVALID_ENUM; return; } + + sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_pixel_get_format(format, type); + if (pFormat <= SW_PIXELFORMAT_UNKNOWN) { RLSW.errCode = SW_INVALID_ENUM; return; } if (w <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; } if (h <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; } - if (w > RLSW.framebuffer.width) w = RLSW.framebuffer.width; - if (h > RLSW.framebuffer.height) h = RLSW.framebuffer.height; + if (w > RLSW.colorBuffer->width) w = RLSW.colorBuffer->width; + if (h > RLSW.colorBuffer->height) h = RLSW.colorBuffer->height; - x = sw_clampi(x, 0, w); - y = sw_clampi(y, 0, h); + x = sw_clamp_int(x, 0, w); + y = sw_clamp_int(y, 0, h); if ((x >= w) || (y >= h)) return; - if ((x == 0) && (y == 0) && (w == RLSW.framebuffer.width) && (h == RLSW.framebuffer.height)) + if ((pFormat == SW_FRAMEBUFFER_COLOR_FORMAT) && (x == 0) && (y == 0) && (w == RLSW.colorBuffer->width) && (h == RLSW.colorBuffer->height)) { - #if SW_COLOR_BUFFER_BITS == 32 - if (pFormat == SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) - { - sw_framebuffer_copy_fast(pixels); - return; - } - #elif SW_COLOR_BUFFER_BITS == 16 - if (pFormat == SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5) - { - sw_framebuffer_copy_fast(pixels); - return; - } - #endif + sw_framebuffer_output_fast(pixels, RLSW.colorBuffer); } - - switch (pFormat) + else { - case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, (uint8_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, (uint8_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_copy_to_R5G6B5(x, y, w, h, (uint16_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_copy_to_R8G8B8(x, y, w, h, (uint8_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_copy_to_R5G5B5A1(x, y, w, h, (uint16_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_copy_to_R4G4B4A4(x, y, w, h, (uint16_t *)pixels); break; - //case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_copy_to_R8G8B8A8(x, y, w, h, (uint8_t *)pixels); break; - // Below: not implemented - case SW_PIXELFORMAT_UNCOMPRESSED_R32: - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: - case SW_PIXELFORMAT_UNCOMPRESSED_R16: - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - default: RLSW.errCode = SW_INVALID_ENUM; break; + sw_framebuffer_output_copy(pixels, RLSW.colorBuffer, x, y, w, h, pFormat); } } -void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels) +void swBlitPixels(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels) { - sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_get_pixel_format(format, type); + // REVIEW: Handle depth buffer copy here or consider it as an error ? + if (format == SW_DEPTH_COMPONENT) { RLSW.errCode = SW_INVALID_ENUM; return; } + + sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_pixel_get_format(format, type); + if (pFormat <= SW_PIXELFORMAT_UNKNOWN) { RLSW.errCode = SW_INVALID_ENUM; return; } if (wSrc <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; } if (hSrc <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; } - if (wSrc > RLSW.framebuffer.width) wSrc = RLSW.framebuffer.width; - if (hSrc > RLSW.framebuffer.height) hSrc = RLSW.framebuffer.height; + if (wSrc > RLSW.colorBuffer->width) wSrc = RLSW.colorBuffer->width; + if (hSrc > RLSW.colorBuffer->height) hSrc = RLSW.colorBuffer->height; - xSrc = sw_clampi(xSrc, 0, wSrc); - ySrc = sw_clampi(ySrc, 0, hSrc); + xSrc = sw_clamp_int(xSrc, 0, wSrc); + ySrc = sw_clamp_int(ySrc, 0, hSrc); // Check if the sizes are identical after clamping the source to avoid unexpected issues // TODO: REVIEW: This repeats the operations if true, so a copy function can be made without these checks - if (xDst == xSrc && yDst == ySrc && wDst == wSrc && hDst == hSrc) + if ((xDst == xSrc) && (yDst == ySrc) && (wDst == wSrc) && (hDst == hSrc)) { - swCopyFramebuffer(xSrc, ySrc, wSrc, hSrc, format, type, pixels); + swReadPixels(xSrc, ySrc, wSrc, hSrc, format, type, pixels); } - - switch (pFormat) + else { - case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_blit_to_R5G6B5(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_blit_to_R8G8B8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_blit_to_R5G5B5A1(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_blit_to_R4G4B4A4(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break; - case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_blit_to_R8G8B8A8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break; - // Below: not implemented - case SW_PIXELFORMAT_UNCOMPRESSED_R32: - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: - case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: - case SW_PIXELFORMAT_UNCOMPRESSED_R16: - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: - case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: - default: - RLSW.errCode = SW_INVALID_ENUM; - break; + sw_framebuffer_output_blit(pixels, RLSW.colorBuffer, xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pFormat); } } @@ -3782,6 +4111,7 @@ void swGetIntegerv(SWget name, int *v) case SW_MODELVIEW_STACK_DEPTH: *v = SW_MODELVIEW_STACK_DEPTH; break; case SW_PROJECTION_STACK_DEPTH: *v = SW_PROJECTION_STACK_DEPTH; break; case SW_TEXTURE_STACK_DEPTH: *v = SW_TEXTURE_STACK_DEPTH; break; + case SW_DRAW_FRAMEBUFFER_BINDING: *v = RLSW.boundFramebufferId; break; default: RLSW.errCode = SW_INVALID_ENUM; break; } } @@ -3792,11 +4122,14 @@ void swGetFloatv(SWget name, float *v) { case SW_COLOR_CLEAR_VALUE: { - sw_framebuffer_read_color(v, &RLSW.clearValue); + v[0] = RLSW.clearColor[0]; + v[1] = RLSW.clearColor[1]; + v[2] = RLSW.clearColor[2]; + v[3] = RLSW.clearColor[3]; } break; case SW_DEPTH_CLEAR_VALUE: { - v[0] = sw_framebuffer_read_depth(&RLSW.clearValue); + v[0] = RLSW.clearDepth; } break; case SW_CURRENT_COLOR: { @@ -3876,11 +4209,6 @@ void swViewport(int x, int y, int width, int height) RLSW.vpCenter[0] = (float)x + RLSW.vpHalf[0]; RLSW.vpCenter[1] = (float)y + RLSW.vpHalf[1]; - - RLSW.vpMin[0] = sw_clampi(x, 0, RLSW.framebuffer.width - 1); - RLSW.vpMin[1] = sw_clampi(y, 0, RLSW.framebuffer.height - 1); - RLSW.vpMax[0] = sw_clampi(x + width, 0, RLSW.framebuffer.width - 1); - RLSW.vpMax[1] = sw_clampi(y + height, 0, RLSW.framebuffer.height - 1); } void swScissor(int x, int y, int width, int height) @@ -3891,10 +4219,10 @@ void swScissor(int x, int y, int width, int height) return; } - RLSW.scMin[0] = sw_clampi(x, 0, RLSW.framebuffer.width - 1); - RLSW.scMin[1] = sw_clampi(y, 0, RLSW.framebuffer.height - 1); - RLSW.scMax[0] = sw_clampi(x + width, 0, RLSW.framebuffer.width - 1); - RLSW.scMax[1] = sw_clampi(y + height, 0, RLSW.framebuffer.height - 1); + RLSW.scMin[0] = x; + RLSW.scMin[1] = y; + RLSW.scMax[0] = x + width; + RLSW.scMax[1] = y + height; RLSW.scClipMin[0] = (2.0f*(float)RLSW.scMin[0]/(float)RLSW.vpSize[0]) - 1.0f; RLSW.scClipMax[0] = (2.0f*(float)RLSW.scMax[0]/(float)RLSW.vpSize[0]) - 1.0f; @@ -3904,30 +4232,31 @@ void swScissor(int x, int y, int width, int height) void swClearColor(float r, float g, float b, float a) { - float v[4] = { r, g, b, a }; - sw_framebuffer_write_color(&RLSW.clearValue, v); + RLSW.clearColor[0] = r; + RLSW.clearColor[1] = g; + RLSW.clearColor[2] = b; + RLSW.clearColor[3] = a; } void swClearDepth(float depth) { - sw_framebuffer_write_depth(&RLSW.clearValue, depth); + RLSW.clearDepth = depth; } void swClear(uint32_t bitmask) { - int size = RLSW.framebuffer.width*RLSW.framebuffer.height; + if (!sw_is_ready_to_render()) return; - if ((bitmask & (SW_COLOR_BUFFER_BIT | SW_DEPTH_BUFFER_BIT)) == (SW_COLOR_BUFFER_BIT | SW_DEPTH_BUFFER_BIT)) + if ((bitmask & (SW_COLOR_BUFFER_BIT)) && (RLSW.colorBuffer != NULL) && (RLSW.colorBuffer->pixels != NULL)) { - sw_framebuffer_fill(RLSW.framebuffer.pixels, size, RLSW.clearValue); + int size = RLSW.colorBuffer->width*RLSW.colorBuffer->height; + sw_framebuffer_fill_color(RLSW.colorBuffer, RLSW.clearColor); } - else if (bitmask & (SW_COLOR_BUFFER_BIT)) + + if ((bitmask & (SW_DEPTH_BUFFER_BIT)) && (RLSW.depthBuffer != NULL) && (RLSW.depthBuffer->pixels != NULL)) { - sw_framebuffer_fill_color(RLSW.framebuffer.pixels, size, RLSW.clearValue.color); - } - else if (bitmask & SW_DEPTH_BUFFER_BIT) - { - sw_framebuffer_fill_depth(RLSW.framebuffer.pixels, size, RLSW.clearValue.depth); + int size = RLSW.depthBuffer->width*RLSW.depthBuffer->height; + sw_framebuffer_fill_depth(RLSW.depthBuffer, RLSW.clearDepth); } } @@ -4277,6 +4606,13 @@ void swOrtho(double left, double right, double bottom, double top, double znear, void swBegin(SWdraw mode) { + // Check if we can render + if (!sw_is_ready_to_render()) + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + // Check if the draw mode is valid if (!sw_is_draw_mode_valid(mode)) { @@ -4294,15 +4630,6 @@ void swBegin(SWdraw mode) RLSW.isDirtyMVP = false; } - // Obtain the number of vertices needed for this primitive - switch (mode) - { - case SW_POINTS: RLSW.reqVertices = 1; break; - case SW_LINES: RLSW.reqVertices = 2; break; - case SW_TRIANGLES: RLSW.reqVertices = 3; break; - case SW_QUADS: RLSW.reqVertices = 4; break; - } - // Initialize required values RLSW.vertexCounter = 0; RLSW.drawMode = mode; @@ -4310,7 +4637,7 @@ void swBegin(SWdraw mode) void swEnd(void) { - RLSW.drawMode = (SWdraw)0; + RLSW.drawMode = SW_DRAW_INVALID; } void swVertex2i(int x, int y) @@ -4477,7 +4804,7 @@ void swBindArray(SWarray type, void *buffer) void swDrawArrays(SWdraw mode, int offset, int count) { - if (RLSW.array.positions == 0) + if ((!sw_is_ready_to_render()) || (RLSW.array.positions == NULL)) { RLSW.errCode = SW_INVALID_OPERATION; return; @@ -4546,13 +4873,13 @@ void swDrawArrays(SWdraw mode, int offset, int count) void swDrawElements(SWdraw mode, int count, int type, const void *indices) { - if (RLSW.array.positions == 0) + if ((!sw_is_ready_to_render()) || (RLSW.array.positions == NULL)) { RLSW.errCode = SW_INVALID_OPERATION; return; } - if (count < 0) + if ((count < 0) || (indices == NULL)) { RLSW.errCode = SW_INVALID_VALUE; return; @@ -4640,162 +4967,1014 @@ void swDrawElements(SWdraw mode, int count, int type, const void *indices) swEnd(); } -void swGenTextures(int count, uint32_t *textures) +void swGenTextures(int count, sw_handle_t *textures) { - if ((count == 0) || (textures == NULL)) return; + if (!count || !textures) return; for (int i = 0; i < count; i++) { - if (RLSW.loadedTextureCount >= SW_MAX_TEXTURES) - { - RLSW.errCode = SW_STACK_OVERFLOW; // WARNING: Out of memory, not really stack overflow - return; - } - - uint32_t id = 0; - if (RLSW.freeTextureIdCount > 0) id = RLSW.freeTextureIds[--RLSW.freeTextureIdCount]; - else id = RLSW.loadedTextureCount++; - - RLSW.loadedTextures[id] = RLSW.loadedTextures[0]; - textures[i] = id; + sw_handle_t h = sw_pool_alloc(&RLSW.texturePool); + if (h == SW_HANDLE_NULL) { RLSW.errCode = SW_OUT_OF_MEMORY; return; } + textures[i] = h; } } -void swDeleteTextures(int count, uint32_t *textures) +void swDeleteTextures(int count, sw_handle_t *textures) { - if ((count == 0) || (textures == NULL)) return; + if (!count || !textures) return; for (int i = 0; i < count; i++) { - if (!sw_is_texture_valid(textures[i])) - { - RLSW.errCode = SW_INVALID_VALUE; - continue; - } + sw_texture_t *tex = sw_pool_get(&RLSW.texturePool, textures[i]); + if (!tex) { RLSW.errCode = SW_INVALID_VALUE; continue; } + if (tex == RLSW.boundTexture) RLSW.boundTexture = NULL; + if (tex == RLSW.colorBuffer) RLSW.colorBuffer = NULL; + if (tex == RLSW.depthBuffer) RLSW.depthBuffer = NULL; - SW_FREE(RLSW.loadedTextures[textures[i]].pixels); + sw_texture_free(tex); + *tex = (sw_texture_t) { 0 }; - RLSW.loadedTextures[textures[i]].pixels = NULL; - RLSW.freeTextureIds[RLSW.freeTextureIdCount++] = textures[i]; + sw_pool_free(&RLSW.texturePool, textures[i]); } } +void swBindTexture(sw_handle_t id) +{ + if (id == SW_HANDLE_NULL) { RLSW.boundTexture = NULL; return; } + if (!sw_is_texture_valid(id)) { RLSW.errCode = SW_INVALID_VALUE; return; } + + RLSW.boundTexture = sw_pool_get(&RLSW.texturePool, id); +} + +void swTexStorage2D(int width, int height, SWinternalformat format) +{ + if (RLSW.boundTexture == NULL) return; + + int pixelFormat = SW_PIXELFORMAT_UNKNOWN; + switch (format) + { + case SW_LUMINANCE8: pixelFormat = SW_PIXELFORMAT_COLOR_GRAYSCALE; break; + case SW_LUMINANCE8_ALPHA8: pixelFormat = SW_PIXELFORMAT_COLOR_GRAYALPHA; break; + case SW_R3_G3_B2: pixelFormat = SW_PIXELFORMAT_COLOR_R3G3B2; break; + case SW_RGB8: pixelFormat = SW_PIXELFORMAT_COLOR_R8G8B8; break; + case SW_RGBA4: pixelFormat = SW_PIXELFORMAT_COLOR_R4G4B4A4; break; + case SW_RGB5_A1: pixelFormat = SW_PIXELFORMAT_COLOR_R5G5B5A1; break; + case SW_RGBA8: pixelFormat = SW_PIXELFORMAT_COLOR_R8G8B8A8; break; + case SW_R16F: pixelFormat = SW_PIXELFORMAT_COLOR_R16; break; + case SW_RGB16F: pixelFormat = SW_PIXELFORMAT_COLOR_R16G16B16; break; + case SW_RGBA16F: pixelFormat = SW_PIXELFORMAT_COLOR_R16G16B16A16; break; + case SW_R32F: pixelFormat = SW_PIXELFORMAT_COLOR_R32; break; + case SW_RGB32F: pixelFormat = SW_PIXELFORMAT_COLOR_R32G32B32; break; + case SW_RGBA32F: pixelFormat = SW_PIXELFORMAT_COLOR_R32G32B32A32; break; + case SW_DEPTH_COMPONENT16: pixelFormat = SW_PIXELFORMAT_DEPTH_D16; break; + case SW_DEPTH_COMPONENT24: pixelFormat = SW_PIXELFORMAT_DEPTH_D32; break; + case SW_DEPTH_COMPONENT32: pixelFormat = SW_PIXELFORMAT_DEPTH_D32; break; + case SW_DEPTH_COMPONENT32F: pixelFormat = SW_PIXELFORMAT_DEPTH_D32; break; + default: + RLSW.errCode = SW_INVALID_ENUM; + return; + } + + (void)sw_texture_alloc(RLSW.boundTexture, NULL, width, height, pixelFormat); +} + void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data) { - uint32_t id = RLSW.currentTexture; + if (RLSW.boundTexture == NULL) return; - if (!sw_is_texture_valid(id)) + int pixelFormat = sw_pixel_get_format(format, type); + if (pixelFormat <= SW_PIXELFORMAT_UNKNOWN) { RLSW.errCode = SW_INVALID_ENUM; return; } + + (void)sw_texture_alloc(RLSW.boundTexture, data, width, height, pixelFormat); +} + +void swTexSubImage2D(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + if (!sw_is_texture_complete(RLSW.boundTexture) || (!pixels) || (width <= 0) || (height <= 0)) { RLSW.errCode = SW_INVALID_VALUE; return; } - int pixelFormat = sw_get_pixel_format(format, type); + if ((x < 0) || (y < 0) || (x + width > RLSW.boundTexture->width) || (y + height > RLSW.boundTexture->height)) + { + RLSW.errCode = SW_INVALID_VALUE; + return; + } - if (pixelFormat <= SW_PIXELFORMAT_UNKNOWN) + sw_pixelformat_t pFormat = sw_pixel_get_format(format, type); + if ((pFormat <= 0) || (pFormat >= SW_PIXELFORMAT_COUNT)) { RLSW.errCode = SW_INVALID_ENUM; return; } - sw_texture_t *texture = &RLSW.loadedTextures[id]; + const int srcPixelSize = SW_PIXELFORMAT_SIZE[pFormat]; + const int dstPixelSize = SW_PIXELFORMAT_SIZE[RLSW.boundTexture->format]; - int size = width*height; - texture->pixels = SW_MALLOC(4*size); + const uint8_t* srcBytes = (const uint8_t *)pixels; + uint8_t* dstBytes = (uint8_t *)RLSW.boundTexture->pixels; - if (texture->pixels == NULL) + if (pFormat == RLSW.boundTexture->format) { - RLSW.errCode = SW_STACK_OVERFLOW; // WARNING: Out of memory... + const int rowSize = width*dstPixelSize; + const int dstStride = RLSW.boundTexture->width*dstPixelSize; + const int srcStride = width*srcPixelSize; + + uint8_t *dstRow = dstBytes + (y*RLSW.boundTexture->width + x)*dstPixelSize; + const uint8_t *srcRow = srcBytes; + + for (int j = 0; j < height; ++j) + { + for (int i = 0; i < rowSize; ++i) dstRow[i] = srcRow[i]; + dstRow += dstStride; + srcRow += srcStride; + } return; } - for (int i = 0; i < size; i++) + for (int j = 0; j < height; ++j) { - uint32_t *dst = &((uint32_t*)texture->pixels)[i]; - sw_get_pixel((uint8_t*)dst, data, i, pixelFormat); - } + for (int i = 0; i < width; ++i) + { + float color[4]; + const int srcPixelOffset = ((j*width) + i)*srcPixelSize; + const int dstPixelOffset = (((y + j)*RLSW.boundTexture->width) + (x + i))*dstPixelSize; - texture->width = width; - texture->height = height; - texture->wMinus1 = width - 1; - texture->hMinus1 = height - 1; - texture->tx = 1.0f/width; - texture->ty = 1.0f/height; + sw_pixel_get_color(color, srcBytes, srcPixelOffset, pFormat); + sw_pixel_set_color(dstBytes, color, dstPixelOffset, RLSW.boundTexture->format); + } + } } void swTexParameteri(int param, int value) { - uint32_t id = RLSW.currentTexture; - - if (!sw_is_texture_valid(id)) - { - RLSW.errCode = SW_INVALID_VALUE; - return; - } - - sw_texture_t *texture = &RLSW.loadedTextures[id]; + if (RLSW.boundTexture == NULL) return; switch (param) { case SW_TEXTURE_MIN_FILTER: - { - if (!sw_is_texture_filter_valid(value)) - { - RLSW.errCode = SW_INVALID_ENUM; - return; - } + if (!sw_is_texture_filter_valid(value)) { RLSW.errCode = SW_INVALID_ENUM; return; } + RLSW.boundTexture->minFilter = (SWfilter)value; + break; - texture->minFilter = (SWfilter)value; - } break; case SW_TEXTURE_MAG_FILTER: - { - if (!sw_is_texture_filter_valid(value)) - { - RLSW.errCode = SW_INVALID_ENUM; - return; - } + if (!sw_is_texture_filter_valid(value)) { RLSW.errCode = SW_INVALID_ENUM; return; } + RLSW.boundTexture->magFilter = (SWfilter)value; + break; - texture->magFilter = (SWfilter)value; - } break; case SW_TEXTURE_WRAP_S: - { - if (!sw_is_texture_wrap_valid(value)) - { - RLSW.errCode = SW_INVALID_ENUM; - return; - } + if (!sw_is_texture_wrap_valid(value)) { RLSW.errCode = SW_INVALID_ENUM; return; } + RLSW.boundTexture->sWrap = (SWwrap)value; + break; - texture->sWrap = (SWwrap)value; - } break; case SW_TEXTURE_WRAP_T: - { - if (!sw_is_texture_wrap_valid(value)) - { - RLSW.errCode = SW_INVALID_ENUM; - return; - } + if (!sw_is_texture_wrap_valid(value)) { RLSW.errCode = SW_INVALID_ENUM; return; } + RLSW.boundTexture->tWrap = (SWwrap)value; + break; - texture->tWrap = (SWwrap)value; - } break; - default: RLSW.errCode = SW_INVALID_ENUM; break; + default: + RLSW.errCode = SW_INVALID_ENUM; + break; } } -void swBindTexture(uint32_t id) +void swGenFramebuffers(int count, uint32_t* framebuffers) { - if (id >= SW_MAX_TEXTURES) + if (!count || !framebuffers) return; + + for (int i = 0; i < count; i++) + { + sw_handle_t h = sw_pool_alloc(&RLSW.framebufferPool); + if (h == SW_HANDLE_NULL) { RLSW.errCode = SW_OUT_OF_MEMORY; return; } + framebuffers[i] = h; + } +} + +void swDeleteFramebuffers(int count, uint32_t* framebuffers) +{ + if (!count || !framebuffers) return; + + for (int i = 0; i < count; i++) + { + sw_framebuffer_t *fb = sw_pool_get(&RLSW.framebufferPool, framebuffers[i]); + if (!fb) { RLSW.errCode = SW_INVALID_VALUE; continue; } + + if (framebuffers[i] == RLSW.boundFramebufferId) + { + RLSW.boundFramebufferId = SW_HANDLE_NULL; + RLSW.colorBuffer = &RLSW.framebuffer.color; + RLSW.depthBuffer = &RLSW.framebuffer.depth; + } + + sw_pool_free(&RLSW.framebufferPool, framebuffers[i]); + } +} + +void swBindFramebuffer(uint32_t id) +{ + if (id == SW_HANDLE_NULL) + { + RLSW.boundFramebufferId = SW_HANDLE_NULL; + RLSW.colorBuffer = &RLSW.framebuffer.color; + RLSW.depthBuffer = &RLSW.framebuffer.depth; + return; + } + + sw_framebuffer_t* fb = sw_pool_get(&RLSW.framebufferPool, id); + if (fb == NULL) { RLSW.errCode = SW_INVALID_VALUE; return; } - if (RLSW.loadedTextures[id].pixels == NULL) + RLSW.boundFramebufferId = id; + RLSW.colorBuffer = sw_pool_get(&RLSW.texturePool, fb->colorAttachment); + RLSW.depthBuffer = sw_pool_get(&RLSW.texturePool, fb->depthAttachment); +} + +void swFramebufferTexture2D(SWattachment attach, uint32_t texture) +{ + if (RLSW.boundFramebufferId == SW_HANDLE_NULL) + { + RLSW.errCode = SW_INVALID_OPERATION; // not really standard but hey + return; + } + + sw_framebuffer_t* fb = sw_pool_get(&RLSW.framebufferPool, RLSW.boundFramebufferId); + if (fb == NULL) return; // Should never happen + + switch (attach) + { + case SW_COLOR_ATTACHMENT: + fb->colorAttachment = texture; + RLSW.colorBuffer = sw_pool_get(&RLSW.texturePool, texture); + break; + case SW_DEPTH_ATTACHMENT: + fb->depthAttachment = texture; + RLSW.depthBuffer = sw_pool_get(&RLSW.texturePool, texture); + break; + default: + RLSW.errCode = SW_INVALID_ENUM; + break; + } +} + +SWfbstatus swCheckFramebufferStatus(void) +{ + if (RLSW.boundFramebufferId == SW_HANDLE_NULL) + { + return SW_FRAMEBUFFER_COMPLETE; + } + + if (RLSW.colorBuffer == NULL) + { + return SW_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; + } + + if (!sw_is_texture_complete(RLSW.colorBuffer)) + { + return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (RLSW.colorBuffer->format != SW_FRAMEBUFFER_COLOR_FORMAT) + { + return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (RLSW.depthBuffer) + { + if (!sw_is_texture_complete(RLSW.depthBuffer)) + { + return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (RLSW.depthBuffer->format != SW_FRAMEBUFFER_DEPTH_FORMAT) + { + return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if ((RLSW.colorBuffer->width != RLSW.depthBuffer->width) || + (RLSW.colorBuffer->height != RLSW.depthBuffer->height)) + { + return SW_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + } + } + + return SW_FRAMEBUFFER_COMPLETE; +} + +void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWattachget property, int *v) +{ + if (RLSW.boundFramebufferId == SW_HANDLE_NULL) { RLSW.errCode = SW_INVALID_OPERATION; return; } - RLSW.currentTexture = id; + if (v == NULL) + { + RLSW.errCode = SW_INVALID_VALUE; + return; + } + + sw_framebuffer_t* fb = sw_pool_get(&RLSW.framebufferPool, RLSW.boundFramebufferId); + if (fb == NULL) return; // Should never happen + + switch (property) + { + case SW_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + { + switch (attachment) + { + case SW_COLOR_ATTACHMENT: + *v = fb->colorAttachment; + break; + case SW_DEPTH_ATTACHMENT: + *v = fb->depthAttachment; + break; + } + } + break; + + case SW_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + { + *v = GL_TEXTURE; + break; + } + } } #endif // RLSW_IMPLEMENTATION + +//---------------------------------------------------------------------------------- +// Template Rasterization Functions +//---------------------------------------------------------------------------------- + +// Triangle rasterization functions +//------------------------------------------------------------------------------------------- +#ifdef RLSW_TEMPLATE_RASTER_TRIANGLE + +// Options: +// - RLSW_TEMPLATE_RASTER_TRIANGLE -> Contains the suffix name +// - SW_ENABLE_DEPTH_TEST +// - SW_ENABLE_TEXTURE +// - SW_ENABLE_BLEND + +#define SW_RASTER_TRIANGLE_SPAN SW_CONCATX(sw_raster_triangle_span_, RLSW_TEMPLATE_RASTER_TRIANGLE) +#define SW_RASTER_TRIANGLE SW_CONCATX(sw_raster_triangle_, RLSW_TEMPLATE_RASTER_TRIANGLE) + +static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t *end, float dUdy, float dVdy) +{ + // Gets the start and end coordinates + int xStart = (int)start->screen[0]; + int xEnd = (int)end->screen[0]; + + // Avoid empty lines + if (xStart == xEnd) return; + + // Compute the subpixel distance to traverse before the first pixel + float xSubstep = 1.0f - sw_fract(start->screen[0]); + + // Compute the inverse horizontal distance along the X axis + float dxRcp = 1.0f/(end->screen[0] - start->screen[0]); + + // Compute the interpolation steps along the X axis +#ifdef SW_ENABLE_DEPTH_TEST + float dZdx = (end->homogeneous[2] - start->homogeneous[2])*dxRcp; +#endif + float dWdx = (end->homogeneous[3] - start->homogeneous[3])*dxRcp; + float dCdx[4] = { + (end->color[0] - start->color[0])*dxRcp, + (end->color[1] - start->color[1])*dxRcp, + (end->color[2] - start->color[2])*dxRcp, + (end->color[3] - start->color[3])*dxRcp + }; +#ifdef SW_ENABLE_TEXTURE + float dUdx = (end->texcoord[0] - start->texcoord[0])*dxRcp; + float dVdx = (end->texcoord[1] - start->texcoord[1])*dxRcp; +#endif + + // Initializing the interpolation starting values +#ifdef SW_ENABLE_DEPTH_TEST + float z = start->homogeneous[2] + dZdx*xSubstep; +#endif + float w = start->homogeneous[3] + dWdx*xSubstep; + float color[4] = { + start->color[0] + dCdx[0]*xSubstep, + start->color[1] + dCdx[1]*xSubstep, + start->color[2] + dCdx[2]*xSubstep, + start->color[3] + dCdx[3]*xSubstep + }; +#ifdef SW_ENABLE_TEXTURE + float u = start->texcoord[0] + dUdx*xSubstep; + float v = start->texcoord[1] + dVdx*xSubstep; +#endif + + // Pre-calculate the starting pointers for the framebuffer row + int y = (int)start->screen[1]; + int baseOffset = y*RLSW.colorBuffer->width + xStart; + uint8_t *cPtr = (uint8_t *)(RLSW.colorBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE; +#ifdef SW_ENABLE_DEPTH_TEST + uint8_t *dPtr = (uint8_t *)(RLSW.depthBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE; +#endif + + // Scanline rasterization + for (int x = xStart; x < xEnd; x++) + { + float wRcp = 1.0f/w; + float srcColor[4] = { + color[0]*wRcp, + color[1]*wRcp, + color[2]*wRcp, + color[3]*wRcp + }; + + #ifdef SW_ENABLE_DEPTH_TEST + { + /* TODO: Implement different depth funcs? */ + float depth = SW_FRAMEBUFFER_DEPTH_GET(dPtr, 0); + if (z > depth) goto discard; + + /* TODO: Implement depth mask */ + SW_FRAMEBUFFER_DEPTH_SET(dPtr, z, 0); + } + #endif + + #ifdef SW_ENABLE_TEXTURE + { + float texColor[4]; + float s = u*wRcp; + float t = v*wRcp; + sw_texture_sample(texColor, RLSW.boundTexture, s, t, dUdx, dUdy, dVdx, dVdy); + srcColor[0] *= texColor[0]; + srcColor[1] *= texColor[1]; + srcColor[2] *= texColor[2]; + srcColor[3] *= texColor[3]; + } + #endif + + #ifdef SW_ENABLE_BLEND + { + float dstColor[4]; + SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); + sw_blend_colors(dstColor, srcColor); + SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); + } + #else + { + SW_FRAMEBUFFER_COLOR_SET(cPtr, srcColor, 0); + } + #endif + + // Increment the interpolation parameter, UVs, and pointers + discard: + #ifdef SW_ENABLE_DEPTH_TEST + { + z += dZdx; + } + #endif + + w += dWdx; + + color[0] += dCdx[0]; + color[1] += dCdx[1]; + color[2] += dCdx[2]; + color[3] += dCdx[3]; + + #ifdef SW_ENABLE_TEXTURE + { + u += dUdx; + v += dVdx; + } + #endif + + cPtr += SW_FRAMEBUFFER_COLOR_SIZE; + + #ifdef SW_ENABLE_DEPTH_TEST + { + dPtr += SW_FRAMEBUFFER_DEPTH_SIZE; + } + #endif + } +} + +static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, const sw_vertex_t *v2) +{ + // Swap vertices by increasing Y + if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } + if (v1->screen[1] > v2->screen[1]) { const sw_vertex_t *tmp = v1; v1 = v2; v2 = tmp; } + if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } + + // Extracting coordinates from the sorted vertices + float x0 = v0->screen[0], y0 = v0->screen[1]; + float x1 = v1->screen[0], y1 = v1->screen[1]; + float x2 = v2->screen[0], y2 = v2->screen[1]; + + // Compute height differences + float h02 = y2 - y0; + float h01 = y1 - y0; + float h12 = y2 - y1; + + if (h02 < 1e-6f) return; + + // Precompute the inverse values without additional checks + float h02Rcp = 1.0f/h02; + float h01Rcp = (h01 > 1e-6f)? 1.0f/h01 : 0.0f; + float h12Rcp = (h12 > 1e-6f)? 1.0f/h12 : 0.0f; + + // Pre-calculation of slopes + float dXdy02 = (x2 - x0)*h02Rcp; + float dXdy01 = (x1 - x0)*h01Rcp; + float dXdy12 = (x2 - x1)*h12Rcp; + + // Y subpixel correction + float y0Substep = 1.0f - sw_fract(y0); + float y1Substep = 1.0f - sw_fract(y1); + + // Y bounds (vertical clipping) + int yTop = (int)y0; + int yMid = (int)y1; + int yBot = (int)y2; + + // Compute gradients for each side of the triangle + sw_vertex_t dVXdy02, dVXdy01, dVXdy12; + sw_get_vertex_grad_PTCH(&dVXdy02, v0, v2, h02Rcp); + sw_get_vertex_grad_PTCH(&dVXdy01, v0, v1, h01Rcp); + sw_get_vertex_grad_PTCH(&dVXdy12, v1, v2, h12Rcp); + + // Get a copy of vertices for interpolation and apply substep correction + sw_vertex_t vLeft = *v0, vRight = *v0; + sw_add_vertex_grad_scaled_PTCH(&vLeft, &dVXdy02, y0Substep); + sw_add_vertex_grad_scaled_PTCH(&vRight, &dVXdy01, y0Substep); + + vLeft.screen[0] += dXdy02*y0Substep; + vRight.screen[0] += dXdy01*y0Substep; + + // Scanline for the upper part of the triangle + for (int y = yTop; y < yMid; y++) + { + vLeft.screen[1] = vRight.screen[1] = y; + + if (vLeft.screen[0] < vRight.screen[0]) + SW_RASTER_TRIANGLE_SPAN(&vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); + else + SW_RASTER_TRIANGLE_SPAN(&vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); + + sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02); + vLeft.screen[0] += dXdy02; + + sw_add_vertex_grad_PTCH(&vRight, &dVXdy01); + vRight.screen[0] += dXdy01; + } + + // Get a copy of next right for interpolation and apply substep correction + vRight = *v1; + sw_add_vertex_grad_scaled_PTCH(&vRight, &dVXdy12, y1Substep); + vRight.screen[0] += dXdy12*y1Substep; + + // Scanline for the lower part of the triangle + for (int y = yMid; y < yBot; y++) + { + vLeft.screen[1] = vRight.screen[1] = y; + + if (vLeft.screen[0] < vRight.screen[0]) + SW_RASTER_TRIANGLE_SPAN(&vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); + else + SW_RASTER_TRIANGLE_SPAN(&vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); + + sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02); + vLeft.screen[0] += dXdy02; + + sw_add_vertex_grad_PTCH(&vRight, &dVXdy12); + vRight.screen[0] += dXdy12; + } +} + +#endif // RLSW_TEMPLATE_RASTER_TRIANGLE +//------------------------------------------------------------------------------------------- + +// Quad rasterization functions +//------------------------------------------------------------------------------------------- +#ifdef RLSW_TEMPLATE_RASTER_QUAD + +// Options: +// - RLSW_TEMPLATE_RASTER_QUAD -> Contains the suffix name +// - SW_ENABLE_DEPTH_TEST +// - SW_ENABLE_TEXTURE +// - SW_ENABLE_BLEND + +#define SW_RASTER_QUAD SW_CONCATX(sw_raster_quad_, RLSW_TEMPLATE_RASTER_QUAD) + +// REVIEW: Could a perfectly aligned quad, where one of the four points has a different depth, +// still appear perfectly aligned from a certain point of view? +// Because in that case, it's still needed to perform perspective division for textures and colors... + +static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, + const sw_vertex_t *c, const sw_vertex_t *d) +{ + // Classify corners + // For axis-aligned quads x+y and x-y uniquely identify each corner + const sw_vertex_t *verts[4] = { a, b, c, d }; + const sw_vertex_t *tl = verts[0], *tr = verts[0], *br = verts[0], *bl = verts[0]; + for (int i = 1; i < 4; i++) + { + float sum = verts[i]->screen[0] + verts[i]->screen[1]; + float diff = verts[i]->screen[0] - verts[i]->screen[1]; + if (sum < tl->screen[0] + tl->screen[1]) tl = verts[i]; + if (diff > tr->screen[0] - tr->screen[1]) tr = verts[i]; + if (sum > br->screen[0] + br->screen[1]) br = verts[i]; + if (diff < bl->screen[0] - bl->screen[1]) bl = verts[i]; + } + + int xMin = (int)tl->screen[0]; + int yMin = (int)tl->screen[1]; + int xMax = (int)br->screen[0]; + int yMax = (int)br->screen[1]; + + float w = (float)(xMax - xMin); + float h = (float)(yMax - yMin); + if ((w <= 0) || (h <= 0)) return; + + float wRcp = 1.0f/w; + float hRcp = 1.0f/h; + + // Subpixel corrections + float xSubstep = 1.0f - sw_fract(tl->screen[0]); + float ySubstep = 1.0f - sw_fract(tl->screen[1]); + + // Gradients along X (tl->tr) and Y (tl->bl) + float dCdx[4] = { + (tr->color[0] - tl->color[0])*wRcp, + (tr->color[1] - tl->color[1])*wRcp, + (tr->color[2] - tl->color[2])*wRcp, + (tr->color[3] - tl->color[3])*wRcp, + }; + float dCdy[4] = { + (bl->color[0] - tl->color[0])*hRcp, + (bl->color[1] - tl->color[1])*hRcp, + (bl->color[2] - tl->color[2])*hRcp, + (bl->color[3] - tl->color[3])*hRcp, + }; + +#ifdef SW_ENABLE_DEPTH_TEST + float dZdx = (tr->homogeneous[2] - tl->homogeneous[2])*wRcp; + float dZdy = (bl->homogeneous[2] - tl->homogeneous[2])*hRcp; + float zRow = tl->homogeneous[2] + dZdx*xSubstep + dZdy*ySubstep; +#endif + +#ifdef SW_ENABLE_TEXTURE + float dUdx = (tr->texcoord[0] - tl->texcoord[0])*wRcp; + float dVdx = (tr->texcoord[1] - tl->texcoord[1])*wRcp; + float dUdy = (bl->texcoord[0] - tl->texcoord[0])*hRcp; + float dVdy = (bl->texcoord[1] - tl->texcoord[1])*hRcp; + float uRow = tl->texcoord[0] + dUdx*xSubstep + dUdy*ySubstep; + float vRow = tl->texcoord[1] + dVdx*xSubstep + dVdy*ySubstep; +#endif + + float cRow[4] = { + tl->color[0] + dCdx[0]*xSubstep + dCdy[0]*ySubstep, + tl->color[1] + dCdx[1]*xSubstep + dCdy[1]*ySubstep, + tl->color[2] + dCdx[2]*xSubstep + dCdy[2]*ySubstep, + tl->color[3] + dCdx[3]*xSubstep + dCdy[3]*ySubstep, + }; + + int stride = RLSW.colorBuffer->width; + uint8_t *cPixels = RLSW.colorBuffer->pixels; +#ifdef SW_ENABLE_DEPTH_TEST + uint8_t *dPixels = RLSW.depthBuffer->pixels; +#endif + + for (int y = yMin; y < yMax; y++) + { + int baseOffset = y*stride + xMin; + uint8_t *cPtr = cPixels + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE; + #ifdef SW_ENABLE_DEPTH_TEST + uint8_t *dPtr = dPixels + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE; + float z = zRow; + #endif + #ifdef SW_ENABLE_TEXTURE + float u = uRow; + float v = vRow; + #endif + float color[4] = { cRow[0], cRow[1], cRow[2], cRow[3] }; + + for (int x = xMin; x < xMax; x++) + { + float srcColor[4] = { color[0], color[1], color[2], color[3] }; + + #ifdef SW_ENABLE_DEPTH_TEST + { + float depth = SW_FRAMEBUFFER_DEPTH_GET(dPtr, 0); + if (z > depth) goto discard; + SW_FRAMEBUFFER_DEPTH_SET(dPtr, z, 0); + } + #endif + + #ifdef SW_ENABLE_TEXTURE + { + float texColor[4]; + sw_texture_sample(texColor, RLSW.boundTexture, u, v, dUdx, dUdy, dVdx, dVdy); + srcColor[0] *= texColor[0]; + srcColor[1] *= texColor[1]; + srcColor[2] *= texColor[2]; + srcColor[3] *= texColor[3]; + } + #endif + + #ifdef SW_ENABLE_BLEND + { + float dstColor[4]; + SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); + sw_blend_colors(dstColor, srcColor); + SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); + } + #else + { + SW_FRAMEBUFFER_COLOR_SET(cPtr, srcColor, 0); + } + #endif + + discard: + color[0] += dCdx[0]; + color[1] += dCdx[1]; + color[2] += dCdx[2]; + color[3] += dCdx[3]; + + #ifdef SW_ENABLE_DEPTH_TEST + { + z += dZdx; + dPtr += SW_FRAMEBUFFER_DEPTH_SIZE; + } + #endif + + #ifdef SW_ENABLE_TEXTURE + { + u += dUdx; + v += dVdx; + } + #endif + + cPtr += SW_FRAMEBUFFER_COLOR_SIZE; + } + + cRow[0] += dCdy[0]; + cRow[1] += dCdy[1]; + cRow[2] += dCdy[2]; + cRow[3] += dCdy[3]; + + #ifdef SW_ENABLE_DEPTH_TEST + { + zRow += dZdy; + } + #endif + + #ifdef SW_ENABLE_TEXTURE + { + uRow += dUdy; + vRow += dVdy; + } + #endif + } +} + +#endif // RLSW_TEMPLATE_RASTER_QUAD +//------------------------------------------------------------------------------------------- + +// Quad rasterization functions +//------------------------------------------------------------------------------------------- +#ifdef RLSW_TEMPLATE_RASTER_LINE + +// Options: +// - RLSW_TEMPLATE_RASTER_LINE -> Contains the suffix name +// - SW_ENABLE_DEPTH_TEST +// - SW_ENABLE_BLEND + +#define SW_RASTER_LINE SW_CONCATX(sw_raster_line_, RLSW_TEMPLATE_RASTER_LINE) +#define SW_RASTER_LINE_THICK SW_CONCATX(sw_raster_line_thick_, RLSW_TEMPLATE_RASTER_LINE) + +static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1) +{ + // Convert from pixel-center convention (n+0.5) to pixel-origin convention (n) + float x0 = v0->screen[0] - 0.5f; + float y0 = v0->screen[1] - 0.5f; + float x1 = v1->screen[0] - 0.5f; + float y1 = v1->screen[1] - 0.5f; + + float dx = x1 - x0; + float dy = y1 - y0; + + // Compute dominant axis and subpixel offset + float steps, substep; + if (fabsf(dx) > fabsf(dy)) + { + steps = fabsf(dx); + if (steps < 1.0f) return; + substep = (dx >= 0.0f)? (1.0f - sw_fract(x0)) : sw_fract(x0); + } + else + { + steps = fabsf(dy); + if (steps < 1.0f) return; + substep = (dy >= 0.0f)? (1.0f - sw_fract(y0)) : sw_fract(y0); + } + + // Compute per pixel increments + float xInc = dx/steps; + float yInc = dy/steps; + float stepRcp = 1.0f/steps; +#ifdef SW_ENABLE_DEPTH_TEST + float zInc = (v1->homogeneous[2] - v0->homogeneous[2])*stepRcp; +#endif + float rInc = (v1->color[0] - v0->color[0])*stepRcp; + float gInc = (v1->color[1] - v0->color[1])*stepRcp; + float bInc = (v1->color[2] - v0->color[2])*stepRcp; + float aInc = (v1->color[3] - v0->color[3])*stepRcp; + + // Initializing the interpolation starting values + float x = x0 + xInc*substep; + float y = y0 + yInc*substep; +#ifdef SW_ENABLE_DEPTH_TEST + float z = v0->homogeneous[2] + zInc*substep; +#endif + float r = v0->color[0] + rInc*substep; + float g = v0->color[1] + gInc*substep; + float b = v0->color[2] + bInc*substep; + float a = v0->color[3] + aInc*substep; + + // Start line rasterization + const int fbWidth = RLSW.colorBuffer->width; + uint8_t *cPixels = RLSW.colorBuffer->pixels; +#ifdef SW_ENABLE_DEPTH_TEST + uint8_t *dPixels = RLSW.depthBuffer->pixels; +#endif + + int numPixels = (int)(steps - substep) + 1; + + for (int i = 0; i < numPixels; i++) + { + int px = x; + int py = y; + + int baseOffset = py*fbWidth + px; + uint8_t *cPtr = cPixels + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE; + #ifdef SW_ENABLE_DEPTH_TEST + uint8_t *dPtr = dPixels + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE; + #endif + + #ifdef SW_ENABLE_DEPTH_TEST + { + // TODO: Implement different depth funcs? + float depth = SW_FRAMEBUFFER_DEPTH_GET(dPtr, 0); + if (z > depth) goto discard; + + // TODO: Implement depth mask + SW_FRAMEBUFFER_DEPTH_SET(dPtr, z, 0); + } + #endif + + float srcColor[4] = {r, g, b, a}; + + #ifdef SW_ENABLE_BLEND + { + float dstColor[4]; + SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); + sw_blend_colors(dstColor, srcColor); + SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); + } + #else + { + SW_FRAMEBUFFER_COLOR_SET(cPtr, srcColor, 0); + } + #endif + + discard: + x += xInc; + y += yInc; + #ifdef SW_ENABLE_DEPTH_TEST + { + z += zInc; + } + #endif + r += rInc; + g += gInc; + b += bInc; + a += aInc; + } +} + +static void SW_RASTER_LINE_THICK(const sw_vertex_t *v1, const sw_vertex_t *v2) +{ + sw_vertex_t tv1, tv2; + + int x1 = (int)v1->screen[0]; + int y1 = (int)v1->screen[1]; + int x2 = (int)v2->screen[0]; + int y2 = (int)v2->screen[1]; + + int dx = x2 - x1; + int dy = y2 - y1; + + SW_RASTER_LINE(v1, v2); + + if ((dx != 0) && (abs(dy/dx) < 1)) + { + int wy = (int)((RLSW.lineWidth - 1.0f)*abs(dx)/sqrtf(dx*dx + dy*dy)); + wy >>= 1; + for (int i = 1; i <= wy; i++) + { + tv1 = *v1, tv2 = *v2; + tv1.screen[1] -= i; + tv2.screen[1] -= i; + SW_RASTER_LINE(&tv1, &tv2); + tv1 = *v1, tv2 = *v2; + tv1.screen[1] += i; + tv2.screen[1] += i; + SW_RASTER_LINE(&tv1, &tv2); + } + } + else if (dy != 0) + { + int wx = (int)((RLSW.lineWidth - 1.0f)*abs(dy)/sqrtf(dx*dx + dy*dy)); + wx >>= 1; + for (int i = 1; i <= wx; i++) + { + tv1 = *v1, tv2 = *v2; + tv1.screen[0] -= i; + tv2.screen[0] -= i; + SW_RASTER_LINE(&tv1, &tv2); + tv1 = *v1, tv2 = *v2; + tv1.screen[0] += i; + tv2.screen[0] += i; + SW_RASTER_LINE(&tv1, &tv2); + } + } +} + +#endif // RLSW_TEMPLATE_RASTER_LINE +//------------------------------------------------------------------------------------------- + +// Point rasterization functions +//------------------------------------------------------------------------------------------- +#ifdef RLSW_TEMPLATE_RASTER_POINT + +// Options: +// - RLSW_TEMPLATE_RASTER_POINT -> Contains the suffix name +// - SW_ENABLE_DEPTH_TEST +// - SW_ENABLE_BLEND + +#define SW_RASTER_POINT_PIXEL SW_CONCATX(sw_raster_point_pixel_, RLSW_TEMPLATE_RASTER_POINT) +#define SW_RASTER_POINT SW_CONCATX(sw_raster_point_, RLSW_TEMPLATE_RASTER_POINT) + +static void SW_RASTER_POINT_PIXEL(int x, int y, float z, const float color[4]) +{ + int offset = y*RLSW.colorBuffer->width + x; + + #ifdef SW_ENABLE_DEPTH_TEST + { + uint8_t *dPtr = (uint8_t *)(RLSW.depthBuffer->pixels) + offset*SW_FRAMEBUFFER_DEPTH_SIZE; + + // TODO: Implement different depth funcs? + float depth = SW_FRAMEBUFFER_DEPTH_GET(dPtr, 0); + if (z > depth) return; + + // TODO: Implement depth mask + SW_FRAMEBUFFER_DEPTH_SET(dPtr, z, 0); + } + #endif + + uint8_t *cPtr = (uint8_t *)(RLSW.colorBuffer->pixels) + offset*SW_FRAMEBUFFER_COLOR_SIZE; + + #ifdef SW_ENABLE_BLEND + { + float dstColor[4]; + SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); + sw_blend_colors(dstColor, color); + SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); + } + #else + { + SW_FRAMEBUFFER_COLOR_SET(cPtr, color, 0); + } + #endif +} + +static void SW_RASTER_POINT(const sw_vertex_t *v) +{ + int cx = v->screen[0]; + int cy = v->screen[1]; + float cz = v->homogeneous[2]; + int radius = RLSW.pointRadius; + const float *color = v->color; + + for (int dy = -radius; dy <= radius; dy++) + { + for (int dx = -radius; dx <= radius; dx++) + { + SW_RASTER_POINT_PIXEL(cx + dx, cy + dy, cz, color); + } + } +} + +#endif // RLSW_TEMPLATE_RASTER_POINT +//------------------------------------------------------------------------------------------- diff --git a/src/rlgl.h b/src/rlgl.h index b40b50b43..df5335790 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -838,6 +838,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) #define RLSW_IMPLEMENTATION #define SW_MALLOC(sz) RL_MALLOC(sz) + #define SW_CALLOC(n,sz) RL_CALLOC(n, sz) #define SW_REALLOC(ptr, newSz) RL_REALLOC(ptr, newSz) #define SW_FREE(ptr) RL_FREE(ptr) #include "external/rlsw.h" // OpenGL 1.1 software implementation @@ -1857,7 +1858,7 @@ void rlDisableShader(void) // Enable rendering to texture (fbo) void rlEnableFramebuffer(unsigned int id) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) glBindFramebuffer(GL_FRAMEBUFFER, id); #endif } @@ -1866,7 +1867,7 @@ void rlEnableFramebuffer(unsigned int id) unsigned int rlGetActiveFramebuffer(void) { GLint fboId = 0; -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fboId); #endif return fboId; @@ -1875,7 +1876,7 @@ unsigned int rlGetActiveFramebuffer(void) // Disable rendering to texture void rlDisableFramebuffer(void) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) glBindFramebuffer(GL_FRAMEBUFFER, 0); #endif } @@ -1891,7 +1892,7 @@ void rlBlitFramebuffer(int srcX, int srcY, int srcWidth, int srcHeight, int dstX // Bind framebuffer object (fbo) void rlBindFramebuffer(unsigned int target, unsigned int framebuffer) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) glBindFramebuffer(target, framebuffer); #endif } @@ -3471,6 +3472,13 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Depth renderbuffer loaded successfully (%i bits)", id, (RLGL.ExtSupported.maxDepthBits >= 24)? RLGL.ExtSupported.maxDepthBits : 16); } +#elif defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + // NOTE: Renderbuffers are the same type of object as textures in rlsw + // WARNING: Ensure that the depth format is the one specified at rlsw compilation + glGenRenderbuffers(1, &id); + glBindRenderbuffer(GL_RENDERBUFFER, id); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); #endif return id; @@ -3771,7 +3779,7 @@ void rlCopyFramebuffer(int x, int y, int width, int height, int format, void *pi #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) unsigned int glInternalFormat, glFormat, glType; rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); // Get OpenGL texture format - swCopyFramebuffer(x, y, width, height, glFormat, glType, pixels); + swReadPixels(x, y, width, height, glFormat, glType, pixels); #endif } @@ -3779,7 +3787,7 @@ void rlCopyFramebuffer(int x, int y, int width, int height, int format, void *pi void rlResizeFramebuffer(int width, int height) { #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) - swResizeFramebuffer(width, height); + swResize(width, height); #endif } @@ -3829,7 +3837,7 @@ unsigned int rlLoadFramebuffer(void) unsigned int fboId = 0; if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return fboId; } -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) glGenFramebuffers(1, &fboId); // Create the framebuffer object glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind any framebuffer #endif @@ -3841,7 +3849,7 @@ unsigned int rlLoadFramebuffer(void) // NOTE: Attach type: 0-Color, 1-Depth renderbuffer, 2-Depth texture void rlFramebufferAttach(unsigned int id, unsigned int texId, int attachType, int texType, int mipLevel) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) glBindFramebuffer(GL_FRAMEBUFFER, id); switch (attachType) @@ -3881,7 +3889,7 @@ bool rlFramebufferComplete(unsigned int id) { bool result = false; -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) glBindFramebuffer(GL_FRAMEBUFFER, id); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -3912,7 +3920,7 @@ bool rlFramebufferComplete(unsigned int id) // NOTE: All attached textures/cubemaps/renderbuffers are also deleted void rlUnloadFramebuffer(unsigned int id) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) // Query depth attachment to automatically delete texture/renderbuffer int depthType = 0; glBindFramebuffer(GL_FRAMEBUFFER, id); // Bind framebuffer to query depth texture type From 6ddf9a18856cea2880d33f2ca216942966cd8f09 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 17 Mar 2026 18:30:48 +0100 Subject: [PATCH 22/41] Code review, format tweaks, defined version to 1.5 --- src/external/rlsw.h | 589 ++++++++++++++++---------------------------- 1 file changed, 208 insertions(+), 381 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index 81d4a54f1..b22bf694b 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* rlsw v1.0 - An OpenGL 1.1-style software renderer implementation +* rlsw v1.5 - An OpenGL 1.1-style software renderer implementation * * DESCRIPTION: * rlsw is a custom OpenGL 1.1-style implementation on software, intended to provide all @@ -87,6 +87,8 @@ #ifndef RLSW_H #define RLSW_H +#define RLGL_VERSION "1.5" + #include #include @@ -738,8 +740,8 @@ SWAPI void swTexImage2D(int width, int height, SWformat format, SWtype type, con SWAPI void swTexSubImage2D(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); SWAPI void swTexParameteri(int param, int value); -SWAPI void swGenFramebuffers(int count, uint32_t* framebuffers); -SWAPI void swDeleteFramebuffers(int count, uint32_t* framebuffers); +SWAPI void swGenFramebuffers(int count, uint32_t *framebuffers); +SWAPI void swDeleteFramebuffers(int count, uint32_t *framebuffers); SWAPI void swBindFramebuffer(uint32_t id); SWAPI void swFramebufferTexture2D(SWattachment attach, uint32_t texture); SWAPI SWfbstatus swCheckFramebufferStatus(void); @@ -942,21 +944,21 @@ typedef struct { } sw_texture_t; typedef struct { - sw_texture_t color; - sw_texture_t depth; + sw_texture_t color; // Default framebuffer color texture + sw_texture_t depth; // Default framebuffer depth texture } sw_default_framebuffer_t; typedef struct { - sw_handle_t colorAttachment; - sw_handle_t depthAttachment; + sw_handle_t colorAttachment; // Framebuffer color attachment id + sw_handle_t depthAttachment; // Framebuffer depth attachment id } sw_framebuffer_t; typedef struct { - void *data; // flat storage [capacity*stride] bytes - uint8_t *gen; // generation per slot [capacity] - uint32_t *freeList; // free indices stack [capacity] + void *data; // Flat storage [capacity*stride] bytes + uint8_t *gen; // Generation per slot [capacity] + uint32_t *freeList; // Free indices stack [capacity] int freeCount; - int watermark; // next blank index (starts at 1, skips 0) + int watermark; // Next blank index (starts at 1, skips 0) int capacity; size_t stride; } sw_pool_t; @@ -967,6 +969,7 @@ typedef void (*sw_raster_quad_f)(const sw_vertex_t *v0, const sw_vertex_t *v1, c typedef void (*sw_raster_line_f)(const sw_vertex_t *v0, const sw_vertex_t *v1); typedef void (*sw_raster_point_f)(const sw_vertex_t *v); +// Graphic context data structure typedef struct { sw_default_framebuffer_t framebuffer; // Default framebuffer float clearColor[4]; // Clear color of the framebuffer @@ -1012,18 +1015,18 @@ typedef struct { bool isDirtyMVP; // Indicates if the MVP matrix should be rebuilt sw_handle_t boundFramebufferId; // Framebuffer currently bound - sw_texture_t* colorBuffer; // Color buffer currently bound - sw_texture_t* depthBuffer; // Depth buffer currently bound + sw_texture_t *colorBuffer; // Color buffer currently bound + sw_texture_t *depthBuffer; // Depth buffer currently bound sw_pool_t framebufferPool; // Framebuffer object pool - sw_texture_t* boundTexture; // Texture currently bound + sw_texture_t *boundTexture; // Texture currently bound sw_pool_t texturePool; // Texture object pool - SWfactor srcFactor; - SWfactor dstFactor; + SWfactor srcFactor; // Source blending factor + SWfactor dstFactor; // Destination bleending factor - sw_blend_factor_t srcFactorFunc; - sw_blend_factor_t dstFactorFunc; + sw_blend_factor_t srcFactorFunc; // Source blend function + sw_blend_factor_t dstFactorFunc; // Destination blend function SWface cullFace; // Faces to cull SWerrcode errCode; // Last error code @@ -1242,10 +1245,7 @@ static inline void sw_add_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const s out->homogeneous[3] += gradients->homogeneous[3]; } -static inline void sw_add_vertex_grad_scaled_PTCH( - sw_vertex_t *SW_RESTRICT out, - const sw_vertex_t *SW_RESTRICT gradients, - float scale) +static inline void sw_add_vertex_grad_scaled_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients, float scale) { // Add gradients to Position out->position[0] += gradients->position[0]*scale; @@ -1276,13 +1276,13 @@ static inline uint16_t sw_float_to_half_ui(uint32_t ui) int32_t s = (ui >> 16) & 0x8000; int32_t em = ui & 0x7fffffff; - // bias exponent and round to nearest; 112 is relative exponent bias (127-15) + // Bias exponent and round to nearest; 112 is relative exponent bias (127-15) int32_t h = (em - (112 << 23) + (1 << 12)) >> 13; - // underflow: flush to zero; 113 encodes exponent -14 + // Underflow: flush to zero; 113 encodes exponent -14 h = (em < (113 << 23))? 0 : h; - // overflow: infinity; 143 encodes exponent 16 + // Overflow: infinity; 143 encodes exponent 16 h = (em >= (143 << 23))? 0x7c00 : h; // NaN; note that we convert all types of NaN to qNaN @@ -1296,13 +1296,13 @@ static inline uint32_t sw_half_to_float_ui(uint16_t h) uint32_t s = (unsigned)(h & 0x8000) << 16; int32_t em = h & 0x7fff; - // bias exponent and pad mantissa with 0; 112 is relative exponent bias (127-15) + // Bias exponent and pad mantissa with 0; 112 is relative exponent bias (127-15) int32_t r = (em + (112 << 10)) << 13; - // denormal: flush to zero + // Denormal: flush to zero r = (em < (1 << 10))? 0 : r; - // infinity/NaN; note that we preserve NaN payload as a byproduct of unifying inf/nan cases + // Infinity/NaN; note that we preserve NaN payload as a byproduct of unifying inf/nan cases // 112 is an exponent bias fixup; since we already applied it once, applying it twice converts 31 to 255 r += (em >= (31 << 10))? (112 << 23) : 0; @@ -1323,14 +1323,14 @@ static inline float sw_half_to_float(sw_half_t y) return v.f; } -static inline uint8_t sw_expand_1to8(uint32_t v) { return v ? 255 : 0; } +static inline uint8_t sw_expand_1to8(uint32_t v) { return v? 255 : 0; } static inline uint8_t sw_expand_2to8(uint32_t v) { return (uint8_t)(v*85); } static inline uint8_t sw_expand_3to8(uint32_t v) { return (uint8_t)((v << 5) | (v << 2) | (v >> 1)); } static inline uint8_t sw_expand_4to8(uint32_t v) { return (uint8_t)((v << 4) | v); } static inline uint8_t sw_expand_5to8(uint32_t v) { return (uint8_t)((v << 3) | (v >> 2)); } static inline uint8_t sw_expand_6to8(uint32_t v) { return (uint8_t)((v << 2) | (v >> 4)); } -static inline float sw_expand_1tof(uint32_t v) { return v ? 1.0f : 0.0f; } +static inline float sw_expand_1tof(uint32_t v) { return v? 1.0f : 0.0f; } static inline float sw_expand_2tof(uint32_t v) { return (float)v*(1.0f/3.0f); } static inline float sw_expand_3tof(uint32_t v) { return (float)v*(1.0f/7.0f); } static inline float sw_expand_4tof(uint32_t v) { return (float)v*(1.0f/15.0f); } @@ -1344,9 +1344,9 @@ static inline uint32_t sw_compress_8to4(uint8_t v) { return v >> 4; } static inline uint32_t sw_compress_8to5(uint8_t v) { return v >> 3; } static inline uint32_t sw_compress_8to6(uint8_t v) { return v >> 2; } -static inline uint32_t sw_compress_fto1(float v) { return v >= 0.5f ? 1 : 0; } -static inline uint32_t sw_compress_fto2(float v) { return (uint32_t)(v* 3.0f + 0.5f) & 0x03; } -static inline uint32_t sw_compress_fto3(float v) { return (uint32_t)(v* 7.0f + 0.5f) & 0x07; } +static inline uint32_t sw_compress_fto1(float v) { return (v >= 0.5f)? 1 : 0; } +static inline uint32_t sw_compress_fto2(float v) { return (uint32_t)(v*3.0f + 0.5f) & 0x03; } +static inline uint32_t sw_compress_fto3(float v) { return (uint32_t)(v*7.0f + 0.5f) & 0x07; } static inline uint32_t sw_compress_fto4(float v) { return (uint32_t)(v*15.0f + 0.5f) & 0x0F; } static inline uint32_t sw_compress_fto5(float v) { return (uint32_t)(v*31.0f + 0.5f) & 0x1F; } static inline uint32_t sw_compress_fto6(float v) { return (uint32_t)(v*63.0f + 0.5f) & 0x3F; } @@ -1356,7 +1356,7 @@ static inline uint32_t sw_compress_fto6(float v) { return (uint32_t)(v*63.0f + 0 //------------------------------------------------------------------------------------------- static bool sw_pool_init(sw_pool_t *pool, int capacity, size_t stride) { - *pool = (sw_pool_t) { 0 }; + *pool = (sw_pool_t){ 0 }; pool->data = SW_CALLOC(capacity, stride); pool->gen = SW_CALLOC(capacity, sizeof(uint8_t)); @@ -1371,8 +1371,8 @@ static bool sw_pool_init(sw_pool_t *pool, int capacity, size_t stride) } pool->watermark = 1; - pool->capacity = capacity; - pool->stride = stride; + pool->capacity = capacity; + pool->stride = stride; return true; } @@ -1440,7 +1440,7 @@ static inline bool sw_is_texture_valid(sw_handle_t id) return sw_pool_valid(&RLSW.texturePool, id); } -static inline bool sw_is_texture_complete(sw_texture_t* tex) +static inline bool sw_is_texture_complete(sw_texture_t *tex) { return (tex != NULL) && (tex->pixels != NULL); } @@ -1752,48 +1752,20 @@ static inline void sw_pixel_get_color8(uint8_t *SW_RESTRICT color, const void *S { switch (format) { - case SW_PIXELFORMAT_COLOR_GRAYSCALE: - sw_pixel_get_color8_GRAYSCALE(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_GRAYALPHA: - sw_pixel_get_color8_GRAYALPHA(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R3G3B2: - sw_pixel_get_color8_R3G3B2(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R5G6B5: - sw_pixel_get_color8_R5G6B5(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R8G8B8: - sw_pixel_get_color8_R8G8B8(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R5G5B5A1: - sw_pixel_get_color8_R5G5B5A1(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R4G4B4A4: - sw_pixel_get_color8_R4G4B4A4(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R8G8B8A8: - sw_pixel_get_color8_R8G8B8A8(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R32: - sw_pixel_get_color8_R32(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R32G32B32: - sw_pixel_get_color8_R32G32B32(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R32G32B32A32: - sw_pixel_get_color8_R32G32B32A32(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R16: - sw_pixel_get_color8_R16(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R16G16B16: - sw_pixel_get_color8_R16G16B16(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R16G16B16A16: - sw_pixel_get_color8_R16G16B16A16(color, pixels, offset); - break; + case SW_PIXELFORMAT_COLOR_GRAYSCALE: sw_pixel_get_color8_GRAYSCALE(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_GRAYALPHA: sw_pixel_get_color8_GRAYALPHA(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R3G3B2: sw_pixel_get_color8_R3G3B2(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R5G6B5: sw_pixel_get_color8_R5G6B5(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R8G8B8: sw_pixel_get_color8_R8G8B8(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R5G5B5A1: sw_pixel_get_color8_R5G5B5A1(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R4G4B4A4: sw_pixel_get_color8_R4G4B4A4(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R8G8B8A8: sw_pixel_get_color8_R8G8B8A8(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R32: sw_pixel_get_color8_R32(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R32G32B32: sw_pixel_get_color8_R32G32B32(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R32G32B32A32: sw_pixel_get_color8_R32G32B32A32(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R16: sw_pixel_get_color8_R16(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R16G16B16: sw_pixel_get_color8_R16G16B16(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R16G16B16A16: sw_pixel_get_color8_R16G16B16A16(color, pixels, offset); break; case SW_PIXELFORMAT_UNKNOWN: case SW_PIXELFORMAT_DEPTH_D8: @@ -1805,8 +1777,8 @@ static inline void sw_pixel_get_color8(uint8_t *SW_RESTRICT color, const void *S color[1] = 0.0f; color[2] = 0.0f; color[3] = 0.0f; - break; - } + } break; + default: break; } } @@ -1921,55 +1893,27 @@ static inline void sw_pixel_set_color8(void *SW_RESTRICT pixels, const uint8_t * { switch (format) { - case SW_PIXELFORMAT_COLOR_GRAYSCALE: - sw_pixel_set_color8_GRAYSCALE(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_GRAYALPHA: - sw_pixel_set_color8_GRAYALPHA(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R3G3B2: - sw_pixel_set_color8_R3G3B2(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R5G6B5: - sw_pixel_set_color8_R5G6B5(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R8G8B8: - sw_pixel_set_color8_R8G8B8(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R5G5B5A1: - sw_pixel_set_color8_R5G5B5A1(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R4G4B4A4: - sw_pixel_set_color8_R4G4B4A4(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R8G8B8A8: - sw_pixel_set_color8_R8G8B8A8(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R32: - sw_pixel_set_color8_R32(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R32G32B32: - sw_pixel_set_color8_R32G32B32(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R32G32B32A32: - sw_pixel_set_color8_R32G32B32A32(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R16: - sw_pixel_set_color8_R16(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R16G16B16: - sw_pixel_set_color8_R16G16B16(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R16G16B16A16: - sw_pixel_set_color8_R16G16B16A16(pixels, color, offset); - break; + case SW_PIXELFORMAT_COLOR_GRAYSCALE: sw_pixel_set_color8_GRAYSCALE(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_GRAYALPHA: sw_pixel_set_color8_GRAYALPHA(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R3G3B2: sw_pixel_set_color8_R3G3B2(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R5G6B5: sw_pixel_set_color8_R5G6B5(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R8G8B8: sw_pixel_set_color8_R8G8B8(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R5G5B5A1: sw_pixel_set_color8_R5G5B5A1(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R4G4B4A4: sw_pixel_set_color8_R4G4B4A4(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R8G8B8A8: sw_pixel_set_color8_R8G8B8A8(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R32: sw_pixel_set_color8_R32(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R32G32B32: sw_pixel_set_color8_R32G32B32(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R32G32B32A32: sw_pixel_set_color8_R32G32B32A32(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R16: sw_pixel_set_color8_R16(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R16G16B16: sw_pixel_set_color8_R16G16B16(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R16G16B16A16: sw_pixel_set_color8_R16G16B16A16(pixels, color, offset); break; case SW_PIXELFORMAT_UNKNOWN: case SW_PIXELFORMAT_DEPTH_D8: case SW_PIXELFORMAT_DEPTH_D16: case SW_PIXELFORMAT_DEPTH_D32: - case SW_PIXELFORMAT_COUNT: - break; + case SW_PIXELFORMAT_COUNT: break; + default: break; } } @@ -2062,7 +2006,7 @@ static inline void sw_pixel_get_color_R8G8B8A8(float *SW_RESTRICT color, const v _mm_storeu_ps(color, fvals); #elif defined(SW_HAS_RVV) - // TODO: Sample code generated by AI, needs testing and review + // TODO: WARNING: Sample code generated by AI, needs testing and review size_t vl = __riscv_vsetvl_e8m1(4); // Set vector length for 8-bit input elements vuint8m1_t vsrc_u8 = __riscv_vle8_v_u8m1(src, vl); // Load 4 unsigned 8-bit integers vuint32m1_t vsrc_u32 = __riscv_vwcvt_xu_u_v_u32m1(vsrc_u8, vl); // Widen to 32-bit unsigned integers @@ -2136,48 +2080,20 @@ static inline void sw_pixel_get_color(float *SW_RESTRICT color, const void *SW_R { switch (format) { - case SW_PIXELFORMAT_COLOR_GRAYSCALE: - sw_pixel_get_color_GRAYSCALE(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_GRAYALPHA: - sw_pixel_get_color_GRAYALPHA(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R3G3B2: - sw_pixel_get_color_R3G3B2(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R5G6B5: - sw_pixel_get_color_R5G6B5(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R8G8B8: - sw_pixel_get_color_R8G8B8(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R5G5B5A1: - sw_pixel_get_color_R5G5B5A1(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R4G4B4A4: - sw_pixel_get_color_R4G4B4A4(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R8G8B8A8: - sw_pixel_get_color_R8G8B8A8(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R32: - sw_pixel_get_color_R32(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R32G32B32: - sw_pixel_get_color_R32G32B32(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R32G32B32A32: - sw_pixel_get_color_R32G32B32A32(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R16: - sw_pixel_get_color_R16(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R16G16B16: - sw_pixel_get_color_R16G16B16(color, pixels, offset); - break; - case SW_PIXELFORMAT_COLOR_R16G16B16A16: - sw_pixel_get_color_R16G16B16A16(color, pixels, offset); - break; + case SW_PIXELFORMAT_COLOR_GRAYSCALE: sw_pixel_get_color_GRAYSCALE(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_GRAYALPHA: sw_pixel_get_color_GRAYALPHA(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R3G3B2: sw_pixel_get_color_R3G3B2(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R5G6B5: sw_pixel_get_color_R5G6B5(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R8G8B8: sw_pixel_get_color_R8G8B8(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R5G5B5A1: sw_pixel_get_color_R5G5B5A1(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R4G4B4A4: sw_pixel_get_color_R4G4B4A4(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R8G8B8A8: sw_pixel_get_color_R8G8B8A8(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R32: sw_pixel_get_color_R32(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R32G32B32: sw_pixel_get_color_R32G32B32(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R32G32B32A32: sw_pixel_get_color_R32G32B32A32(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R16: sw_pixel_get_color_R16(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R16G16B16: sw_pixel_get_color_R16G16B16(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_R16G16B16A16: sw_pixel_get_color_R16G16B16A16(color, pixels, offset); break; case SW_PIXELFORMAT_UNKNOWN: case SW_PIXELFORMAT_DEPTH_D8: @@ -2189,8 +2105,8 @@ static inline void sw_pixel_get_color(float *SW_RESTRICT color, const void *SW_R color[1] = 0.0f; color[2] = 0.0f; color[3] = 0.0f; - break; - } + } break; + default: break; } } @@ -2277,7 +2193,7 @@ static inline void sw_pixel_set_color_R8G8B8A8(void *SW_RESTRICT pixels, const f _mm_storeu_si32(dst, i8); #elif defined(SW_HAS_RVV) - // TODO: Sample code generated by AI, needs testing and review + // TODO: WARNING: Sample code generated by AI, needs testing and review // REVIEW: It shouldn't perform so many operations; take inspiration from other versions // NOTE: RVV 1.0 specs define the use of __riscv_ prefix for instrinsic functions size_t vl = __riscv_vsetvl_e32m1(4); // Load up to 4 floats into a vector register @@ -2350,55 +2266,26 @@ static inline void sw_pixel_set_color(void *SW_RESTRICT pixels, const float *SW_ { switch (format) { - case SW_PIXELFORMAT_COLOR_GRAYSCALE: - sw_pixel_set_color_GRAYSCALE(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_GRAYALPHA: - sw_pixel_set_color_GRAYALPHA(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R3G3B2: - sw_pixel_set_color_R3G3B2(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R5G6B5: - sw_pixel_set_color_R5G6B5(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R8G8B8: - sw_pixel_set_color_R8G8B8(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R5G5B5A1: - sw_pixel_set_color_R5G5B5A1(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R4G4B4A4: - sw_pixel_set_color_R4G4B4A4(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R8G8B8A8: - sw_pixel_set_color_R8G8B8A8(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R32: - sw_pixel_set_color_R32(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R32G32B32: - sw_pixel_set_color_R32G32B32(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R32G32B32A32: - sw_pixel_set_color_R32G32B32A32(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R16: - sw_pixel_set_color_R16(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R16G16B16: - sw_pixel_set_color_R16G16B16(pixels, color, offset); - break; - case SW_PIXELFORMAT_COLOR_R16G16B16A16: - sw_pixel_set_color_R16G16B16A16(pixels, color, offset); - break; + case SW_PIXELFORMAT_COLOR_GRAYSCALE: sw_pixel_set_color_GRAYSCALE(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_GRAYALPHA: sw_pixel_set_color_GRAYALPHA(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R3G3B2: sw_pixel_set_color_R3G3B2(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R5G6B5: sw_pixel_set_color_R5G6B5(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R8G8B8: sw_pixel_set_color_R8G8B8(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R5G5B5A1: sw_pixel_set_color_R5G5B5A1(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R4G4B4A4: sw_pixel_set_color_R4G4B4A4(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R8G8B8A8: sw_pixel_set_color_R8G8B8A8(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R32: sw_pixel_set_color_R32(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R32G32B32: sw_pixel_set_color_R32G32B32(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R32G32B32A32: sw_pixel_set_color_R32G32B32A32(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R16: sw_pixel_set_color_R16(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R16G16B16: sw_pixel_set_color_R16G16B16(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_R16G16B16A16: sw_pixel_set_color_R16G16B16A16(pixels, color, offset); break; case SW_PIXELFORMAT_UNKNOWN: case SW_PIXELFORMAT_DEPTH_D8: case SW_PIXELFORMAT_DEPTH_D16: case SW_PIXELFORMAT_DEPTH_D32: - case SW_PIXELFORMAT_COUNT: - break; + case SW_PIXELFORMAT_COUNT: break; } } @@ -2421,30 +2308,26 @@ static inline float sw_pixel_get_depth(const void *pixels, uint32_t offset, sw_p { switch (format) { - case SW_PIXELFORMAT_DEPTH_D8: - return sw_pixel_get_depth_D8(pixels, offset); - case SW_PIXELFORMAT_DEPTH_D16: - return sw_pixel_get_depth_D16(pixels, offset); - case SW_PIXELFORMAT_DEPTH_D32: - return sw_pixel_get_depth_D32(pixels, offset); + case SW_PIXELFORMAT_DEPTH_D8: return sw_pixel_get_depth_D8(pixels, offset); + case SW_PIXELFORMAT_DEPTH_D16: return sw_pixel_get_depth_D16(pixels, offset); + case SW_PIXELFORMAT_DEPTH_D32: return sw_pixel_get_depth_D32(pixels, offset); - case SW_PIXELFORMAT_UNKNOWN: - case SW_PIXELFORMAT_COLOR_GRAYSCALE: - case SW_PIXELFORMAT_COLOR_GRAYALPHA: - case SW_PIXELFORMAT_COLOR_R3G3B2: - case SW_PIXELFORMAT_COLOR_R5G6B5: - case SW_PIXELFORMAT_COLOR_R8G8B8: - case SW_PIXELFORMAT_COLOR_R5G5B5A1: - case SW_PIXELFORMAT_COLOR_R4G4B4A4: - case SW_PIXELFORMAT_COLOR_R8G8B8A8: - case SW_PIXELFORMAT_COLOR_R32: - case SW_PIXELFORMAT_COLOR_R32G32B32: - case SW_PIXELFORMAT_COLOR_R32G32B32A32: - case SW_PIXELFORMAT_COLOR_R16: - case SW_PIXELFORMAT_COLOR_R16G16B16: - case SW_PIXELFORMAT_COLOR_R16G16B16A16: - case SW_PIXELFORMAT_COUNT: - break; + case SW_PIXELFORMAT_UNKNOWN: + case SW_PIXELFORMAT_COLOR_GRAYSCALE: + case SW_PIXELFORMAT_COLOR_GRAYALPHA: + case SW_PIXELFORMAT_COLOR_R3G3B2: + case SW_PIXELFORMAT_COLOR_R5G6B5: + case SW_PIXELFORMAT_COLOR_R8G8B8: + case SW_PIXELFORMAT_COLOR_R5G5B5A1: + case SW_PIXELFORMAT_COLOR_R4G4B4A4: + case SW_PIXELFORMAT_COLOR_R8G8B8A8: + case SW_PIXELFORMAT_COLOR_R32: + case SW_PIXELFORMAT_COLOR_R32G32B32: + case SW_PIXELFORMAT_COLOR_R32G32B32A32: + case SW_PIXELFORMAT_COLOR_R16: + case SW_PIXELFORMAT_COLOR_R16G16B16: + case SW_PIXELFORMAT_COLOR_R16G16B16A16: + case SW_PIXELFORMAT_COUNT: break; } return 0.0f; @@ -2469,33 +2352,26 @@ static inline void sw_pixel_set_depth(void *pixels, float depth, uint32_t offset { switch (format) { - case SW_PIXELFORMAT_DEPTH_D8: - sw_pixel_set_depth_D8(pixels, depth, offset); - break; - case SW_PIXELFORMAT_DEPTH_D16: - sw_pixel_set_depth_D16(pixels, depth, offset); - break; - case SW_PIXELFORMAT_DEPTH_D32: - sw_pixel_set_depth_D32(pixels, depth, offset); - break; + case SW_PIXELFORMAT_DEPTH_D8: sw_pixel_set_depth_D8(pixels, depth, offset); break; + case SW_PIXELFORMAT_DEPTH_D16: w_pixel_set_depth_D16(pixels, depth, offset); break; + case SW_PIXELFORMAT_DEPTH_D32: sw_pixel_set_depth_D32(pixels, depth, offset); break; - case SW_PIXELFORMAT_UNKNOWN: - case SW_PIXELFORMAT_COLOR_GRAYSCALE: - case SW_PIXELFORMAT_COLOR_GRAYALPHA: - case SW_PIXELFORMAT_COLOR_R3G3B2: - case SW_PIXELFORMAT_COLOR_R5G6B5: - case SW_PIXELFORMAT_COLOR_R8G8B8: - case SW_PIXELFORMAT_COLOR_R5G5B5A1: - case SW_PIXELFORMAT_COLOR_R4G4B4A4: - case SW_PIXELFORMAT_COLOR_R8G8B8A8: - case SW_PIXELFORMAT_COLOR_R32: - case SW_PIXELFORMAT_COLOR_R32G32B32: - case SW_PIXELFORMAT_COLOR_R32G32B32A32: - case SW_PIXELFORMAT_COLOR_R16: - case SW_PIXELFORMAT_COLOR_R16G16B16: - case SW_PIXELFORMAT_COLOR_R16G16B16A16: - case SW_PIXELFORMAT_COUNT: - break; + case SW_PIXELFORMAT_UNKNOWN: + case SW_PIXELFORMAT_COLOR_GRAYSCALE: + case SW_PIXELFORMAT_COLOR_GRAYALPHA: + case SW_PIXELFORMAT_COLOR_R3G3B2: + case SW_PIXELFORMAT_COLOR_R5G6B5: + case SW_PIXELFORMAT_COLOR_R8G8B8: + case SW_PIXELFORMAT_COLOR_R5G5B5A1: + case SW_PIXELFORMAT_COLOR_R4G4B4A4: + case SW_PIXELFORMAT_COLOR_R8G8B8A8: + case SW_PIXELFORMAT_COLOR_R32: + case SW_PIXELFORMAT_COLOR_R32G32B32: + case SW_PIXELFORMAT_COLOR_R32G32B32A32: + case SW_PIXELFORMAT_COLOR_R16: + case SW_PIXELFORMAT_COLOR_R16G16B16: + case SW_PIXELFORMAT_COLOR_R16G16B16A16: + case SW_PIXELFORMAT_COUNT: break; } } //------------------------------------------------------------------------------------------- @@ -2509,17 +2385,17 @@ static inline bool sw_texture_alloc(sw_texture_t *texture, const void *data, int if (newSize > texture->allocSz) { - void* ptr = SW_REALLOC(texture->pixels, newSize); + void *ptr = SW_REALLOC(texture->pixels, newSize); if (!ptr) { RLSW.errCode = SW_OUT_OF_MEMORY; return false; } texture->allocSz = newSize; texture->pixels = ptr; } - uint8_t* dst = texture->pixels; - const uint8_t* src = data; + uint8_t *dst = texture->pixels; + const uint8_t *src = data; if (data) for (int i = 0; i < newSize; i++) dst[i] = src[i]; - else for (int i = 0; i < newSize; i++) dst[i] = 0; + else for (int i = 0; i < newSize; i++) dst[i] = 0; texture->format = format; texture->width = w; @@ -2635,7 +2511,7 @@ static inline void sw_texture_sample(float *SW_RESTRICT color, const sw_texture_ // Framebuffer management functions //------------------------------------------------------------------------------------------- -static inline bool sw_default_framebuffer_alloc(sw_default_framebuffer_t* fb, int w, int h) +static inline bool sw_default_framebuffer_alloc(sw_default_framebuffer_t *fb, int w, int h) { if (!sw_texture_alloc(&fb->color, NULL, w, h, SW_FRAMEBUFFER_COLOR_FORMAT)) { @@ -2650,7 +2526,7 @@ static inline bool sw_default_framebuffer_alloc(sw_default_framebuffer_t* fb, in return true; } -static inline void sw_default_framebuffer_free(sw_default_framebuffer_t* fb) +static inline void sw_default_framebuffer_free(sw_default_framebuffer_t *fb) { sw_texture_free(&fb->color); sw_texture_free(&fb->depth); @@ -2736,9 +2612,9 @@ static inline void sw_framebuffer_fill_depth(sw_texture_t *depthBuffer, float de } } -static inline void sw_framebuffer_output_fast(void* dst, const sw_texture_t* buffer) +static inline void sw_framebuffer_output_fast(void *dst, const sw_texture_t *buffer) { - int width = buffer->width; + int width = buffer->width; int height = buffer->height; uint8_t *d = (uint8_t *)dst; @@ -2777,7 +2653,7 @@ static inline void sw_framebuffer_output_fast(void* dst, const sw_texture_t* buf #endif } -static inline void sw_framebuffer_output_copy(void* dst, const sw_texture_t* buffer, int x, int y, int w, int h, sw_pixelformat_t format) +static inline void sw_framebuffer_output_copy(void *dst, const sw_texture_t *buffer, int x, int y, int w, int h, sw_pixelformat_t format) { int dstPixelSize = SW_PIXELFORMAT_SIZE[format]; int stride = buffer->width; @@ -2808,15 +2684,12 @@ static inline void sw_framebuffer_output_copy(void* dst, const sw_texture_t* buf } src -= stride*SW_FRAMEBUFFER_COLOR_SIZE; - d += w*dstPixelSize; + d += w*dstPixelSize; } } -static inline void sw_framebuffer_output_blit( - void* dst, const sw_texture_t* buffer, - int xDst, int yDst, int wDst, int hDst, - int xSrc, int ySrc, int wSrc, int hSrc, - sw_pixelformat_t format) +static inline void sw_framebuffer_output_blit(void *dst, const sw_texture_t *buffer, + int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, sw_pixelformat_t format) { const uint8_t *srcBase = buffer->pixels; @@ -3692,7 +3565,8 @@ static inline bool sw_line_clip_coord(float q, float p, float *t0, float *t1) static bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1) { float t0 = 0.0f, t1 = 1.0f; - float dH[4], dC[4]; + float dH[4] = { 0 } + float dC[4] = { 0 }; for (int i = 0; i < 4; i++) { @@ -4460,7 +4334,7 @@ void swLoadIdentity(void) void swTranslatef(float x, float y, float z) { - sw_matrix_t mat; + sw_matrix_t mat = { 0 }; sw_matrix_id(mat); mat[12] = x; @@ -4490,7 +4364,7 @@ void swRotatef(float angle, float x, float y, float z) float cosres = cosf(angle); float t = 1.0f - cosres; - sw_matrix_t mat; + sw_matrix_t mat = { 0 }; mat[0] = x*x*t + cosres; mat[1] = y*x*t + z*sinres; @@ -4519,7 +4393,7 @@ void swRotatef(float angle, float x, float y, float z) void swScalef(float x, float y, float z) { - sw_matrix_t mat; + sw_matrix_t mat = { 0 }; mat[0] = x, mat[1] = 0, mat[2] = 0, mat[3] = 0; mat[4] = 0, mat[5] = y, mat[6] = 0, mat[7] = 0; @@ -4540,7 +4414,7 @@ void swMultMatrixf(const float *mat) void swFrustum(double left, double right, double bottom, double top, double znear, double zfar) { - sw_matrix_t mat; + sw_matrix_t mat = { 0 }; double rl = right - left; double tb = top - bottom; @@ -4573,7 +4447,7 @@ void swFrustum(double left, double right, double bottom, double top, double znea void swOrtho(double left, double right, double bottom, double top, double znear, double zfar) { - sw_matrix_t mat; + sw_matrix_t mat = { 0 }; double rl = right - left; double tb = top - bottom; @@ -4695,7 +4569,7 @@ void swVertex4fv(const float *v) void swColor3ub(uint8_t r, uint8_t g, uint8_t b) { - float cv[4]; + float cv[4] = { 0 }; cv[0] = (float)r*SW_INV_255; cv[1] = (float)g*SW_INV_255; cv[2] = (float)b*SW_INV_255; @@ -4706,7 +4580,7 @@ void swColor3ub(uint8_t r, uint8_t g, uint8_t b) void swColor3ubv(const uint8_t *v) { - float cv[4]; + float cv[4] = { 0 }; cv[0] = (float)v[0]*SW_INV_255; cv[1] = (float)v[1]*SW_INV_255; cv[2] = (float)v[2]*SW_INV_255; @@ -4717,7 +4591,7 @@ void swColor3ubv(const uint8_t *v) void swColor3f(float r, float g, float b) { - float cv[4]; + float cv[4] = { 0 }; cv[0] = r; cv[1] = g; cv[2] = b; @@ -4728,7 +4602,7 @@ void swColor3f(float r, float g, float b) void swColor3fv(const float *v) { - float cv[4]; + float cv[4] = { 0 }; cv[0] = v[0]; cv[1] = v[1]; cv[2] = v[2]; @@ -4739,7 +4613,7 @@ void swColor3fv(const float *v) void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - float cv[4]; + float cv[4] = { 0 }; cv[0] = (float)r*SW_INV_255; cv[1] = (float)g*SW_INV_255; cv[2] = (float)b*SW_INV_255; @@ -4750,7 +4624,7 @@ void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a) void swColor4ubv(const uint8_t *v) { - float cv[4]; + float cv[4] = { 0 }; cv[0] = (float)v[0]*SW_INV_255; cv[1] = (float)v[1]*SW_INV_255; cv[2] = (float)v[2]*SW_INV_255; @@ -4761,7 +4635,7 @@ void swColor4ubv(const uint8_t *v) void swColor4f(float r, float g, float b, float a) { - float cv[4]; + float cv[4] = { 0 }; cv[0] = r; cv[1] = g; cv[2] = b; @@ -4891,18 +4765,10 @@ void swDrawElements(SWdraw mode, int count, int type, const void *indices) switch (type) { - case SW_UNSIGNED_BYTE: - indicesUb = (const uint8_t *)indices; - break; - case SW_UNSIGNED_SHORT: - indicesUs = (const uint16_t *)indices; - break; - case SW_UNSIGNED_INT: - indicesUi = (const uint32_t *)indices; - break; - default: - RLSW.errCode = SW_INVALID_ENUM; - return; + case SW_UNSIGNED_BYTE: indicesUb = (const uint8_t *)indices; break; + case SW_UNSIGNED_SHORT: indicesUs = (const uint16_t *)indices; break; + case SW_UNSIGNED_INT: indicesUi = (const uint32_t *)indices; break; + default: RLSW.errCode = SW_INVALID_ENUM; return; } swBegin(mode); @@ -4992,7 +4858,7 @@ void swDeleteTextures(int count, sw_handle_t *textures) if (tex == RLSW.depthBuffer) RLSW.depthBuffer = NULL; sw_texture_free(tex); - *tex = (sw_texture_t) { 0 }; + *tex = (sw_texture_t){ 0 }; sw_pool_free(&RLSW.texturePool, textures[i]); } @@ -5030,9 +4896,7 @@ void swTexStorage2D(int width, int height, SWinternalformat format) case SW_DEPTH_COMPONENT24: pixelFormat = SW_PIXELFORMAT_DEPTH_D32; break; case SW_DEPTH_COMPONENT32: pixelFormat = SW_PIXELFORMAT_DEPTH_D32; break; case SW_DEPTH_COMPONENT32F: pixelFormat = SW_PIXELFORMAT_DEPTH_D32; break; - default: - RLSW.errCode = SW_INVALID_ENUM; - return; + default: RLSW.errCode = SW_INVALID_ENUM; return; } (void)sw_texture_alloc(RLSW.boundTexture, NULL, width, height, pixelFormat); @@ -5072,8 +4936,8 @@ void swTexSubImage2D(GLint x, GLint y, GLsizei width, GLsizei height, GLenum for const int srcPixelSize = SW_PIXELFORMAT_SIZE[pFormat]; const int dstPixelSize = SW_PIXELFORMAT_SIZE[RLSW.boundTexture->format]; - const uint8_t* srcBytes = (const uint8_t *)pixels; - uint8_t* dstBytes = (uint8_t *)RLSW.boundTexture->pixels; + const uint8_t *srcBytes = (const uint8_t *)pixels; + uint8_t *dstBytes = (uint8_t *)RLSW.boundTexture->pixels; if (pFormat == RLSW.boundTexture->format) { @@ -5114,32 +4978,30 @@ void swTexParameteri(int param, int value) switch (param) { case SW_TEXTURE_MIN_FILTER: + { if (!sw_is_texture_filter_valid(value)) { RLSW.errCode = SW_INVALID_ENUM; return; } RLSW.boundTexture->minFilter = (SWfilter)value; - break; - + } break; case SW_TEXTURE_MAG_FILTER: + { if (!sw_is_texture_filter_valid(value)) { RLSW.errCode = SW_INVALID_ENUM; return; } RLSW.boundTexture->magFilter = (SWfilter)value; - break; - + } break; case SW_TEXTURE_WRAP_S: + { if (!sw_is_texture_wrap_valid(value)) { RLSW.errCode = SW_INVALID_ENUM; return; } RLSW.boundTexture->sWrap = (SWwrap)value; - break; - + } break; case SW_TEXTURE_WRAP_T: + { if (!sw_is_texture_wrap_valid(value)) { RLSW.errCode = SW_INVALID_ENUM; return; } RLSW.boundTexture->tWrap = (SWwrap)value; - break; - - default: - RLSW.errCode = SW_INVALID_ENUM; - break; + } break; + default: RLSW.errCode = SW_INVALID_ENUM; break; } } -void swGenFramebuffers(int count, uint32_t* framebuffers) +void swGenFramebuffers(int count, uint32_t *framebuffers) { if (!count || !framebuffers) return; @@ -5151,7 +5013,7 @@ void swGenFramebuffers(int count, uint32_t* framebuffers) } } -void swDeleteFramebuffers(int count, uint32_t* framebuffers) +void swDeleteFramebuffers(int count, uint32_t *framebuffers) { if (!count || !framebuffers) return; @@ -5181,7 +5043,7 @@ void swBindFramebuffer(uint32_t id) return; } - sw_framebuffer_t* fb = sw_pool_get(&RLSW.framebufferPool, id); + sw_framebuffer_t *fb = sw_pool_get(&RLSW.framebufferPool, id); if (fb == NULL) { RLSW.errCode = SW_INVALID_VALUE; @@ -5201,64 +5063,43 @@ void swFramebufferTexture2D(SWattachment attach, uint32_t texture) return; } - sw_framebuffer_t* fb = sw_pool_get(&RLSW.framebufferPool, RLSW.boundFramebufferId); + sw_framebuffer_t *fb = sw_pool_get(&RLSW.framebufferPool, RLSW.boundFramebufferId); if (fb == NULL) return; // Should never happen switch (attach) { case SW_COLOR_ATTACHMENT: + { fb->colorAttachment = texture; RLSW.colorBuffer = sw_pool_get(&RLSW.texturePool, texture); - break; + } break; case SW_DEPTH_ATTACHMENT: + { fb->depthAttachment = texture; RLSW.depthBuffer = sw_pool_get(&RLSW.texturePool, texture); - break; - default: - RLSW.errCode = SW_INVALID_ENUM; - break; + } break; + default: RLSW.errCode = SW_INVALID_ENUM; break; } } SWfbstatus swCheckFramebufferStatus(void) { - if (RLSW.boundFramebufferId == SW_HANDLE_NULL) - { - return SW_FRAMEBUFFER_COMPLETE; - } + if (RLSW.boundFramebufferId == SW_HANDLE_NULL) return SW_FRAMEBUFFER_COMPLETE; - if (RLSW.colorBuffer == NULL) - { - return SW_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; - } + if (RLSW.colorBuffer == NULL) return SW_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; - if (!sw_is_texture_complete(RLSW.colorBuffer)) - { - return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + if (!sw_is_texture_complete(RLSW.colorBuffer)) return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - if (RLSW.colorBuffer->format != SW_FRAMEBUFFER_COLOR_FORMAT) - { - return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + if (RLSW.colorBuffer->format != SW_FRAMEBUFFER_COLOR_FORMAT) return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; if (RLSW.depthBuffer) { - if (!sw_is_texture_complete(RLSW.depthBuffer)) - { - return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + if (!sw_is_texture_complete(RLSW.depthBuffer)) return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - if (RLSW.depthBuffer->format != SW_FRAMEBUFFER_DEPTH_FORMAT) - { - return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } + if (RLSW.depthBuffer->format != SW_FRAMEBUFFER_DEPTH_FORMAT) return SW_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; if ((RLSW.colorBuffer->width != RLSW.depthBuffer->width) || - (RLSW.colorBuffer->height != RLSW.depthBuffer->height)) - { - return SW_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; - } + (RLSW.colorBuffer->height != RLSW.depthBuffer->height)) return SW_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; } return SW_FRAMEBUFFER_COMPLETE; @@ -5278,30 +5119,18 @@ void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWattachget return; } - sw_framebuffer_t* fb = sw_pool_get(&RLSW.framebufferPool, RLSW.boundFramebufferId); + sw_framebuffer_t *fb = sw_pool_get(&RLSW.framebufferPool, RLSW.boundFramebufferId); if (fb == NULL) return; // Should never happen switch (property) { case SW_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: { - switch (attachment) - { - case SW_COLOR_ATTACHMENT: - *v = fb->colorAttachment; - break; - case SW_DEPTH_ATTACHMENT: - *v = fb->depthAttachment; - break; - } - } - break; - - case SW_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: - { - *v = GL_TEXTURE; - break; - } + if (attachment == SW_COLOR_ATTACHMENT) *v = fb->colorAttachment; + else if (attachment == SW_DEPTH_ATTACHMENT) *v = fb->depthAttachment; + } break; + case SW_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: *v = GL_TEXTURE; break; + default: break; } } @@ -5328,7 +5157,7 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t { // Gets the start and end coordinates int xStart = (int)start->screen[0]; - int xEnd = (int)end->screen[0]; + int xEnd = (int)end->screen[0]; // Avoid empty lines if (xStart == xEnd) return; @@ -5538,10 +5367,8 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con { vLeft.screen[1] = vRight.screen[1] = y; - if (vLeft.screen[0] < vRight.screen[0]) - SW_RASTER_TRIANGLE_SPAN(&vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); - else - SW_RASTER_TRIANGLE_SPAN(&vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); + if (vLeft.screen[0] < vRight.screen[0]) SW_RASTER_TRIANGLE_SPAN(&vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); + else SW_RASTER_TRIANGLE_SPAN(&vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02); vLeft.screen[0] += dXdy02; From 18756bb79d35f79de28e755d9bf763947b1922ca Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 17 Mar 2026 18:33:15 +0100 Subject: [PATCH 23/41] REVIEWED: Software renderer flag, renamed to `GRAPHICS_API_OPENGL_SOFTWARE` Dropped the `11` relative to OpenGL 1.1 because latest `rlsw 1.5` also includes support for FBOs and could potentially implemented other higher level features in the feature, discerning from OpenGL 1.1 limitations --- src/platforms/rcore_desktop_sdl.c | 10 +++---- src/platforms/rcore_desktop_win32.c | 14 +++++----- src/platforms/rcore_drm.c | 18 ++++++------ src/platforms/rcore_memory.c | 4 +-- src/platforms/rcore_web.c | 6 ++-- src/platforms/rcore_web_emscripten.c | 4 +-- src/rlgl.h | 42 ++++++++++++++-------------- src/rmodels.c | 2 +- 8 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 9b6bea987..0cf18a15d 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -60,7 +60,7 @@ #include "SDL.h" #endif -#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) #if defined(GRAPHICS_API_OPENGL_ES2) // It seems it does not need to be included to work //#include "SDL_opengles2.h" @@ -1259,7 +1259,7 @@ void DisableCursor(void) // Swap back buffer with front buffer (screen drawing) void SwapScreenBuffer(void) { -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) // NOTE: Using 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); @@ -1981,7 +1981,7 @@ int InitPlatform(void) // NOTE: Some OpenGL context attributes must be set before window creation - if (rlGetVersion() != RL_OPENGL_11_SOFTWARE) + if (rlGetVersion() != RL_OPENGL_SOFTWARE) { // Add the flag telling the window to use an OpenGL context flags |= SDL_WINDOW_OPENGL; @@ -2044,12 +2044,12 @@ int InitPlatform(void) #endif // Init OpenGL context - if (rlGetVersion() != RL_OPENGL_11_SOFTWARE) + if (rlGetVersion() != RL_OPENGL_SOFTWARE) { platform.glContext = SDL_GL_CreateContext(platform.window); } - if ((platform.window != NULL) && ((rlGetVersion() == RL_OPENGL_11_SOFTWARE) || (platform.glContext != NULL))) + if ((platform.window != NULL) && ((rlGetVersion() == RL_OPENGL_SOFTWARE) || (platform.glContext != NULL))) { CORE.Window.ready = true; diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index 1cf8826aa..612800b83 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -71,7 +71,7 @@ #include // Required for alloca() -#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) #include #endif @@ -1218,7 +1218,7 @@ void SwapScreenBuffer(void) { if (!platform.hdc) abort(); -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) // Update framebuffer rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.pixels); @@ -1603,7 +1603,7 @@ int InitPlatform(void) // NOTE: Windows GDI object that represents a drawing surface platform.hdc = GetDC(platform.hwnd); - if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer + if (rlGetVersion() == RL_OPENGL_SOFTWARE) // Using software renderer { // Initialize software framebuffer BITMAPINFO bmi = { 0 }; @@ -1649,11 +1649,11 @@ 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 (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer + if (rlGetVersion() == RL_OPENGL_SOFTWARE) // Using software renderer { TRACELOG(LOG_INFO, "GL: OpenGL device information:"); TRACELOG(LOG_INFO, " > Vendor: %s", "raylib"); - TRACELOG(LOG_INFO, " > Renderer: %s", "rlsw - OpenGL 1.1 Software Renderer"); + TRACELOG(LOG_INFO, " > Renderer: %s", "rlsw - OpenGL Software Renderer"); TRACELOG(LOG_INFO, " > Version: %s", "1.0"); TRACELOG(LOG_INFO, " > GLSL: %s", "NOT SUPPORTED"); } @@ -1719,7 +1719,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara case WM_DESTROY: { // Clean up for window destruction - if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer + if (rlGetVersion() == RL_OPENGL_SOFTWARE) // Using software renderer { if (platform.hdcmem) { @@ -1935,7 +1935,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara } break; case WM_PAINT: { - if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer + if (rlGetVersion() == RL_OPENGL_SOFTWARE) // Using software renderer { PAINTSTRUCT ps = { 0 }; HDC hdc = BeginPaint(hwnd, &ps); diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index a32934aa9..faba8956a 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -65,7 +65,7 @@ #include // Direct Rendering Manager user-level library interface #include // Direct Rendering Manager mode setting (KMS) interface -#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) #include // Generic Buffer Management (native platform for EGL on DRM) #include "EGL/egl.h" // Native platform windowing system interface #include "EGL/eglext.h" // EGL extensions @@ -111,7 +111,7 @@ typedef struct { 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) +#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) struct gbm_device *gbmDevice; // GBM device struct gbm_surface *gbmSurface; // GBM surface struct gbm_bo *prevBO; // Previous GBM buffer object (during frame swapping) @@ -796,7 +796,7 @@ void SwapScreenBuffer() // Swap back buffer with front buffer (screen drawing) void SwapScreenBuffer(void) { -#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) // Hardware rendering buffer swap with EGL eglSwapBuffers(platform.device, platform.surface); @@ -1140,7 +1140,7 @@ int InitPlatform(void) platform.crtc = NULL; platform.prevFB = 0; -#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) platform.gbmDevice = NULL; platform.gbmSurface = NULL; platform.prevBO = NULL; @@ -1224,7 +1224,7 @@ int InitPlatform(void) // 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)) { -#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) // For hardware rendering, an encoder_id is needed if (con->encoder_id) { @@ -1256,7 +1256,7 @@ int InitPlatform(void) return -1; } -#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) drmModeEncoder *enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id); if (!enc) { @@ -1367,7 +1367,7 @@ int InitPlatform(void) drmModeFreeResources(res); res = NULL; -#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) // Hardware rendering initialization with EGL platform.gbmDevice = gbm_create_device(platform.fd); if (!platform.gbmDevice) @@ -1657,7 +1657,7 @@ void ClosePlatform(void) platform.prevFB = 0; } -#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) if (platform.prevBO) { gbm_surface_release_buffer(platform.gbmSurface, platform.prevBO); @@ -1697,7 +1697,7 @@ void ClosePlatform(void) platform.fd = -1; } -#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) // Close surface, context and display if (platform.device != EGL_NO_DISPLAY) { diff --git a/src/platforms/rcore_memory.c b/src/platforms/rcore_memory.c index 322841439..1512e7bf4 100644 --- a/src/platforms/rcore_memory.c +++ b/src/platforms/rcore_memory.c @@ -486,9 +486,9 @@ void PollInputEvents(void) int InitPlatform(void) { // Memory framebuffer can only work with software renderer - if (rlGetVersion() != RL_OPENGL_11_SOFTWARE) + if (rlGetVersion() != RL_OPENGL_SOFTWARE) { - TRACELOG(LOG_WARNING, "DISPLAY: Memory platform requires software renderer (GRAPHICS_API_OPENGL_11_SOFTWARE)"); + TRACELOG(LOG_WARNING, "DISPLAY: Memory platform requires software renderer (GRAPHICS_API_OPENGL_SOFTWARE)"); TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device"); return -1; } diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index 62b2afda9..8835ecdcc 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -77,7 +77,7 @@ typedef struct { char canvasId[64]; // Keep current canvas id where wasm app is running // NOTE: Useful when trying to run multiple wasms in different canvases in same webpage -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) unsigned int *pixels; // Pointer to pixel data buffer (RGBA 32bit format) #endif } PlatformData; @@ -949,7 +949,7 @@ void DisableCursor(void) // Swap back buffer with front buffer (screen drawing) void SwapScreenBuffer(void) { -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) // Update framebuffer rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.pixels); @@ -1306,7 +1306,7 @@ int InitPlatform(void) // Init fullscreen toggle required var: platform.ourFullscreen = false; -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) // Avoid creating a WebGL canvas, avoid calling glfwCreateWindow() emscripten_set_canvas_element_size(platform.canvasId, CORE.Window.screen.width, CORE.Window.screen.height); EM_ASM({ diff --git a/src/platforms/rcore_web_emscripten.c b/src/platforms/rcore_web_emscripten.c index 60b647f60..3b6064255 100644 --- a/src/platforms/rcore_web_emscripten.c +++ b/src/platforms/rcore_web_emscripten.c @@ -927,7 +927,7 @@ void DisableCursor(void) // Swap back buffer with front buffer (screen drawing) void SwapScreenBuffer(void) { -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) // Update framebuffer rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.pixels); @@ -1188,7 +1188,7 @@ int InitPlatform(void) if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) attribs.antialias = EM_TRUE; // Check selection OpenGL version - if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) + if (rlGetVersion() == RL_OPENGL_SOFTWARE) { // Avoid creating a WebGL canvas, create 2d canvas for software rendering emscripten_set_canvas_element_size(platform.canvasId, CORE.Window.screen.width, CORE.Window.screen.height); diff --git a/src/rlgl.h b/src/rlgl.h index df5335790..15ee58b0c 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -21,7 +21,7 @@ * Internal buffer (and resources) must be manually unloaded calling rlglClose() * * CONFIGURATION: -* #define GRAPHICS_API_OPENGL_11_SOFTWARE +* #define GRAPHICS_API_OPENGL_SOFTWARE * #define GRAPHICS_API_OPENGL_11 * #define GRAPHICS_API_OPENGL_21 * #define GRAPHICS_API_OPENGL_33 @@ -145,7 +145,7 @@ #endif // Security check in case no GRAPHICS_API_OPENGL_* defined -#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) && \ +#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) && \ !defined(GRAPHICS_API_OPENGL_11) && \ !defined(GRAPHICS_API_OPENGL_21) && \ !defined(GRAPHICS_API_OPENGL_33) && \ @@ -156,7 +156,7 @@ #endif // Security check in case multiple GRAPHICS_API_OPENGL_* defined -#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_SOFTWARE) #if defined(GRAPHICS_API_OPENGL_21) #undef GRAPHICS_API_OPENGL_21 #endif @@ -172,7 +172,7 @@ #endif // Software implementation uses OpenGL 1.1 functionality -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) #define GRAPHICS_API_OPENGL_11 #endif @@ -423,7 +423,7 @@ typedef struct rlRenderBatch { // OpenGL version typedef enum { - RL_OPENGL_11_SOFTWARE = 0, // Software rendering + RL_OPENGL_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) @@ -835,7 +835,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #endif #if defined(GRAPHICS_API_OPENGL_11) - #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + #if defined(GRAPHICS_API_OPENGL_SOFTWARE) #define RLSW_IMPLEMENTATION #define SW_MALLOC(sz) RL_MALLOC(sz) #define SW_CALLOC(n,sz) RL_CALLOC(n, sz) @@ -1858,7 +1858,7 @@ void rlDisableShader(void) // Enable rendering to texture (fbo) void rlEnableFramebuffer(unsigned int id) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) glBindFramebuffer(GL_FRAMEBUFFER, id); #endif } @@ -1867,7 +1867,7 @@ void rlEnableFramebuffer(unsigned int id) unsigned int rlGetActiveFramebuffer(void) { GLint fboId = 0; -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fboId); #endif return fboId; @@ -1876,7 +1876,7 @@ unsigned int rlGetActiveFramebuffer(void) // Disable rendering to texture void rlDisableFramebuffer(void) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) glBindFramebuffer(GL_FRAMEBUFFER, 0); #endif } @@ -1892,7 +1892,7 @@ void rlBlitFramebuffer(int srcX, int srcY, int srcWidth, int srcHeight, int dstX // Bind framebuffer object (fbo) void rlBindFramebuffer(unsigned int target, unsigned int framebuffer) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) glBindFramebuffer(target, framebuffer); #endif } @@ -2325,7 +2325,7 @@ void rlglInit(int width, int height) RLGL.State.currentMatrix = &RLGL.State.modelview; #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) // Initialize software renderer backend int result = swInit(width, height); if (result == 0) @@ -2387,7 +2387,7 @@ void rlglClose(void) TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture unloaded successfully", RLGL.State.defaultTextureId); #endif -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) swClose(); // Unload sofware renderer resources #endif isGpuReady = false; @@ -2702,8 +2702,8 @@ int rlGetVersion(void) { int glVersion = 0; -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) - glVersion = RL_OPENGL_11_SOFTWARE; +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) + glVersion = RL_OPENGL_SOFTWARE; #elif defined(GRAPHICS_API_OPENGL_11) glVersion = RL_OPENGL_11; #endif @@ -3472,7 +3472,7 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Depth renderbuffer loaded successfully (%i bits)", id, (RLGL.ExtSupported.maxDepthBits >= 24)? RLGL.ExtSupported.maxDepthBits : 16); } -#elif defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#elif defined(GRAPHICS_API_OPENGL_SOFTWARE) // NOTE: Renderbuffers are the same type of object as textures in rlsw // WARNING: Ensure that the depth format is the one specified at rlsw compilation glGenRenderbuffers(1, &id); @@ -3776,7 +3776,7 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format) // Copy framebuffer pixel data to internal buffer void rlCopyFramebuffer(int x, int y, int width, int height, int format, void *pixels) { -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) unsigned int glInternalFormat, glFormat, glType; rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); // Get OpenGL texture format swReadPixels(x, y, width, height, glFormat, glType, pixels); @@ -3786,7 +3786,7 @@ void rlCopyFramebuffer(int x, int y, int width, int height, int format, void *pi // Resize internal framebuffer void rlResizeFramebuffer(int width, int height) { -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) swResize(width, height); #endif } @@ -3837,7 +3837,7 @@ unsigned int rlLoadFramebuffer(void) unsigned int fboId = 0; if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return fboId; } -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) glGenFramebuffers(1, &fboId); // Create the framebuffer object glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind any framebuffer #endif @@ -3849,7 +3849,7 @@ unsigned int rlLoadFramebuffer(void) // NOTE: Attach type: 0-Color, 1-Depth renderbuffer, 2-Depth texture void rlFramebufferAttach(unsigned int id, unsigned int texId, int attachType, int texType, int mipLevel) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) glBindFramebuffer(GL_FRAMEBUFFER, id); switch (attachType) @@ -3889,7 +3889,7 @@ bool rlFramebufferComplete(unsigned int id) { bool result = false; -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) glBindFramebuffer(GL_FRAMEBUFFER, id); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -3920,7 +3920,7 @@ bool rlFramebufferComplete(unsigned int id) // NOTE: All attached textures/cubemaps/renderbuffers are also deleted void rlUnloadFramebuffer(unsigned int id) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE)) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) // Query depth attachment to automatically delete texture/renderbuffer int depthType = 0; glBindFramebuffer(GL_FRAMEBUFFER, id); // Bind framebuffer to query depth texture type diff --git a/src/rmodels.c b/src/rmodels.c index 1c7a5452c..ba28eb839 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1430,7 +1430,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) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_SOFTWARE) #define GL_VERTEX_ARRAY 0x8074 #define GL_NORMAL_ARRAY 0x8075 #define GL_COLOR_ARRAY 0x8076 From fbce5e75415de04782fb3f33bad52a1f339a951f Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 17 Mar 2026 18:33:53 +0100 Subject: [PATCH 24/41] Bump rlgl version to 6.0, after the low-level shaders API redesign, aligned with `raylib 6.0` --- src/rlgl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 15ee58b0c..13c037132 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* rlgl v5.0 - A multi-OpenGL abstraction layer with an immediate-mode style API +* rlgl v6.0 - A multi-OpenGL abstraction layer with an immediate-mode style API * * DESCRIPTION: * An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0, ES 3.0) @@ -107,7 +107,7 @@ #ifndef RLGL_H #define RLGL_H -#define RLGL_VERSION "5.0" +#define RLGL_VERSION "6.0" // Function specifiers in case library is build/used as a shared library // NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll From 48a34d63ede200fd2ae733eeedb537ff0753b0a2 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 17 Mar 2026 18:35:33 +0100 Subject: [PATCH 25/41] Update rlsw.h --- src/external/rlsw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index b22bf694b..1166e3448 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -87,7 +87,7 @@ #ifndef RLSW_H #define RLSW_H -#define RLGL_VERSION "1.5" +#define RLSW_VERSION "1.5" #include #include From 0de2e8092bf0685e777cf0a97c4f4c059a896173 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 17 Mar 2026 19:38:29 +0100 Subject: [PATCH 26/41] REVIEWED: `GetTime()`, make sure division is with doubles #5668 --- src/platforms/rcore_desktop_sdl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 0cf18a15d..2bf846be0 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -1276,7 +1276,7 @@ void SwapScreenBuffer(void) // Get elapsed time measure in seconds double GetTime(void) { - double time = (double)(SDL_GetPerformanceCounter()/SDL_GetPerformanceFrequency()) - CORE.Time.base; + double time = ((double)SDL_GetPerformanceCounter()/(double)SDL_GetPerformanceFrequency()) - CORE.Time.base; return time; } @@ -2125,7 +2125,7 @@ int InitPlatform(void) // Initialize timing system //---------------------------------------------------------------------------- // Get base time from window initialization - CORE.Time.base = (double)(SDL_GetPerformanceCounter()/SDL_GetPerformanceFrequency()); + CORE.Time.base = (double)SDL_GetPerformanceCounter()/(double)SDL_GetPerformanceFrequency(); #if defined(_WIN32) && SUPPORT_WINMM_HIGHRES_TIMER && !SUPPORT_BUSY_WAIT_LOOP SDL_SetHint(SDL_HINT_TIMER_RESOLUTION, "1"); // SDL equivalent of timeBeginPeriod() and timeEndPeriod() From d657e8604395a20be6a7717102da60223af41060 Mon Sep 17 00:00:00 2001 From: Le Juez Victor <90587919+Bigfoot71@users.noreply.github.com> Date: Tue, 17 Mar 2026 20:01:45 +0100 Subject: [PATCH 27/41] [rlsw] Fix typos, update build scripts, and align style (#5669) * fix typo that appeared during re-format * fix build scripts for `GRAPHICS_API_OPENGL_SOFTWARE` * consistency tweak --- cmake/LibraryConfigurations.cmake | 2 +- src/Makefile | 10 +++++----- src/external/rlsw.h | 10 ++++------ 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake index 9e7efe792..7af078de0 100644 --- a/cmake/LibraryConfigurations.cmake +++ b/cmake/LibraryConfigurations.cmake @@ -190,7 +190,7 @@ if (NOT ${OPENGL_VERSION} MATCHES "OFF") elseif (${OPENGL_VERSION} MATCHES "ES 3.0") set(GRAPHICS "GRAPHICS_API_OPENGL_ES3") elseif (${OPENGL_VERSION} MATCHES "Software") - set(GRAPHICS "GRAPHICS_API_OPENGL_11_SOFTWARE") + set(GRAPHICS "GRAPHICS_API_OPENGL_SOFTWARE") 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.") diff --git a/src/Makefile b/src/Makefile index b67ba3e6a..026888614 100644 --- a/src/Makefile +++ b/src/Makefile @@ -246,7 +246,7 @@ 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_SOFTWARE # Uncomment to use software rendering + #GRAPHICS = GRAPHICS_API_OPENGL_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 @@ -257,7 +257,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL) endif ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW) GRAPHICS ?= GRAPHICS_API_OPENGL_33 - #GRAPHICS = GRAPHICS_API_OPENGL_11_SOFTWARE # Uncomment to use software rendering + #GRAPHICS = GRAPHICS_API_OPENGL_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 @@ -265,7 +265,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW) endif ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_WIN32) GRAPHICS ?= GRAPHICS_API_OPENGL_33 - #GRAPHICS = GRAPHICS_API_OPENGL_11_SOFTWARE # Uncomment to use software rendering + #GRAPHICS = GRAPHICS_API_OPENGL_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 @@ -273,7 +273,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_WIN32) endif ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) GRAPHICS ?= GRAPHICS_API_OPENGL_ES2 - #GRAPHICS = GRAPHICS_API_OPENGL_11_SOFTWARE # Uncomment to use software rendering + #GRAPHICS = GRAPHICS_API_OPENGL_SOFTWARE # Uncomment to use software rendering endif ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW)) # On HTML5 OpenGL ES 2.0 is used, emscripten translates it to WebGL 1.0 @@ -709,7 +709,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DRM) endif ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_WIN32) LDLIBS = -lgdi32 -lwinmm -lshcore - ifneq ($(GRAPHICS),GRAPHICS_API_OPENGL_11_SOFTWARE) + ifneq ($(GRAPHICS),GRAPHICS_API_OPENGL_SOFTWARE) LDLIBS += -lopengl32 endif endif diff --git a/src/external/rlsw.h b/src/external/rlsw.h index 1166e3448..e0700024a 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -2353,7 +2353,7 @@ static inline void sw_pixel_set_depth(void *pixels, float depth, uint32_t offset switch (format) { case SW_PIXELFORMAT_DEPTH_D8: sw_pixel_set_depth_D8(pixels, depth, offset); break; - case SW_PIXELFORMAT_DEPTH_D16: w_pixel_set_depth_D16(pixels, depth, offset); break; + case SW_PIXELFORMAT_DEPTH_D16: sw_pixel_set_depth_D16(pixels, depth, offset); break; case SW_PIXELFORMAT_DEPTH_D32: sw_pixel_set_depth_D32(pixels, depth, offset); break; case SW_PIXELFORMAT_UNKNOWN: @@ -3565,7 +3565,7 @@ static inline bool sw_line_clip_coord(float q, float p, float *t0, float *t1) static bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1) { float t0 = 0.0f, t1 = 1.0f; - float dH[4] = { 0 } + float dH[4] = { 0 }; float dC[4] = { 0 }; for (int i = 0; i < 4; i++) @@ -5345,10 +5345,8 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con { vLeft.screen[1] = vRight.screen[1] = y; - if (vLeft.screen[0] < vRight.screen[0]) - SW_RASTER_TRIANGLE_SPAN(&vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); - else - SW_RASTER_TRIANGLE_SPAN(&vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); + if (vLeft.screen[0] < vRight.screen[0]) SW_RASTER_TRIANGLE_SPAN(&vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); + else SW_RASTER_TRIANGLE_SPAN(&vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02); vLeft.screen[0] += dXdy02; From 2c39703d13fb895c80ea590cbbbddc2558b18c88 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 18 Mar 2026 13:28:45 +0100 Subject: [PATCH 28/41] RENAMED: `rl_gputex` to `rltexgpu` --- src/external/{rl_gputex.h => rltexgpu.h} | 463 ++++++++++++----------- 1 file changed, 233 insertions(+), 230 deletions(-) rename src/external/{rl_gputex.h => rltexgpu.h} (74%) diff --git a/src/external/rl_gputex.h b/src/external/rltexgpu.h similarity index 74% rename from src/external/rl_gputex.h rename to src/external/rltexgpu.h index 033045bc8..eb4d2b6b1 100644 --- a/src/external/rl_gputex.h +++ b/src/external/rltexgpu.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* rl_gputex v1.1 - GPU compressed textures loading and saving +* rltexgpu v1.2 - GPU compressed textures loading and saving * * DESCRIPTION: * @@ -10,41 +10,40 @@ * Note that some file formats (DDS, PVR, KTX) also support uncompressed data storage. * In those cases data is loaded uncompressed and format is returned * -* FIXME: This library still depends on Raylib due to the following reasons: +* FIXME: This library still depends on raylib due to the following reasons: * - rl_save_ktx_to_memory() requires rlGetGlTextureFormats() from rlgl.h -* though this is not a problem, if you don't need KTX support * * TODO: * - Review rl_load_ktx_from_memory() to support KTX v2.2 specs * * CONFIGURATION: * -* #define RL_GPUTEX_SUPPORT_DDS -* #define RL_GPUTEX_SUPPORT_PKM -* #define RL_GPUTEX_SUPPORT_KTX -* #define RL_GPUTEX_SUPPORT_PVR -* #define RL_GPUTEX_SUPPORT_ASTC +* #define RLTEXGPU_SUPPORT_DDS +* #define RLTEXGPU_SUPPORT_PKM +* #define RLTEXGPU_SUPPORT_KTX +* #define RLTEXGPU_SUPPORT_PVR +* #define RLTEXGPU_SUPPORT_ASTC * Define desired file formats to be supported * -* #define RL_GPUTEX_SHOW_LOG_INFO +* #define RLTEXGPU_SHOW_LOG_INFO * Define, if you wish to see warnings generated by the library -* This will include unless you provide your own RL_GPUTEX_LOG -* #define RL_GPUTEX_LOG +* This will include unless you provide your own RLTEXGPU_LOG +* #define RLTEXGPU_LOG * Define, if you wish to provide your own warning function * Make sure that this macro puts newline character '\n' at the end * -* #define RL_GPUTEX_MALLOC -* #define RL_GPUTEX_FREE +* #define RLTEXGPU_MALLOC +* #define RLTEXGPU_FREE * Define those macros in order to provide your own libc-compliant allocator; * not doing so will include * If you're providing any of those, you must provide ALL of them, * otherwise the code will (most likely) crash... * -* #define RL_GPUTEX_NULL +* #define RLTEXGPU_NULL * Define in order to provide your own libc-compliant NULL pointer; * not doing so will include * -* #define RL_GPUTEX_MEMCPY +* #define RLTEXGPU_MEMCPY * Define in order to provide your own libc-compliant 'memcpy' function; * not doing so will include * @@ -53,12 +52,16 @@ * There is no need to do so when statically linking * * VERSIONS HISTORY: +* 1.2 (18-Mar-2026) Renamed library to `rltexgpu` +* Improved usage as standalone linrary +* Decouple logging and memory allocation from raylib +* * 1.1 (15-Jul-2025) Several minor fixes related to specific image formats; some work has been done -* in order to decouple the library from Raylib by introducing few new macros; library still -* requires Raylib in order to function properly +* in order to decouple the library from raylib by introducing few new macros; library still +* requires raylib in order to function properly * * 1.0 (17-Sep-2022) First version has been created by migrating part of compressed-texture-loading -* functionality from Raylib src/rtextures.c into self-contained library +* functionality from raylib src/rtextures.c into self-contained library * * LICENSE: zlib/libpng * @@ -81,8 +84,8 @@ * **********************************************************************************************/ -#ifndef RL_GPUTEX_H -#define RL_GPUTEX_H +#ifndef RLTEXGPU_H +#define RLTEXGPU_H #ifndef RLGPUTEXAPI #define RLGPUTEXAPI // Functions defined as 'extern' by default (implicit specifiers) @@ -93,30 +96,30 @@ // WARNING: Enum values aligned with raylib/rlgl equivalent PixelFormat/rlPixelFormat enum, // to avoid value mapping between the 3 libraries format values typedef enum { - RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) - RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) - RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G6B5, // 16 bpp - RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8, // 24 bpp - RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) - RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) - RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, // 32 bpp - RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32, // 32 bpp (1 channel - float) - RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) - RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) - RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16, // 16 bpp (1 channel - half float) - RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16, // 16*3 bpp (3 channels - half float) - RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16, // 16*4 bpp (4 channels - half float) - RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) - RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) - RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT3_RGBA, // 8 bpp - RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT5_RGBA, // 8 bpp - RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC1_RGB, // 4 bpp - RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_RGB, // 4 bpp - RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA, // 8 bpp - RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGB, // 4 bpp - RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGBA, // 4 bpp - RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA, // 8 bpp - RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA // 2 bpp + RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) + RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) + RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G6B5, // 16 bpp + RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8, // 24 bpp + RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) + RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) + RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, // 32 bpp + RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32, // 32 bpp (1 channel - float) + RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) + RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) + RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16, // 16 bpp (1 channel - half float) + RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16, // 16*3 bpp (3 channels - half float) + RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16, // 16*4 bpp (4 channels - half float) + RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) + RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) + RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT3_RGBA, // 8 bpp + RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT5_RGBA, // 8 bpp + RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC1_RGB, // 4 bpp + RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_RGB, // 4 bpp + RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA, // 8 bpp + RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGB, // 4 bpp + RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGBA, // 4 bpp + RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA, // 8 bpp + RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA // 2 bpp } rlGpuTexPixelFormat; //---------------------------------------------------------------------------------- @@ -139,7 +142,7 @@ RLGPUTEXAPI int rl_save_ktx_to_memory(const char *fileName, void *data, int widt } #endif -#endif // RL_GPUTEX_H +#endif // RLTEXGPU_H /*********************************************************************************** * @@ -147,49 +150,49 @@ RLGPUTEXAPI int rl_save_ktx_to_memory(const char *fileName, void *data, int widt * ************************************************************************************/ -#if defined(RL_GPUTEX_IMPLEMENTATION) +#if defined(RLTEXGPU_IMPLEMENTATION) -#if defined(RL_GPUTEX_SHOW_LOG_INFO) && !defined(RL_GPUTEX_LOG) +#if defined(RLTEXGPU_SHOW_LOG_INFO) && !defined(RLTEXGPU_LOG) #include // Required for: printf() #endif -#if !defined(RL_GPUTEX_MALLOC) || !defined(RL_GPUTEX_NULL) +#if !defined(RLTEXGPU_MALLOC) || !defined(RLTEXGPU_NULL) #include // Required for: NULL, malloc(), calloc(), free() #endif -#if !defined(RL_GPUTEX_MEMCPY) +#if !defined(RLTEXGPU_MEMCPY) #include // Required for: memcpy() #endif -#if defined(RL_GPUTEX_MALLOC) || defined(RL_GPUTEX_FREE) - #if !defined(RL_GPUTEX_MALLOC) || !defined(RL_GPUTEX_FREE) - #warning "RL_GPUTEX_MALLOC and RL_GPUTEX_FREE allocation functions are required to be provided" +#if defined(RLTEXGPU_MALLOC) || defined(RLTEXGPU_FREE) + #if !defined(RLTEXGPU_MALLOC) || !defined(RLTEXGPU_FREE) + #warning "RLTEXGPU_MALLOC and RLTEXGPU_FREE allocation functions are required to be provided" #endif #endif -#if !defined(RL_GPUTEX_MALLOC) - #define RL_GPUTEX_MALLOC(sz) malloc(sz) - #define RL_GPUTEX_FREE(ptr) free(ptr) +#if !defined(RLTEXGPU_MALLOC) + #define RLTEXGPU_MALLOC(sz) malloc(sz) + #define RLTEXGPU_FREE(ptr) free(ptr) #endif -#if !defined(RL_GPUTEX_NULL) - #define RL_GPUTEX_NULL NULL +#if !defined(RLTEXGPU_NULL) + #define RLTEXGPU_NULL NULL #endif -#if !defined(RL_GPUTEX_MEMCPY) - #define RL_GPUTEX_MEMCPY(dest, src, num) memcpy(dest, src, num) +#if !defined(RLTEXGPU_MEMCPY) + #define RLTEXGPU_MEMCPY(dest, src, num) memcpy(dest, src, num) #endif // Simple warning logging system to avoid LOG() calls if required // NOTE: Avoiding those calls, also avoids const strings memory usage -// WARN: This macro expects that newline character is added automatically -// in order to match the functionality of Raylib's TRACELOG() -#if defined(RL_GPUTEX_SHOW_LOG_INFO) - #if !defined(RL_GPUTEX_LOG) - #define RL_GPUTEX_LOG(...) (void)(printf("RL_GPUTEX: WARNING: " __VA_ARGS__), printf("\n")) +// WARNING: This macro expects that newline character is added automatically +// in order to match the functionality of raylib's TRACELOG() +#if defined(RLTEXGPU_SHOW_LOG_INFO) + #if !defined(RLTEXGPU_LOG) + #define RLTEXGPU_LOG(...) (void)(printf("RL_GPUTEX: WARNING: " __VA_ARGS__), printf("\n")) #endif #else - #if defined(RL_GPUTEX_LOG) + #if defined(RLTEXGPU_LOG) // Undefine it first in order to supress warnings about macro redefinition - #undef RL_GPUTEX_LOG + #undef RLTEXGPU_LOG #endif - #define RL_GPUTEX_LOG(...) + #define RLTEXGPU_LOG(...) #endif //---------------------------------------------------------------------------------- @@ -204,11 +207,11 @@ void get_gl_texture_formats(int format, unsigned int *gl_internal_format, unsign //---------------------------------------------------------------------------------- // Module Functions Definition //---------------------------------------------------------------------------------- -#if defined(RL_GPUTEX_SUPPORT_DDS) +#if defined(RLTEXGPU_SUPPORT_DDS) // Loading DDS from memory image data (compressed or uncompressed) void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips) { - void *image_data = RL_GPUTEX_NULL; // Image data pointer + void *image_data = RLTEXGPU_NULL; // Image data pointer int image_pixel_size = 0; // Image pixel size unsigned char *file_data_ptr = (unsigned char *)file_data; @@ -256,7 +259,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ unsigned int reserved2; } dds_header; - if (file_data_ptr != RL_GPUTEX_NULL) + if (file_data_ptr != RLTEXGPU_NULL) { // Verify the type of file unsigned char *dds_header_id = file_data_ptr; @@ -264,7 +267,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ if ((dds_header_id[0] != 'D') || (dds_header_id[1] != 'D') || (dds_header_id[2] != 'S') || (dds_header_id[3] != ' ')) { - RL_GPUTEX_LOG("DDS file data not valid"); + RLTEXGPU_LOG("DDS file data not valid"); } else { @@ -275,8 +278,8 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ *width = header->width; *height = header->height; - if (*width % 4 != 0) RL_GPUTEX_LOG("DDS file width must be multiple of 4. Image will not display correctly"); - if (*height % 4 != 0) RL_GPUTEX_LOG("DDS file height must be multiple of 4. Image will not display correctly"); + if (*width % 4 != 0) RLTEXGPU_LOG("DDS file width must be multiple of 4. Image will not display correctly"); + if (*height % 4 != 0) RLTEXGPU_LOG("DDS file height must be multiple of 4. Image will not display correctly"); image_pixel_size = header->width*header->height; @@ -289,11 +292,11 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ { int data_size = image_pixel_size*sizeof(unsigned short); if (header->mipmap_count > 1) data_size = data_size + data_size/3; - image_data = RL_GPUTEX_MALLOC(data_size); + image_data = RLTEXGPU_MALLOC(data_size); - RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size); + RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size); - *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G6B5; + *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G6B5; } else if (header->ddspf.flags == 0x41) // With alpha channel { @@ -301,9 +304,9 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ { int data_size = image_pixel_size*sizeof(unsigned short); if (header->mipmap_count > 1) data_size = data_size + data_size/3; - image_data = RL_GPUTEX_MALLOC(data_size); + image_data = RLTEXGPU_MALLOC(data_size); - RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size); + RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size); unsigned char alpha = 0; @@ -315,15 +318,15 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ ((unsigned short *)image_data)[i] += alpha; } - *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1; + *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1; } else if (header->ddspf.a_bit_mask == 0xf000) // 4bit alpha { int data_size = image_pixel_size*sizeof(unsigned short); if (header->mipmap_count > 1) data_size = data_size + data_size/3; - image_data = RL_GPUTEX_MALLOC(data_size); + image_data = RLTEXGPU_MALLOC(data_size); - RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size); + RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size); unsigned char alpha = 0; @@ -335,7 +338,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ ((unsigned short *)image_data)[i] += alpha; } - *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4; + *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4; } } } @@ -343,19 +346,19 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ { int data_size = image_pixel_size*3*sizeof(unsigned char); if (header->mipmap_count > 1) data_size = data_size + data_size/3; - image_data = RL_GPUTEX_MALLOC(data_size); + image_data = RLTEXGPU_MALLOC(data_size); - RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size); + RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size); - *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8; + *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8; } else if ((header->ddspf.flags == 0x41) && (header->ddspf.rgb_bit_count == 32)) // DDS_RGBA, no compressed { int data_size = image_pixel_size*4*sizeof(unsigned char); if (header->mipmap_count > 1) data_size = data_size + data_size/3; - image_data = RL_GPUTEX_MALLOC(data_size); + image_data = RLTEXGPU_MALLOC(data_size); - RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size); + RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size); unsigned char blue = 0; @@ -369,7 +372,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ ((unsigned char *)image_data)[i + 2] = blue; } - *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; } else if (((header->ddspf.flags == 0x04) || (header->ddspf.flags == 0x05)) && (header->ddspf.fourcc > 0)) // Compressed { @@ -379,19 +382,19 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ if (header->mipmap_count > 1) data_size = header->pitch_or_linear_size + header->pitch_or_linear_size/3; else data_size = header->pitch_or_linear_size; - image_data = RL_GPUTEX_MALLOC(data_size*sizeof(unsigned char)); + image_data = RLTEXGPU_MALLOC(data_size*sizeof(unsigned char)); - RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size); + RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size); switch (header->ddspf.fourcc) { case FOURCC_DXT1: { - if (header->ddspf.flags == 0x04) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGB; - else *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGBA; + if (header->ddspf.flags == 0x04) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGB; + else *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGBA; } break; - case FOURCC_DXT3: *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT3_RGBA; break; - case FOURCC_DXT5: *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT5_RGBA; break; + case FOURCC_DXT3: *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT3_RGBA; break; + case FOURCC_DXT5: *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT5_RGBA; break; default: break; } } @@ -402,13 +405,13 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ } #endif -#if defined(RL_GPUTEX_SUPPORT_PKM) +#if defined(RLTEXGPU_SUPPORT_PKM) // Loading PKM image data (ETC1/ETC2 compression) // NOTE: KTX is the standard Khronos Group compression format (ETC1/ETC2, mipmaps) // PKM is a much simpler file format used mainly to contain a single ETC1/ETC2 compressed image (no mipmaps) void *rl_load_pkm_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips) { - void *image_data = RL_GPUTEX_NULL; // Image data pointer + void *image_data = RLTEXGPU_NULL; // Image data pointer unsigned char *file_data_ptr = (unsigned char *)file_data; @@ -439,13 +442,13 @@ void *rl_load_pkm_from_memory(const unsigned char *file_data, unsigned int file_ // NOTE: The extended width and height are the widths rounded up to a multiple of 4 // NOTE: ETC is always 4bit per pixel (64 bit for each 4x4 block of pixels) - if (file_data_ptr != RL_GPUTEX_NULL) + if (file_data_ptr != RLTEXGPU_NULL) { pkm_header *header = (pkm_header *)file_data_ptr; if ((header->id[0] != 'P') || (header->id[1] != 'K') || (header->id[2] != 'M') || (header->id[3] != ' ')) { - RL_GPUTEX_LOG("PKM file data not valid"); + RLTEXGPU_LOG("PKM file data not valid"); } else { @@ -465,13 +468,13 @@ void *rl_load_pkm_from_memory(const unsigned char *file_data, unsigned int file_ int data_size = (*width)*(*height)*bpp/8; // Total data size in bytes - image_data = RL_GPUTEX_MALLOC(data_size*sizeof(unsigned char)); + image_data = RLTEXGPU_MALLOC(data_size*sizeof(unsigned char)); - RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size); + RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size); - if (header->format == 0) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC1_RGB; - else if (header->format == 1) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_RGB; - else if (header->format == 3) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA; + if (header->format == 0) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC1_RGB; + else if (header->format == 1) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_RGB; + else if (header->format == 3) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA; } } @@ -479,12 +482,12 @@ void *rl_load_pkm_from_memory(const unsigned char *file_data, unsigned int file_ } #endif -#if defined(RL_GPUTEX_SUPPORT_KTX) +#if defined(RLTEXGPU_SUPPORT_KTX) // Load KTX compressed image data (ETC1/ETC2 compression) // TODO: Review KTX loading, many things changed! void *rl_load_ktx_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips) { - void *image_data = RL_GPUTEX_NULL; // Image data pointer + void *image_data = RLTEXGPU_NULL; // Image data pointer unsigned char *file_data_ptr = (unsigned char *)file_data; @@ -522,14 +525,14 @@ void *rl_load_ktx_from_memory(const unsigned char *file_data, unsigned int file_ // NOTE: Before start of every mipmap data block, we have: unsigned int data_size - if (file_data_ptr != RL_GPUTEX_NULL) + if (file_data_ptr != RLTEXGPU_NULL) { ktx_header *header = (ktx_header *)file_data_ptr; if ((header->id[1] != 'K') || (header->id[2] != 'T') || (header->id[3] != 'X') || (header->id[4] != ' ') || (header->id[5] != '1') || (header->id[6] != '1')) { - RL_GPUTEX_LOG("KTX file data not valid"); + RLTEXGPU_LOG("KTX file data not valid"); } else { @@ -544,13 +547,13 @@ void *rl_load_ktx_from_memory(const unsigned char *file_data, unsigned int file_ int data_size = ((int *)file_data_ptr)[0]; file_data_ptr += sizeof(int); - image_data = RL_GPUTEX_MALLOC(data_size*sizeof(unsigned char)); + image_data = RLTEXGPU_MALLOC(data_size*sizeof(unsigned char)); - RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size); + RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size); - if (header->gl_internal_format == 0x8D64) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC1_RGB; - else if (header->gl_internal_format == 0x9274) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_RGB; - else if (header->gl_internal_format == 0x9278) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA; + if (header->gl_internal_format == 0x8D64) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC1_RGB; + else if (header->gl_internal_format == 0x9274) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_RGB; + else if (header->gl_internal_format == 0x9278) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA; // TODO: Support uncompressed data formats? Right now it returns format = 0! } @@ -608,7 +611,7 @@ int rl_save_ktx(const char *file_name, void *data, int width, int height, int fo w /= 2; h /= 2; } - unsigned char *file_data = RL_GPUTEX_MALLOC(data_size); + unsigned char *file_data = RLTEXGPU_MALLOC(data_size); unsigned char *file_data_ptr = file_data; ktx_header header = { 0 }; @@ -620,7 +623,7 @@ int rl_save_ktx(const char *file_name, void *data, int width, int height, int fo const char ktx_identifier[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' }; // Get the image header - RL_GPUTEX_MEMCPY(header.id, ktx_identifier, 12); // KTX 1.1 signature + RLTEXGPU_MEMCPY(header.id, ktx_identifier, 12); // KTX 1.1 signature header.endianness = 0; header.gl_type = 0; // Obtained from format header.gl_type_size = 1; @@ -642,10 +645,10 @@ int rl_save_ktx(const char *file_name, void *data, int width, int height, int fo // NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC - if (header.gl_format == -1) RL_GPUTEX_LOG("RL_GPUTEX: GL format not supported for KTX export (%i)", header.gl_format); + if (header.gl_format == -1) RLTEXGPU_LOG("RL_GPUTEX: GL format not supported for KTX export (%i)", header.gl_format); else { - RL_GPUTEX_MEMCPY(file_data_ptr, &header, sizeof(ktx_header)); + RLTEXGPU_MEMCPY(file_data_ptr, &header, sizeof(ktx_header)); file_data_ptr += sizeof(ktx_header); int temp_width = width; @@ -657,8 +660,8 @@ int rl_save_ktx(const char *file_name, void *data, int width, int height, int fo { unsigned int data_size = get_pixel_data_size(temp_width, temp_height, format); - RL_GPUTEX_MEMCPY(file_data_ptr, &data_size, sizeof(unsigned int)); - RL_GPUTEX_MEMCPY(file_data_ptr + 4, (unsigned char *)data + data_offset, data_size); + RLTEXGPU_MEMCPY(file_data_ptr, &data_size, sizeof(unsigned int)); + RLTEXGPU_MEMCPY(file_data_ptr + 4, (unsigned char *)data + data_offset, data_size); temp_width /= 2; temp_height /= 2; @@ -671,34 +674,34 @@ int rl_save_ktx(const char *file_name, void *data, int width, int height, int fo int success = false; FILE *file = fopen(file_name, "wb"); - if (file != RL_GPUTEX_NULL) + if (file != RLTEXGPU_NULL) { unsigned int count = (unsigned int)fwrite(file_data, sizeof(unsigned char), data_size, file); - if (count == 0) RL_GPUTEX_LOG("FILEIO: [%s] Failed to write file", file_name); - else if (count != data_size) RL_GPUTEX_LOG("FILEIO: [%s] File partially written", file_name); - else (void)0; // WARN: this branch is handled by Raylib, since rl_gputex only prints warnings + if (count == 0) RLTEXGPU_LOG("FILEIO: [%s] Failed to write file", file_name); + else if (count != data_size) RLTEXGPU_LOG("FILEIO: [%s] File partially written", file_name); + else (void)0; int result = fclose(file); - if (result != 0) RL_GPUTEX_LOG("FILEIO: [%s] Failed to close file", file_name); + if (result != 0) RLTEXGPU_LOG("FILEIO: [%s] Failed to close file", file_name); if (result == 0 && count == data_size) success = true; } - else RL_GPUTEX_LOG("FILEIO: [%s] Failed to open file", file_name); + else RLTEXGPU_LOG("FILEIO: [%s] Failed to open file", file_name); - RL_GPUTEX_FREE(file_data); // Free file data buffer + RLTEXGPU_FREE(file_data); // Free file data buffer // If all data has been written correctly to file, success = 1 return success; } #endif -#if defined(RL_GPUTEX_SUPPORT_PVR) +#if defined(RLTEXGPU_SUPPORT_PVR) // Loading PVR image data (uncompressed or PVRT compression) // NOTE: PVR v2 not supported, use PVR v3 instead void *rl_load_pvr_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips) { - void *image_data = RL_GPUTEX_NULL; // Image data pointer + void *image_data = RLTEXGPU_NULL; // Image data pointer unsigned char *file_data_ptr = (unsigned char *)file_data; @@ -756,7 +759,7 @@ void *rl_load_pvr_from_memory(const unsigned char *file_data, unsigned int file_ } PVRMetadata; #endif - if (file_data_ptr != RL_GPUTEX_NULL) + if (file_data_ptr != RLTEXGPU_NULL) { // Check PVR image version unsigned char pvr_version = file_data_ptr[0]; @@ -768,7 +771,7 @@ void *rl_load_pvr_from_memory(const unsigned char *file_data, unsigned int file_ if ((header->id[0] != 'P') || (header->id[1] != 'V') || (header->id[2] != 'R') || (header->id[3] != 3)) { - RL_GPUTEX_LOG("PVR file data not valid"); + RLTEXGPU_LOG("PVR file data not valid"); } else { @@ -779,24 +782,24 @@ void *rl_load_pvr_from_memory(const unsigned char *file_data, unsigned int file_ *mips = header->num_mipmaps; // Check data format - if (((header->channels[0] == 'l') && (header->channels[1] == 0)) && (header->channel_depth[0] == 8)) *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; - else if (((header->channels[0] == 'l') && (header->channels[1] == 'a')) && ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8))) *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA; + if (((header->channels[0] == 'l') && (header->channels[1] == 0)) && (header->channel_depth[0] == 8)) *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; + else if (((header->channels[0] == 'l') && (header->channels[1] == 'a')) && ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8))) *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA; else if ((header->channels[0] == 'r') && (header->channels[1] == 'g') && (header->channels[2] == 'b')) { if (header->channels[3] == 'a') { - if ((header->channel_depth[0] == 5) && (header->channel_depth[1] == 5) && (header->channel_depth[2] == 5) && (header->channel_depth[3] == 1)) *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1; - else if ((header->channel_depth[0] == 4) && (header->channel_depth[1] == 4) && (header->channel_depth[2] == 4) && (header->channel_depth[3] == 4)) *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4; - else if ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8) && (header->channel_depth[2] == 8) && (header->channel_depth[3] == 8)) *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + if ((header->channel_depth[0] == 5) && (header->channel_depth[1] == 5) && (header->channel_depth[2] == 5) && (header->channel_depth[3] == 1)) *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1; + else if ((header->channel_depth[0] == 4) && (header->channel_depth[1] == 4) && (header->channel_depth[2] == 4) && (header->channel_depth[3] == 4)) *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4; + else if ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8) && (header->channel_depth[2] == 8) && (header->channel_depth[3] == 8)) *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; } else if (header->channels[3] == 0) { - if ((header->channel_depth[0] == 5) && (header->channel_depth[1] == 6) && (header->channel_depth[2] == 5)) *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G6B5; - else if ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8) && (header->channel_depth[2] == 8)) *format = RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8; + if ((header->channel_depth[0] == 5) && (header->channel_depth[1] == 6) && (header->channel_depth[2] == 5)) *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G6B5; + else if ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8) && (header->channel_depth[2] == 8)) *format = RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8; } } - else if (header->channels[0] == 2) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGB; - else if (header->channels[0] == 3) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGBA; + else if (header->channels[0] == 2) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGB; + else if (header->channels[0] == 3) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGBA; file_data_ptr += header->metadata_size; // Skip meta data header @@ -804,36 +807,36 @@ void *rl_load_pvr_from_memory(const unsigned char *file_data, unsigned int file_ int bpp = 0; switch (*format) { - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G6B5: - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break; - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGB: - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G6B5: + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break; + case RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGB: + case RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break; default: break; } int data_size = (*width)*(*height)*bpp/8; // Total data size in bytes - image_data = RL_GPUTEX_MALLOC(data_size*sizeof(unsigned char)); + image_data = RLTEXGPU_MALLOC(data_size*sizeof(unsigned char)); - RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size); + RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size); } } - else if (pvr_version == 52) RL_GPUTEX_LOG("PVRv2 format not supported, update your files to PVRv3"); + else if (pvr_version == 52) RLTEXGPU_LOG("PVRv2 format not supported, update your files to PVRv3"); } return image_data; } #endif -#if defined(RL_GPUTEX_SUPPORT_ASTC) +#if defined(RLTEXGPU_SUPPORT_ASTC) // Load ASTC compressed image data (ASTC compression) void *rl_load_astc_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips) { - void *image_data = RL_GPUTEX_NULL; // Image data pointer + void *image_data = RLTEXGPU_NULL; // Image data pointer unsigned char *file_data_ptr = (unsigned char *)file_data; @@ -856,13 +859,13 @@ void *rl_load_astc_from_memory(const unsigned char *file_data, unsigned int file unsigned char length[3]; // void *Z-size (1 for 2D images) } astc_header; - if (file_data_ptr != RL_GPUTEX_NULL) + if (file_data_ptr != RLTEXGPU_NULL) { astc_header *header = (astc_header *)file_data_ptr; if ((header->id[3] != 0x5c) || (header->id[2] != 0xa1) || (header->id[1] != 0xab) || (header->id[0] != 0x13)) { - RL_GPUTEX_LOG("ASTC file data not valid"); + RLTEXGPU_LOG("ASTC file data not valid"); } else { @@ -881,14 +884,14 @@ void *rl_load_astc_from_memory(const unsigned char *file_data, unsigned int file { int data_size = (*width)*(*height)*bpp/8; // Data size in bytes - image_data = RL_GPUTEX_MALLOC(data_size*sizeof(unsigned char)); + image_data = RLTEXGPU_MALLOC(data_size*sizeof(unsigned char)); - RL_GPUTEX_MEMCPY(image_data, file_data_ptr, data_size); + RLTEXGPU_MEMCPY(image_data, file_data_ptr, data_size); - if (bpp == 8) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA; - else if (bpp == 2) *format = RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA; + if (bpp == 8) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA; + else if (bpp == 2) *format = RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA; } - else RL_GPUTEX_LOG("ASTC block size configuration not supported"); + else RLTEXGPU_LOG("ASTC block size configuration not supported"); } } @@ -907,27 +910,27 @@ static int get_pixel_data_size(int width, int height, int format) switch (format) { - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G6B5: - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32: bpp = 32; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 32*3; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break; - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGB: - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGBA: - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC1_RGB: - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_RGB: - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGB: - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break; - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT3_RGBA: - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT5_RGBA: - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break; - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G6B5: + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32: bpp = 32; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 32*3; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break; + case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGB: + case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGBA: + case RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC1_RGB: + case RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_RGB: + case RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGB: + case RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break; + case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT3_RGBA: + case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT5_RGBA: + case RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: + case RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break; + case RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break; default: break; } @@ -937,8 +940,8 @@ static int get_pixel_data_size(int width, int height, int format) // if texture is smaller, minimum dataSize is 8 or 16 if ((width < 4) && (height < 4)) { - if ((format >= RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT3_RGBA)) data_size = 8; - else if ((format >= RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) data_size = 16; + if ((format >= RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT3_RGBA)) data_size = 8; + else if ((format >= RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) data_size = 16; } return data_size; @@ -959,69 +962,69 @@ void get_gl_texture_formats(int format, unsigned int *gl_internal_format, unsign { #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2) // NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_UNSIGNED_BYTE; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *gl_internal_format = GL_LUMINANCE_ALPHA; *gl_format = GL_LUMINANCE_ALPHA; *gl_type = GL_UNSIGNED_BYTE; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G6B5: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_SHORT_5_6_5; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_BYTE; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_5_5_5_1; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_4_4_4_4; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_BYTE; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_UNSIGNED_BYTE; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *gl_internal_format = GL_LUMINANCE_ALPHA; *gl_format = GL_LUMINANCE_ALPHA; *gl_type = GL_UNSIGNED_BYTE; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G6B5: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_SHORT_5_6_5; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_BYTE; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_5_5_5_1; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_4_4_4_4; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_BYTE; break; #if !defined(GRAPHICS_API_OPENGL_11) #if defined(GRAPHICS_API_OPENGL_ES3) - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32: *gl_internal_format = GL_R32F_EXT; *gl_format = GL_RED_EXT; *gl_type = GL_FLOAT; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32: *gl_internal_format = GL_RGB32F_EXT; *gl_format = GL_RGB; *gl_type = GL_FLOAT; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: *gl_internal_format = GL_RGBA32F_EXT; *gl_format = GL_RGBA; *gl_type = GL_FLOAT; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_R16F_EXT; *gl_format = GL_RED_EXT; *gl_type = GL_HALF_FLOAT; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB16F_EXT; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA16F_EXT; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32: *gl_internal_format = GL_R32F_EXT; *gl_format = GL_RED_EXT; *gl_type = GL_FLOAT; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32: *gl_internal_format = GL_RGB32F_EXT; *gl_format = GL_RGB; *gl_type = GL_FLOAT; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: *gl_internal_format = GL_RGBA32F_EXT; *gl_format = GL_RGBA; *gl_type = GL_FLOAT; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_R16F_EXT; *gl_format = GL_RED_EXT; *gl_type = GL_HALF_FLOAT; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB16F_EXT; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA16F_EXT; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT; break; #else - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float #if defined(GRAPHICS_API_OPENGL_21) - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_HALF_FLOAT_ARB; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT_ARB; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT_ARB; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_HALF_FLOAT_ARB; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT_ARB; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT_ARB; break; #else // defined(GRAPHICS_API_OPENGL_ES2) - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_LUMINANCE; *gl_format = GL_LUMINANCE; *gl_type = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float #endif #endif #endif #elif defined(GRAPHICS_API_OPENGL_33) - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *gl_internal_format = GL_R8; *gl_format = GL_RED; *gl_type = GL_UNSIGNED_BYTE; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *gl_internal_format = GL_RG8; *gl_format = GL_RG; *gl_type = GL_UNSIGNED_BYTE; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G6B5: *gl_internal_format = GL_RGB565; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_SHORT_5_6_5; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8: *gl_internal_format = GL_RGB8; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_BYTE; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *gl_internal_format = GL_RGB5_A1; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_5_5_5_1; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *gl_internal_format = GL_RGBA4; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_4_4_4_4; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *gl_internal_format = GL_RGBA8; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_BYTE; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32: *gl_internal_format = GL_R32F; *gl_format = GL_RED; *gl_type = GL_FLOAT; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32: *gl_internal_format = GL_RGB32F; *gl_format = GL_RGB; *gl_type = GL_FLOAT; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: *gl_internal_format = GL_RGBA32F; *gl_format = GL_RGBA; *gl_type = GL_FLOAT; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_R16F; *gl_format = GL_RED; *gl_type = GL_HALF_FLOAT; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB16F; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT; break; - case RL_GPUTEX_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA16F; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *gl_internal_format = GL_R8; *gl_format = GL_RED; *gl_type = GL_UNSIGNED_BYTE; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *gl_internal_format = GL_RG8; *gl_format = GL_RG; *gl_type = GL_UNSIGNED_BYTE; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G6B5: *gl_internal_format = GL_RGB565; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_SHORT_5_6_5; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8: *gl_internal_format = GL_RGB8; *gl_format = GL_RGB; *gl_type = GL_UNSIGNED_BYTE; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *gl_internal_format = GL_RGB5_A1; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_5_5_5_1; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *gl_internal_format = GL_RGBA4; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_SHORT_4_4_4_4; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *gl_internal_format = GL_RGBA8; *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_BYTE; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32: *gl_internal_format = GL_R32F; *gl_format = GL_RED; *gl_type = GL_FLOAT; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32: *gl_internal_format = GL_RGB32F; *gl_format = GL_RGB; *gl_type = GL_FLOAT; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: *gl_internal_format = GL_RGBA32F; *gl_format = GL_RGBA; *gl_type = GL_FLOAT; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16: *gl_internal_format = GL_R16F; *gl_format = GL_RED; *gl_type = GL_HALF_FLOAT; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16: *gl_internal_format = GL_RGB16F; *gl_format = GL_RGB; *gl_type = GL_HALF_FLOAT; break; + case RLTEXGPU_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: *gl_internal_format = GL_RGBA16F; *gl_format = GL_RGBA; *gl_type = GL_HALF_FLOAT; break; #endif #if !defined(GRAPHICS_API_OPENGL_11) - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGB: *gl_internal_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT1_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT3_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_DXT5_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC1_RGB: *gl_internal_format = GL_ETC1_RGB8_OES; break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3 - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_RGB: *gl_internal_format = GL_COMPRESSED_RGB8_ETC2; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA8_ETC2_EAC; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGB: *gl_internal_format = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_PVRT_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 - case RL_GPUTEX_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 + case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGB: *gl_internal_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; + case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT1_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; + case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT3_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; + case RLTEXGPU_PIXELFORMAT_COMPRESSED_DXT5_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; + case RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC1_RGB: *gl_internal_format = GL_ETC1_RGB8_OES; break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3 + case RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_RGB: *gl_internal_format = GL_COMPRESSED_RGB8_ETC2; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 + case RLTEXGPU_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA8_ETC2_EAC; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 + case RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGB: *gl_internal_format = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU + case RLTEXGPU_PIXELFORMAT_COMPRESSED_PVRT_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU + case RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 + case RLTEXGPU_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: *gl_internal_format = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 #endif - default: RL_GPUTEX_LOG("GPUTEX: Current format not supported (%i)", format); break; + default: RLTEXGPU_LOG("GPUTEX: Current format not supported (%i)", format); break; } */ } -#endif // RL_GPUTEX_IMPLEMENTATION +#endif // RLTEXGPU_IMPLEMENTATION /* // OpenGL texture data formats From 29e4b775809a52c3952de6873c7619fb95b276c2 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 18 Mar 2026 13:29:36 +0100 Subject: [PATCH 29/41] RENAMED: `rl_gputex` to `rltexgpu` --- CHANGELOG | 7 ++++--- HISTORY.md | 2 +- src/raylib.h | 2 +- src/rtextures.c | 24 ++++++++++++------------ 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f6a3e8ad1..053ff3018 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -747,12 +747,13 @@ Detailed changes: [rexm] REVIEWED: `Makefile.Web` before trying to rebuild new example for web by @raysan5 [rexm] REVIEWED: Using `Makefile.Web` for specific web versions generation by @raysan5 +[external] RENAMED: `rl_gputex.h` to `rltexgpu.h`, compressed textures loading +[external] REVIEWED: `rltexgpu.h`, make it usable standalone by @raysan5 +[external] REVIEWED: `rltexgpu.h, fix the swizzling in `rl_load_dds_from_memory()` (#5422) by @msmith-codes +[external]`REVIEWED: `rltexgpu.h, decouple logging and memory allocation from raylib by @sleeptightAnsiC [external] REVIEWED: `jar_mod.h`, buffer overflow on memcpy by @LoneAuios [external] REVIEWED: `sdefl` and `sinfl` issues (#5367) by @raysan5 [external] REVIEWED: `sinfl_bsr()`, improvements by @RicoP -[external] REVIEWED: `rl_gputex.h`, make it usable standalone by @raysan5 -[external] REVIEWED: `rl_gputex.h,, fix the swizzling in `rl_load_dds_from_memory()` (#5422) by @msmith-codes -[external]`REVIEWED: `rl_gputex.h,, decouple logging and memory allocation from raylib by @sleeptightAnsiC [external] REVIEWED: `stb_truetype`, fix composite glyph scaling logic (#4811) by @ashishbhattarai [external] UPDATED: dr_libs (#5020) by @Emil2010 [external] UPDATED: miniaudio to v0.11.22 (#4983) by @M374LX diff --git a/HISTORY.md b/HISTORY.md index 4fc5569d5..b68ee44f4 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -419,7 +419,7 @@ Highlights for `raylib 4.5`: - **`NEW` Support QOA audio format (import/export)**: Just a couple of months ago the new [QOA file format](https://qoaformat.org/) was published, a very simple, portable and open source quite-ok-audio file format. raylib already supports it, added to `raudio` module and including audio loading from file, loading from memory, streaming from file, streaming from memory and **exporting to QOA** audio format. **Because simplicity really matters to raylib!** - - **`NEW` Module for compressed textures loading**: [`rl_gputex`](https://github.com/raysan5/raylib/blob/master/src/external/rl_gputex.h), a portable single-file header-only small library to load compressed texture file-formats (DDS, PKM, KTX, PVR, ASTC). Provided functionality is not new to raylib but it was part of the raylib `rtextures` module, now it has been moved into a separate self-contained library, **improving portability**. Note that this module is only intended to **load compressed data from files, ready to be uploaded to GPU**, no compression/decompression functionality is provided. This change is a first step towards a better modularization of raylib library. + - **`NEW` Module for compressed textures loading**: [`rl_gputex`](https://github.com/raysan5/raylib/blob/master/src/external/rltexgpu.h), a portable single-file header-only small library to load compressed texture file-formats (DDS, PKM, KTX, PVR, ASTC). Provided functionality is not new to raylib but it was part of the raylib `rtextures` module, now it has been moved into a separate self-contained library, **improving portability**. Note that this module is only intended to **load compressed data from files, ready to be uploaded to GPU**, no compression/decompression functionality is provided. This change is a first step towards a better modularization of raylib library. - **Reviewed `rlgl` module for automatic limits checking**: Again, [`rlgl`](https://github.com/raysan5/raylib/blob/master/src/rlgl.h) has been reviewed to simplify usage. Now users do not need to worry about reaching the internal render-batch limits when they send their triangles to draw 2d/3d, `rlgl` manages it automatically! This change allows a **great simplification for other modules** like `rshapes`, `rtextures` and `rmodels` that do not need to worry about bufffer overflows and can just define as many vertex as desired! diff --git a/src/raylib.h b/src/raylib.h index 951f1ffb3..2e849c917 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -40,7 +40,7 @@ * [rtextures] stb_image_write (Sean Barret) for image writing (BMP, TGA, PNG, JPG) * [rtextures] stb_image_resize2 (Sean Barret) for image resizing algorithms * [rtextures] stb_perlin (Sean Barret) for Perlin Noise image generation -* [rtextures] rl_gputex (Ramon Santamaria) for GPU-compressed texture formats +* [rtextures] rltexgpu (Ramon Santamaria) for GPU-compressed texture formats * [rtext] stb_truetype (Sean Barret) for ttf fonts loading * [rtext] stb_rect_pack (Sean Barret) for rectangles packing * [rmodels] par_shapes (Philip Rideout) for parametric 3d shapes generation diff --git a/src/rtextures.c b/src/rtextures.c index cf19edd1e..45b615cf7 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -100,19 +100,19 @@ #endif #if SUPPORT_FILEFORMAT_DDS - #define RL_GPUTEX_SUPPORT_DDS + #define RLTEXGPU_SUPPORT_DDS #endif #if SUPPORT_FILEFORMAT_PKM - #define RL_GPUTEX_SUPPORT_PKM + #define RLTEXGPU_SUPPORT_PKM #endif #if SUPPORT_FILEFORMAT_KTX - #define RL_GPUTEX_SUPPORT_KTX + #define RLTEXGPU_SUPPORT_KTX #endif #if SUPPORT_FILEFORMAT_PVR - #define RL_GPUTEX_SUPPORT_PVR + #define RLTEXGPU_SUPPORT_PVR #endif #if SUPPORT_FILEFORMAT_ASTC - #define RL_GPUTEX_SUPPORT_ASTC + #define RLTEXGPU_SUPPORT_ASTC #endif // Image fileformats not supported by default @@ -161,13 +161,13 @@ #pragma GCC diagnostic ignored "-Wunused-function" #endif - #define RL_GPUTEX_MALLOC RL_MALLOC - #define RL_GPUTEX_FREE RL_FREE - #define RL_GPUTEX_LOG(...) TRACELOG(LOG_WARNING, "IMAGE: " __VA_ARGS__) - #define RL_GPUTEX_SHOW_LOG_INFO - #define RL_GPUTEX_IMPLEMENTATION - #include "external/rl_gputex.h" // Required for: rl_load_xxx_from_memory() - // NOTE: Used to read compressed textures data (multiple formats support) + #define RLTEXGPU_MALLOC RL_MALLOC + #define RLTEXGPU_FREE RL_FREE + #define RLTEXGPU_LOG(...) TRACELOG(LOG_WARNING, "IMAGE: " __VA_ARGS__) + #define RLTEXGPU_SHOW_LOG_INFO + #define RLTEXGPU_IMPLEMENTATION + #include "external/rltexgpu.h" // Required for: rl_load_xxx_from_memory() + // NOTE: Used to read compressed textures data (multiple formats support) #if defined(__GNUC__) // GCC and Clang #pragma GCC diagnostic pop #endif From f23319db3c188d23ec22bb207eaf9bd0b8ac7620 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 18 Mar 2026 13:29:51 +0100 Subject: [PATCH 30/41] Update ROADMAP.md --- ROADMAP.md | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 9d333089a..441a811d2 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -13,16 +13,28 @@ Here is a wishlist with features and ideas to improve the library. Note that fea _Current version of raylib is complete and functional but there is always room for improvements._ -**raylib 5.x** - - [ ] `rcore`: Support additional platforms: iOS, consoles? - - [x] `rcore_web`: Avoid GLFW dependency, functionality can be directly implemented using emscripten SDK - - [x] `rlgl`: Review GLSL shaders naming conventions for consistency - - [ ] `textures`: Improve compressed textures support, loading and saving +**raylib 7.0** + - [ ] `rcore_desktop_win32`: Improve new Windows platform backend - inputs, highdpi + - [ ] `rcore_desktop_emscripten`: Improve new Web platform backend - inputs, highdpi + - [ ] `rcore_desktop_cocoa`: Create additional platform backend: macOS + - [ ] `rcore_desktop_x11`: Create additional platform backend: Linux/X11 + - [ ] `rcore_desktop_wayland`: Create additional platform backend: Linux/Wayland + - [ ] `rcore`: Investigate alternative embedded platforms and realtime OSs + - [ ] `rlsw`: Software renderer optimizations, platform-specific, improve SIMD support + - [ ] `rtextures`: Consider moving N-patch system to separate example + - [ ] `rtextures`: Review blending modes system, provide more options or better samples + - [ ] `raudio`: Support microphone input, basic API to read microphone + - [ ] `rltexgpu`: Improve compressed textures support, loading and saving, improve KTX 2.0 + - [ ] `rlobj`: Create OBJ loader, supporting material file separately (low priority) + +**raylib 6.0** + - [x] `rlsw`: New Software Renderer backend, pseudo-OpenGL 1.1 implementation + - [x] `rcore_emscripten`: New emscripten-only backend, avoiding GLFW dependency + - [x] `rlgl`: Review GLSL shaders naming conventions for consistency, redesigned shader API - [x] `rmodels`: Improve 3d objects loading, specially animations (obj, gltf) - [x] `examples`: Review all examples, add more and better code explanations - - [x] Software renderer backend? Maybe using `Image` provided API -**raylib 4.x** +**raylib 5.0** - [x] Split core module into separate platforms? - [x] Redesign gestures system, improve touch inputs management - [x] Redesign camera module (more flexible) ([#1143](https://github.com/raysan5/raylib/issues/1143), https://github.com/raysan5/raylib/discussions/2507) @@ -30,7 +42,6 @@ _Current version of raylib is complete and functional but there is always room f - [x] Focus on HTML5 ([raylib 5k gamejam](https://itch.io/jam/raylib-5k-gamejam)) and embedded platforms (RPI and similar SOCs) - [x] Additional support libraries: [raygui](https://github.com/raysan5/raygui), [rres](https://github.com/raysan5/rres) - **raylib 4.0** - [x] Improved consistency and coherency in raylib API - [x] Continuous Deployment using GitHub Actions From 85df4e7de54031638c8957c5f550b3191e0535e6 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 18 Mar 2026 13:31:09 +0100 Subject: [PATCH 31/41] REVIEWED: `rlsw`, use provided library information --- src/external/rlsw.h | 6 +++--- src/platforms/rcore_desktop_sdl.c | 2 +- src/platforms/rcore_desktop_win32.c | 9 +++++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index e0700024a..3c908a82f 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -4050,9 +4050,9 @@ const char *swGetString(SWget name) switch (name) { - case SW_VENDOR: result = "RLSW Header"; break; - case SW_RENDERER: result = "RLSW Software Renderer"; break; - case SW_VERSION: result = "RLSW 1.0"; break; + case SW_VENDOR: result = "RLSW"; break; + case SW_RENDERER: result = "RLSW OpenGL Software Renderer"; break; + case SW_VERSION: result = RLSW_VERSION; break; case SW_EXTENSIONS: result = "None"; break; default: RLSW.errCode = SW_INVALID_ENUM; break; } diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 2bf846be0..92c1979b3 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -2166,7 +2166,7 @@ static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode) return mapScancodeToKey[sdlScancode]; } - return KEY_NULL; // No equivalent key in Raylib + return KEY_NULL; // No equivalent key in raylib } // Get next codepoint in a byte sequence and bytes processed diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index 612800b83..afbbedffc 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -1652,9 +1652,9 @@ int InitPlatform(void) if (rlGetVersion() == RL_OPENGL_SOFTWARE) // Using software renderer { TRACELOG(LOG_INFO, "GL: OpenGL device information:"); - TRACELOG(LOG_INFO, " > Vendor: %s", "raylib"); - TRACELOG(LOG_INFO, " > Renderer: %s", "rlsw - OpenGL Software Renderer"); - TRACELOG(LOG_INFO, " > Version: %s", "1.0"); + TRACELOG(LOG_INFO, " > Vendor: %s", glGetString(GL_VENDOR)); + TRACELOG(LOG_INFO, " > Renderer: %s", glGetString(GL_RENDERER)); + TRACELOG(LOG_INFO, " > Version: %s", glGetString(GL_VERSION)); TRACELOG(LOG_INFO, " > GLSL: %s", "NOT SUPPORTED"); } @@ -1870,7 +1870,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara // WARNING: Don't trust the docs, they say this message can not be obtained if not calling DefWindowProc() // in response to WM_WINDOWPOSCHANGED but looks like when a window is created, // this message can be obtained without getting WM_WINDOWPOSCHANGED - HandleWindowResize(hwnd, &platform.appScreenWidth, &platform.appScreenHeight); + // WARNING: This call fails for Software-Renderer backend + //HandleWindowResize(hwnd, &platform.appScreenWidth, &platform.appScreenHeight); } break; //case WM_MOVE case WM_WINDOWPOSCHANGED: From 528caf8b9dc83c2937d7f3aaf450cfa9371853c6 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 18 Mar 2026 16:21:14 +0100 Subject: [PATCH 32/41] Added some libraries --- projects/VS2022/raylib/raylib.vcxproj | 3 +++ projects/VS2022/raylib/raylib.vcxproj.filters | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/projects/VS2022/raylib/raylib.vcxproj b/projects/VS2022/raylib/raylib.vcxproj index 8cc3fae7a..cf686e498 100644 --- a/projects/VS2022/raylib/raylib.vcxproj +++ b/projects/VS2022/raylib/raylib.vcxproj @@ -585,6 +585,9 @@ + + + diff --git a/projects/VS2022/raylib/raylib.vcxproj.filters b/projects/VS2022/raylib/raylib.vcxproj.filters index 17ac7f9b8..444686eab 100644 --- a/projects/VS2022/raylib/raylib.vcxproj.filters +++ b/projects/VS2022/raylib/raylib.vcxproj.filters @@ -102,6 +102,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + From 2fd058c1e49d17e6976f789769e8ead27ac1396e Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 18 Mar 2026 16:21:18 +0100 Subject: [PATCH 33/41] Update ROADMAP.md --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 441a811d2..10754e52b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -20,7 +20,7 @@ _Current version of raylib is complete and functional but there is always room f - [ ] `rcore_desktop_x11`: Create additional platform backend: Linux/X11 - [ ] `rcore_desktop_wayland`: Create additional platform backend: Linux/Wayland - [ ] `rcore`: Investigate alternative embedded platforms and realtime OSs - - [ ] `rlsw`: Software renderer optimizations, platform-specific, improve SIMD support + - [ ] `rlsw`: Software renderer optimizations: mipmaps, platform-specific SIMD - [ ] `rtextures`: Consider moving N-patch system to separate example - [ ] `rtextures`: Review blending modes system, provide more options or better samples - [ ] `raudio`: Support microphone input, basic API to read microphone From 2a3b28b67a484e188344fc8136bee30ec24e983e Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 18 Mar 2026 16:21:35 +0100 Subject: [PATCH 34/41] Reviewed some comments --- src/external/rlsw.h | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index 3c908a82f..1237c5147 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -937,8 +937,8 @@ typedef struct { int allocSz; // Allocated size SWfilter minFilter; // Minification filter SWfilter magFilter; // Magnification filter - SWwrap sWrap; // texcoord.x wrap mode - SWwrap tWrap; // texcoord.y wrap mode + SWwrap sWrap; // Wrap mode for texcoord.x + SWwrap tWrap; // Wrap mode for texcoord.y float tx; // Texel width float ty; // Texel height } sw_texture_t; @@ -1285,7 +1285,7 @@ static inline uint16_t sw_float_to_half_ui(uint32_t ui) // Overflow: infinity; 143 encodes exponent 16 h = (em >= (143 << 23))? 0x7c00 : h; - // NaN; note that we convert all types of NaN to qNaN + // NaN; note that all types of NaN are converted to qNaN h = (em > (255 << 23))? 0x7e00 : h; return (uint16_t)(s | h); @@ -1302,8 +1302,8 @@ static inline uint32_t sw_half_to_float_ui(uint16_t h) // Denormal: flush to zero r = (em < (1 << 10))? 0 : r; - // Infinity/NaN; note that we preserve NaN payload as a byproduct of unifying inf/nan cases - // 112 is an exponent bias fixup; since we already applied it once, applying it twice converts 31 to 255 + // Infinity/NaN; note that NaN payload is preeserved as a byproduct of unifying inf/nan cases + // 112 is an exponent bias fixup; since it was already applied once, applying it twice converts 31 to 255 r += (em >= (31 << 10))? (112 << 23) : 0; return s | r; @@ -2487,8 +2487,9 @@ static inline void sw_texture_sample_linear(float *SW_RESTRICT color, const sw_t static inline void sw_texture_sample(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, float u, float v, float dUdx, float dUdy, float dVdx, float dVdy) { - // Previous method: There is no need to compute the square root - // because using the squared value, the comparison remains (L2 > 1.0f*1.0f) + // NOTE: Commented there is the previous method used + // There was no need to compute the square root because + // using the squared value, the comparison remains (L2 > 1.0f*1.0f) //float du = sqrtf(dUdx*dUdx + dUdy*dUdy); //float dv = sqrtf(dVdx*dVdx + dVdy*dVdy); //float L = (du > dv)? du : dv; @@ -2534,10 +2535,9 @@ static inline void sw_default_framebuffer_free(sw_default_framebuffer_t *fb) static inline void sw_framebuffer_fill_color(sw_texture_t *colorBuffer, const float color[4]) { - // NOTE: MSVC doesn't support VLA, so we allocate the largest possible size - //uint8_t pixel[SW_FRAMEBUFFER_COLOR_SIZE]; - - uint8_t pixel[16]; + // NOTE: MSVC doesn't support VLA, so the largest possible size is allocated: 16 bytes + //uint8_t pixel[SW_FRAMEBUFFER_COLOR_SIZE] = { 0 }; + uint8_t pixel[16] = { 0 }; SW_FRAMEBUFFER_COLOR_SET(pixel, color, 0); uint8_t *dst = (uint8_t *)colorBuffer->pixels; @@ -2574,10 +2574,9 @@ static inline void sw_framebuffer_fill_color(sw_texture_t *colorBuffer, const fl static inline void sw_framebuffer_fill_depth(sw_texture_t *depthBuffer, float depth) { - // NOTE: MSVC doesn't support VLA, so we allocate the largest possible size - //uint8_t pixel[SW_FRAMEBUFFER_DEPTH_SIZE]; - - uint8_t pixel[4]; + // NOTE: MSVC doesn't support VLA, so the largest possible size is allocated: 4 bytes + //uint8_t pixel[SW_FRAMEBUFFER_DEPTH_SIZE] = { 0 }; + uint8_t pixel[4] = { 0 }; SW_FRAMEBUFFER_DEPTH_SET(pixel, depth, 0); uint8_t *dst = (uint8_t *)depthBuffer->pixels; @@ -3740,7 +3739,7 @@ static inline void sw_poly_fill_render(uint32_t state) //------------------------------------------------------------------------------------------- static void sw_immediate_push_vertex(const float position[4], const float color[4], const float texcoord[2]) { - // Check if we are in a valid draw mode + // Check if the draw mode is valid if (!sw_is_draw_mode_valid(RLSW.drawMode)) { RLSW.errCode = SW_INVALID_OPERATION; @@ -4480,7 +4479,7 @@ void swOrtho(double left, double right, double bottom, double top, double znear, void swBegin(SWdraw mode) { - // Check if we can render + // Check if render is possible if (!sw_is_ready_to_render()) { RLSW.errCode = SW_INVALID_OPERATION; From da9e881092469e15bec7e6eae109c615132fd8c5 Mon Sep 17 00:00:00 2001 From: Amine Laaboudi <71769287+0x00650a@users.noreply.github.com> Date: Wed, 18 Mar 2026 16:09:27 -0400 Subject: [PATCH 35/41] Fix uninstall process to remove rcamera header file (#5671) Co-authored-by: 0x00650a --- src/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile b/src/Makefile index 026888614..8f13b4355 100644 --- a/src/Makefile +++ b/src/Makefile @@ -959,6 +959,7 @@ ifeq ($(ROOT),root) endif rm --force --interactive --verbose $(RAYLIB_H_INSTALL_PATH)/raylib.h rm --force --interactive --verbose $(RAYLIB_H_INSTALL_PATH)/raymath.h + rm --force --interactive --verbose $(RAYLIB_H_INSTALL_PATH)/rcamera.h rm --force --interactive --verbose $(RAYLIB_H_INSTALL_PATH)/rlgl.h @echo "raylib development files removed!" else From 7fef65a3fec491551aa3d76a297a99a5b376a973 Mon Sep 17 00:00:00 2001 From: devel Date: Thu, 19 Mar 2026 18:17:27 -0400 Subject: [PATCH 36/41] Make fogColor in the fog tutorial a parameter (#5672) * uniform fogColor fogColor is now a parameter * use new fog color parameter * convert ambient to Vector4 --- examples/shaders/resources/shaders/glsl330/fog.fs | 5 +---- examples/shaders/shaders_fog_rendering.c | 7 ++++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/shaders/resources/shaders/glsl330/fog.fs b/examples/shaders/resources/shaders/glsl330/fog.fs index 67d0795ec..ac0132ff0 100644 --- a/examples/shaders/resources/shaders/glsl330/fog.fs +++ b/examples/shaders/resources/shaders/glsl330/fog.fs @@ -37,6 +37,7 @@ struct Light { uniform Light lights[MAX_LIGHTS]; uniform vec4 ambient; uniform vec3 viewPos; +uniform vec4 fogColor; uniform float fogDensity; void main() @@ -77,10 +78,6 @@ void main() // Fog calculation float dist = length(viewPos - fragPosition); - // these could be parameters... - const vec4 fogColor = vec4(0.5, 0.5, 0.5, 1.0); - //const float fogDensity = 0.16; - // Exponential fog float fogFactor = 1.0/exp((dist*fogDensity)*(dist*fogDensity)); diff --git a/examples/shaders/shaders_fog_rendering.c b/examples/shaders/shaders_fog_rendering.c index bc0e54ceb..a1044312d 100644 --- a/examples/shaders/shaders_fog_rendering.c +++ b/examples/shaders/shaders_fog_rendering.c @@ -72,8 +72,13 @@ int main(void) shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos"); // Ambient light level + Vector4 ambient = (Vector4){ 0.2f, 0.2f, 0.2f, 1.0f }; int ambientLoc = GetShaderLocation(shader, "ambient"); - SetShaderValue(shader, ambientLoc, (float[4]){ 0.2f, 0.2f, 0.2f, 1.0f }, SHADER_UNIFORM_VEC4); + SetShaderValue(shader, ambientLoc, &ambient, SHADER_UNIFORM_VEC4); + + Vector4 fogColor = ColorNormalize(GRAY); + int fogColorLoc = GetShaderLocation(shader, "fogColor"); + SetShaderValue(shader, fogColorLoc, &fogColor, SHADER_UNIFORM_VEC4); float fogDensity = 0.15f; int fogDensityLoc = GetShaderLocation(shader, "fogDensity"); From bca4f83a024ea8a6062c2d3f5773cbfe978fe289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20Mich=C3=A1lek?= Date: Thu, 19 Mar 2026 23:19:44 +0100 Subject: [PATCH 37/41] required change for ESP-IDF 6 (#5674) --- src/external/rlsw.h | 10 ++++++++++ src/rcore.c | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index 1237c5147..2be21def5 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -689,6 +689,7 @@ SWAPI void swClear(uint32_t bitmask); SWAPI void swBlendFunc(SWfactor sfactor, SWfactor dfactor); SWAPI void swPolygonMode(SWpoly mode); SWAPI void swCullFace(SWface face); +SWAPI void *swGetColorBuffer(int *width, int *height); // Restored for ESP-IDF compatibility SWAPI void swPointSize(float size); SWAPI void swLineWidth(float width); @@ -4200,6 +4201,15 @@ void swCullFace(SWface face) RLSW.cullFace = face; } +// Get direct pointer to the default framebuffer's pixel data +// Restored for ESP-IDF compatibility - removed in Raylib 6.0 PR #5655 +void *swGetColorBuffer(int *width, int *height) +{ + if (width) *width = RLSW.colorBuffer->width; + if (height) *height = RLSW.colorBuffer->height; + return RLSW.colorBuffer->pixels; +} + void swPointSize(float size) { RLSW.pointRadius = floorf(size*0.5f); diff --git a/src/rcore.c b/src/rcore.c index de1bb371c..0bb32ba27 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -682,6 +682,18 @@ void InitWindow(int width, int height, const char *title) TRACELOG(LOG_WARNING, "SYSTEM: Failed to initialize platform"); return; } + + // FIX: Initialize render dimensions for embedded platforms + // On desktop platforms (GLFW, SDL, etc.), CORE.Window.render.width/height are + // set during window creation. On embedded platforms with no window manager, + // InitPlatform() doesn't set these values, so we initialize them here from + // the screen dimensions (which are set from the InitWindow parameters). + // This fix is required for embedded platforms. + if (CORE.Window.render.width == 0 || CORE.Window.render.height == 0) + { + CORE.Window.render.width = CORE.Window.screen.width; + CORE.Window.render.height = CORE.Window.screen.height; + } //-------------------------------------------------------------- // Initialize rlgl default data (buffers and shaders) From 04c5dc449331bcb9ee27ff1fadae2ea4343f34ca Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 19 Mar 2026 23:35:18 +0100 Subject: [PATCH 38/41] REVIEWED: PR #5674 --- src/external/rlsw.h | 19 +++++++++---------- src/rcore.c | 12 +++++------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index 2be21def5..9d56ce55d 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -671,6 +671,7 @@ SWAPI void swClose(void); SWAPI bool swResize(int w, int h); SWAPI void swReadPixels(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels); SWAPI void swBlitPixels(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels); +SWAPI void *swGetColorBuffer(int *width, int *height); // Restored for ESP-IDF compatibility SWAPI void swEnable(SWstate state); SWAPI void swDisable(SWstate state); @@ -689,7 +690,6 @@ SWAPI void swClear(uint32_t bitmask); SWAPI void swBlendFunc(SWfactor sfactor, SWfactor dfactor); SWAPI void swPolygonMode(SWpoly mode); SWAPI void swCullFace(SWface face); -SWAPI void *swGetColorBuffer(int *width, int *height); // Restored for ESP-IDF compatibility SWAPI void swPointSize(float size); SWAPI void swLineWidth(float width); @@ -3952,6 +3952,14 @@ void swBlitPixels(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, in } } +// Get framefuffer pixel data pointer and size +void *swGetColorBuffer(int *width, int *height) +{ + if (width != NULL) *width = RLSW.framebuffer.color->width; + if (height != NULL) *height = RLSW.framebuffer.color->height; + return RLSW.framebuffer.color->pixels; +} + void swEnable(SWstate state) { switch (state) @@ -4201,15 +4209,6 @@ void swCullFace(SWface face) RLSW.cullFace = face; } -// Get direct pointer to the default framebuffer's pixel data -// Restored for ESP-IDF compatibility - removed in Raylib 6.0 PR #5655 -void *swGetColorBuffer(int *width, int *height) -{ - if (width) *width = RLSW.colorBuffer->width; - if (height) *height = RLSW.colorBuffer->height; - return RLSW.colorBuffer->pixels; -} - void swPointSize(float size) { RLSW.pointRadius = floorf(size*0.5f); diff --git a/src/rcore.c b/src/rcore.c index 0bb32ba27..5cdc8aca1 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -683,13 +683,11 @@ void InitWindow(int width, int height, const char *title) return; } - // FIX: Initialize render dimensions for embedded platforms - // On desktop platforms (GLFW, SDL, etc.), CORE.Window.render.width/height are - // set during window creation. On embedded platforms with no window manager, - // InitPlatform() doesn't set these values, so we initialize them here from - // the screen dimensions (which are set from the InitWindow parameters). - // This fix is required for embedded platforms. - if (CORE.Window.render.width == 0 || CORE.Window.render.height == 0) + // Initialize render dimensions for embedded platforms + // NOTE: On desktop platforms (GLFW, SDL, etc.), CORE.Window.render.width/height are set during window creation + // On embedded platforms with no window manager, InitPlatform() doesn't set these values, so they should be initialized + // here from screen dimensions (which are set from the InitWindow parameters) + if ((CORE.Window.render.width == 0) || (CORE.Window.render.height == 0)) { CORE.Window.render.width = CORE.Window.screen.width; CORE.Window.render.height = CORE.Window.screen.height; From 7ae46fb2e6b245537e3cbd663d996aedea99fa07 Mon Sep 17 00:00:00 2001 From: Le Juez Victor <90587919+Bigfoot71@users.noreply.github.com> Date: Thu, 19 Mar 2026 23:39:52 +0100 Subject: [PATCH 39/41] [rlsw] Micro-optimizations, tighter pipeline and cleanup (#5673) * auto generates all combinations of blending factors This adds a macro system that generate a function for each possible combination of blending factors, resulting in 11*11 functions, hence 121. This then allows for only one indirection and function call instead of two previously (assuming the first call was inlined). * rename dispatch tables for consistency * change blend funcs validity check Simplifies the validation of blend functions. Can allow `SW_SRC_ALPHA_SATURATE` as dst factor, but hey * disables blending when it requires alpha and there is none * review immediate rendering functions and attribute layout * prevent state changes during immediate record * reduce number of op for each vertex push + review primitive struct * simplified draw functions * review `sw_vertex_t` removes `float screen[2]`; each step stores the transformed coordinates in `float coord[4]`. This also simplifies vertex interpolation during triangle rasterization. * reduces unnecessary interpolation costs during triangle rasterization + cleanup * extends the simd color conversion to more cases * affine interpolation per blocks * long side check for each triangle line My mistake in a previous commit * style tweaks * select the read function on texture load This removes the per-pixel switch; it's slightly more efficient on my hardware, but probably a poor prediction Should remain profitable or at worst the same * use optionnal LUT for uint8_t -> float conversion * sets internal the number of vertices post-clipping and the epsilon clipping + a little cleanup * moves color conversion to math part * prevents sampling if it's a depth texture that is bound --- src/external/rlsw.h | 2349 +++++++++++++++++++++++-------------------- 1 file changed, 1241 insertions(+), 1108 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index 9d56ce55d..b243f576f 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -153,17 +153,15 @@ #define SW_MAX_TEXTURES 128 #endif -// Under normal circumstances, clipping a polygon can add at most one vertex per clipping plane -// Considering the largest polygon involved is a quadrilateral (4 vertices), -// and that clipping occurs against both the frustum (6 planes) and the scissors (4 planes), -// the maximum number of vertices after clipping is: -// 4 (original vertices) + 6 (frustum planes) + 4 (scissors planes) = 14 -#ifndef SW_MAX_CLIPPED_POLYGON_VERTICES - #define SW_MAX_CLIPPED_POLYGON_VERTICES 14 -#endif - -#ifndef SW_CLIP_EPSILON - #define SW_CLIP_EPSILON 1e-4f +// Enables the use of a lookup table for uint8_t to float conversion +// Requires an additional 1KB of global memory +// Disabled when SIMD intrinsics are enabled +#ifndef SW_USE_COLOR_LUT + #if RLSW_USE_SIMD_INTRINSICS + #define SW_USE_COLOR_LUT false + #else + #define SW_USE_COLOR_LUT true + #endif #endif //---------------------------------------------------------------------------------- @@ -860,6 +858,13 @@ SWAPI void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWatta #define SW_DEG2RAD (SW_PI/180.0f) #define SW_RAD2DEG (180.0f/SW_PI) +// When clipping a convex polygon against a plane, at most one vertex is added. +// Starting from a quadrilateral (4 vertices), clipped sequentially against +// the frustum (6 planes) then the scissor rectangle (4 planes): +// 4 + 6 + 4 = 14 vertices maximum. +#define SW_MAX_CLIPPED_POLYGON_VERTICES 14 +#define SW_CLIP_EPSILON 1e-4f + #define SW_HANDLE_NULL 0u #define SW_POOL_SLOT_LIVE 0x80u // bit7 of the generation byte #define SW_POOL_SLOT_VER_MASK 0x7Fu // bits6:0 = anti-ABA counter @@ -867,12 +872,12 @@ SWAPI void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWatta #define SW_CONCAT(a, b) a##b #define SW_CONCATX(a, b) SW_CONCAT(a, b) -#define SW_FRAMEBUFFER_COLOR8_GET(c,p,o) SW_CONCATX(sw_pixel_get_color8_, SW_FRAMEBUFFER_COLOR_TYPE)((c),(p),(o)) -#define SW_FRAMEBUFFER_COLOR_GET(c,p,o) SW_CONCATX(sw_pixel_get_color_, SW_FRAMEBUFFER_COLOR_TYPE)((c),(p),(o)) -#define SW_FRAMEBUFFER_COLOR_SET(p,c,o) SW_CONCATX(sw_pixel_set_color_, SW_FRAMEBUFFER_COLOR_TYPE)((p),(c),(o)) +#define SW_FRAMEBUFFER_COLOR8_GET(c,p,o) SW_CONCATX(sw_pixel_read_color8_, SW_FRAMEBUFFER_COLOR_TYPE)((c),(p),(o)) +#define SW_FRAMEBUFFER_COLOR_GET(c,p,o) SW_CONCATX(sw_pixel_read_color_, SW_FRAMEBUFFER_COLOR_TYPE)((c),(p),(o)) +#define SW_FRAMEBUFFER_COLOR_SET(p,c,o) SW_CONCATX(sw_pixel_write_color_, SW_FRAMEBUFFER_COLOR_TYPE)((p),(c),(o)) -#define SW_FRAMEBUFFER_DEPTH_GET(p,o) SW_CONCATX(sw_pixel_get_depth_, SW_FRAMEBUFFER_DEPTH_TYPE)((p),(o)) -#define SW_FRAMEBUFFER_DEPTH_SET(p,d,o) SW_CONCATX(sw_pixel_set_depth_, SW_FRAMEBUFFER_DEPTH_TYPE)((p),(d),(o)) +#define SW_FRAMEBUFFER_DEPTH_GET(p,o) SW_CONCATX(sw_pixel_read_depth_, SW_FRAMEBUFFER_DEPTH_TYPE)((p),(o)) +#define SW_FRAMEBUFFER_DEPTH_SET(p,d,o) SW_CONCATX(sw_pixel_write_depth_, SW_FRAMEBUFFER_DEPTH_TYPE)((p),(d),(o)) #define SW_FRAMEBUFFER_COLOR_FORMAT SW_CONCATX(SW_PIXELFORMAT_COLOR_, SW_FRAMEBUFFER_COLOR_TYPE) #define SW_FRAMEBUFFER_DEPTH_FORMAT SW_CONCATX(SW_PIXELFORMAT_DEPTH_, SW_FRAMEBUFFER_DEPTH_TYPE) @@ -880,15 +885,15 @@ SWAPI void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWatta #define SW_FRAMEBUFFER_COLOR_SIZE SW_PIXELFORMAT_SIZE[SW_FRAMEBUFFER_COLOR_FORMAT] #define SW_FRAMEBUFFER_DEPTH_SIZE SW_PIXELFORMAT_SIZE[SW_FRAMEBUFFER_DEPTH_FORMAT] -#define SW_STATE_CHECK(flags) (SW_STATE_CHECK_EX(RLSW.stateFlags, (flags))) -#define SW_STATE_CHECK_EX(state, flags) (((state) & (flags)) == (flags)) - #define SW_STATE_SCISSOR_TEST (1 << 0) #define SW_STATE_TEXTURE_2D (1 << 1) #define SW_STATE_DEPTH_TEST (1 << 2) #define SW_STATE_CULL_FACE (1 << 3) #define SW_STATE_BLEND (1 << 4) +#define SW_BLEND_FLAG_NOOP (1 << 0) +#define SW_BLEND_FLAG_NEEDS_ALPHA (1 << 1) + //---------------------------------------------------------------------------------- // Module Types and Structures Definition //---------------------------------------------------------------------------------- @@ -919,29 +924,56 @@ typedef enum { SW_PIXELFORMAT_COUNT } sw_pixelformat_t; +typedef enum { + SW_PIXEL_ALPHA_NONE = 0, // No transparency + SW_PIXEL_ALPHA_BIN, // Binary transparency + SW_PIXEL_ALPHA_YES, // Contains transparency +} sw_pixel_alpha_t; + +// Forward declarations +typedef struct sw_vertex sw_vertex_t; + +// Pixel getter functions +typedef void (*sw_pixel_read_color8_f)(uint8_t *SW_RESTRICT, const void *SW_RESTRICT, uint32_t); +typedef void (*sw_pixel_read_color_f)(float *SW_RESTRICT, const void *SW_RESTRICT, uint32_t); + +// Pixel setter functions +typedef void (*sw_pixel_write_color8_f)(void *SW_RESTRICT, const uint8_t *SW_RESTRICT, uint32_t); +typedef void (*sw_pixel_write_color_f)(void *SW_RESTRICT, const float *SW_RESTRICT, uint32_t); + +// Color blending function +typedef void (*sw_blend_f)(float *SW_RESTRICT, const float *SW_RESTRICT); + +// Rasterizer functions +typedef void (*sw_raster_triangle_f)(const sw_vertex_t*, const sw_vertex_t*, const sw_vertex_t*); +typedef void (*sw_raster_quad_f)(const sw_vertex_t*, const sw_vertex_t*, const sw_vertex_t*, const sw_vertex_t*); +typedef void (*sw_raster_line_f)(const sw_vertex_t*, const sw_vertex_t*); +typedef void (*sw_raster_point_f)(const sw_vertex_t*); + typedef float sw_matrix_t[4*4]; -typedef struct { +typedef struct sw_vertex { float position[4]; // Position coordinates - float texcoord[2]; // Texture coordinates float color[4]; // Color value (RGBA) - - float homogeneous[4]; // Homogeneous coordinates - float screen[2]; // Screen coordinates + float texcoord[2]; // Texture coordinates + float coord[4]; // Clip space (x,y,z,w) -> NDC (after /w) -> screen space (x,y,z,1/w) } sw_vertex_t; typedef struct { - void *pixels; // Texture pixels - sw_pixelformat_t format; // Texture format - int width, height; // Dimensions of the texture - int wMinus1, hMinus1; // Dimensions minus one - int allocSz; // Allocated size - SWfilter minFilter; // Minification filter - SWfilter magFilter; // Magnification filter - SWwrap sWrap; // Wrap mode for texcoord.x - SWwrap tWrap; // Wrap mode for texcoord.y - float tx; // Texel width - float ty; // Texel height + void *pixels; // Texture pixels + sw_pixel_read_color8_f readColor8; // Texel read RGBA8 + sw_pixel_read_color_f readColor; // Texel read RGBA32F + sw_pixelformat_t format; // Texture format + sw_pixel_alpha_t alpha; // Texture alpha mode + int width, height; // Dimensions of the texture + int wMinus1, hMinus1; // Dimensions minus one + int allocSz; // Allocated size + SWfilter minFilter; // Minification filter + SWfilter magFilter; // Magnification filter + SWwrap sWrap; // Wrap mode for texcoord.x + SWwrap tWrap; // Wrap mode for texcoord.y + float tx; // Texel width + float ty; // Texel height } sw_texture_t; typedef struct { @@ -964,12 +996,6 @@ typedef struct { size_t stride; } sw_pool_t; -typedef void (*sw_blend_factor_t)(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst); -typedef void (*sw_raster_triangle_f)(const sw_vertex_t *v0, const sw_vertex_t *v1, const sw_vertex_t *v2); -typedef void (*sw_raster_quad_f)(const sw_vertex_t *v0, const sw_vertex_t *v1, const sw_vertex_t *v2, const sw_vertex_t *v3); -typedef void (*sw_raster_line_f)(const sw_vertex_t *v0, const sw_vertex_t *v1); -typedef void (*sw_raster_point_f)(const sw_vertex_t *v); - // Graphic context data structure typedef struct { sw_default_framebuffer_t framebuffer; // Default framebuffer @@ -985,20 +1011,20 @@ typedef struct { float scClipMin[2]; // Scissor rectangle minimum renderable point in clip space float scClipMax[2]; // Scissor rectangle maximum renderable point in clip space + struct { + sw_vertex_t buffer[SW_MAX_CLIPPED_POLYGON_VERTICES]; // Buffer used for storing primitive vertices, used for processing and rendering + int vertexCount; // Number of vertices in the primtive buffer + float color[4]; // Current color for the next pushed vertex + float texcoord[2]; // Current texture coordinates for the next push vertex + bool hasColorAlpha; // Flag indicating whether the current primitive contains transparency + } primitive; + struct { float *positions; float *texcoords; uint8_t *colors; } array; - struct { - float texcoord[2]; - float color[4]; - } current; - - sw_vertex_t vertexBuffer[SW_MAX_CLIPPED_POLYGON_VERTICES]; // Buffer used for storing primitive vertices, used for processing and rendering - int vertexCounter; // Number of vertices in 'ctx.vertexBuffer' - SWdraw drawMode; // Current primitive mode (e.g., lines, triangles) SWpoly polyMode; // Current polygon filling mode (e.g., lines, triangles) float pointRadius; // Rasterized point radius @@ -1023,16 +1049,16 @@ typedef struct { sw_texture_t *boundTexture; // Texture currently bound sw_pool_t texturePool; // Texture object pool - SWfactor srcFactor; // Source blending factor - SWfactor dstFactor; // Destination bleending factor - - sw_blend_factor_t srcFactorFunc; // Source blend function - sw_blend_factor_t dstFactorFunc; // Destination blend function + SWfactor srcFactor; // Source blending factor + SWfactor dstFactor; // Destination bleending factor + uint32_t blendFlags; // Flags about the current blend mode + sw_blend_f blendFunc; // Source blend function SWface cullFace; // Faces to cull SWerrcode errCode; // Last error code - uint32_t stateFlags; + uint32_t userState; // User-defined pipeline state + uint32_t rasterState; // Cleaned pipeline state for the rasterizer } sw_context_t; //---------------------------------------------------------------------------------- @@ -1040,9 +1066,35 @@ typedef struct { //---------------------------------------------------------------------------------- static sw_context_t RLSW = { 0 }; +#if SW_USE_COLOR_LUT +static float SW_LUT_UINT8_TO_FLOAT[256] = { 0 }; +#endif + //---------------------------------------------------------------------------------- // Internal Constants Definition //---------------------------------------------------------------------------------- +// Pixel formats that has an alpha channel +static const sw_pixel_alpha_t SW_PIXELFORMAT_ALPHA[SW_PIXELFORMAT_COUNT] = +{ + [SW_PIXELFORMAT_COLOR_GRAYSCALE] = SW_PIXEL_ALPHA_NONE, + [SW_PIXELFORMAT_COLOR_GRAYALPHA] = SW_PIXEL_ALPHA_YES, + [SW_PIXELFORMAT_COLOR_R3G3B2] = SW_PIXEL_ALPHA_NONE, + [SW_PIXELFORMAT_COLOR_R5G6B5] = SW_PIXEL_ALPHA_NONE, + [SW_PIXELFORMAT_COLOR_R8G8B8] = SW_PIXEL_ALPHA_NONE, + [SW_PIXELFORMAT_COLOR_R5G5B5A1] = SW_PIXEL_ALPHA_BIN, + [SW_PIXELFORMAT_COLOR_R4G4B4A4] = SW_PIXEL_ALPHA_YES, + [SW_PIXELFORMAT_COLOR_R8G8B8A8] = SW_PIXEL_ALPHA_YES, + [SW_PIXELFORMAT_COLOR_R32] = SW_PIXEL_ALPHA_NONE, + [SW_PIXELFORMAT_COLOR_R32G32B32] = SW_PIXEL_ALPHA_NONE, + [SW_PIXELFORMAT_COLOR_R32G32B32A32] = SW_PIXEL_ALPHA_YES, + [SW_PIXELFORMAT_COLOR_R16] = SW_PIXEL_ALPHA_NONE, + [SW_PIXELFORMAT_COLOR_R16G16B16] = SW_PIXEL_ALPHA_NONE, + [SW_PIXELFORMAT_COLOR_R16G16B16A16] = SW_PIXEL_ALPHA_YES, + [SW_PIXELFORMAT_DEPTH_D8] = SW_PIXEL_ALPHA_NONE, + [SW_PIXELFORMAT_DEPTH_D16] = SW_PIXEL_ALPHA_NONE, + [SW_PIXELFORMAT_DEPTH_D32] = SW_PIXEL_ALPHA_NONE, +}; + // Pixel formats sizes in bytes static const int SW_PIXELFORMAT_SIZE[SW_PIXELFORMAT_COUNT] = { @@ -1169,7 +1221,7 @@ static inline float sw_luminance(const float *color) return color[0]*0.299f + color[1]*0.587f + color[2]*0.114f; } -static inline void sw_lerp_vertex_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float t) +static inline void sw_lerp_vertex_PCTH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float t) { const float tInv = 1.0f - t; @@ -1179,96 +1231,123 @@ static inline void sw_lerp_vertex_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_ve out->position[2] = a->position[2]*tInv + b->position[2]*t; out->position[3] = a->position[3]*tInv + b->position[3]*t; - // Texture coordinate interpolation (2 components) - out->texcoord[0] = a->texcoord[0]*tInv + b->texcoord[0]*t; - out->texcoord[1] = a->texcoord[1]*tInv + b->texcoord[1]*t; - // Color interpolation (4 components) out->color[0] = a->color[0]*tInv + b->color[0]*t; out->color[1] = a->color[1]*tInv + b->color[1]*t; out->color[2] = a->color[2]*tInv + b->color[2]*t; out->color[3] = a->color[3]*tInv + b->color[3]*t; - // Homogeneous coordinate interpolation (4 components) - out->homogeneous[0] = a->homogeneous[0]*tInv + b->homogeneous[0]*t; - out->homogeneous[1] = a->homogeneous[1]*tInv + b->homogeneous[1]*t; - out->homogeneous[2] = a->homogeneous[2]*tInv + b->homogeneous[2]*t; - out->homogeneous[3] = a->homogeneous[3]*tInv + b->homogeneous[3]*t; + // Texture coordinate interpolation (2 components) + out->texcoord[0] = a->texcoord[0]*tInv + b->texcoord[0]*t; + out->texcoord[1] = a->texcoord[1]*tInv + b->texcoord[1]*t; + + // Pipeline coordinate interpolation (4 components) + out->coord[0] = a->coord[0]*tInv + b->coord[0]*t; + out->coord[1] = a->coord[1]*tInv + b->coord[1]*t; + out->coord[2] = a->coord[2]*tInv + b->coord[2]*t; + out->coord[3] = a->coord[3]*tInv + b->coord[3]*t; } -static inline void sw_get_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale) +static inline void sw_get_vertex_grad_CTH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale) { - // Calculate gradients for Position - out->position[0] = (b->position[0] - a->position[0])*scale; - out->position[1] = (b->position[1] - a->position[1])*scale; - out->position[2] = (b->position[2] - a->position[2])*scale; - out->position[3] = (b->position[3] - a->position[3])*scale; - - // Calculate gradients for Texture coordinates - out->texcoord[0] = (b->texcoord[0] - a->texcoord[0])*scale; - out->texcoord[1] = (b->texcoord[1] - a->texcoord[1])*scale; - // Calculate gradients for Color out->color[0] = (b->color[0] - a->color[0])*scale; out->color[1] = (b->color[1] - a->color[1])*scale; out->color[2] = (b->color[2] - a->color[2])*scale; out->color[3] = (b->color[3] - a->color[3])*scale; - // Calculate gradients for Homogeneous coordinates - out->homogeneous[0] = (b->homogeneous[0] - a->homogeneous[0])*scale; - out->homogeneous[1] = (b->homogeneous[1] - a->homogeneous[1])*scale; - out->homogeneous[2] = (b->homogeneous[2] - a->homogeneous[2])*scale; - out->homogeneous[3] = (b->homogeneous[3] - a->homogeneous[3])*scale; + // Calculate gradients for Texture coordinates + out->texcoord[0] = (b->texcoord[0] - a->texcoord[0])*scale; + out->texcoord[1] = (b->texcoord[1] - a->texcoord[1])*scale; + + // Calculate gradients for Pipeline coordinates + out->coord[0] = (b->coord[0] - a->coord[0])*scale; + out->coord[1] = (b->coord[1] - a->coord[1])*scale; + out->coord[2] = (b->coord[2] - a->coord[2])*scale; + out->coord[3] = (b->coord[3] - a->coord[3])*scale; } -static inline void sw_add_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients) +static inline void sw_add_vertex_grad_CTH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients) { - // Add gradients to Position - out->position[0] += gradients->position[0]; - out->position[1] += gradients->position[1]; - out->position[2] += gradients->position[2]; - out->position[3] += gradients->position[3]; - - // Add gradients to Texture coordinates - out->texcoord[0] += gradients->texcoord[0]; - out->texcoord[1] += gradients->texcoord[1]; - // Add gradients to Color out->color[0] += gradients->color[0]; out->color[1] += gradients->color[1]; out->color[2] += gradients->color[2]; out->color[3] += gradients->color[3]; - // Add gradients to Homogeneous coordinates - out->homogeneous[0] += gradients->homogeneous[0]; - out->homogeneous[1] += gradients->homogeneous[1]; - out->homogeneous[2] += gradients->homogeneous[2]; - out->homogeneous[3] += gradients->homogeneous[3]; + // Add gradients to Texture coordinates + out->texcoord[0] += gradients->texcoord[0]; + out->texcoord[1] += gradients->texcoord[1]; + + // Add gradients to Pipeline coordinates + out->coord[0] += gradients->coord[0]; + out->coord[1] += gradients->coord[1]; + out->coord[2] += gradients->coord[2]; + out->coord[3] += gradients->coord[3]; } -static inline void sw_add_vertex_grad_scaled_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients, float scale) +static inline void sw_add_vertex_grad_scaled_CTH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients, float scale) { - // Add gradients to Position - out->position[0] += gradients->position[0]*scale; - out->position[1] += gradients->position[1]*scale; - out->position[2] += gradients->position[2]*scale; - out->position[3] += gradients->position[3]*scale; - - // Add gradients to Texture coordinates - out->texcoord[0] += gradients->texcoord[0]*scale; - out->texcoord[1] += gradients->texcoord[1]*scale; - // Add gradients to Color out->color[0] += gradients->color[0]*scale; out->color[1] += gradients->color[1]*scale; out->color[2] += gradients->color[2]*scale; out->color[3] += gradients->color[3]*scale; - // Add gradients to Homogeneous coordinates - out->homogeneous[0] += gradients->homogeneous[0]*scale; - out->homogeneous[1] += gradients->homogeneous[1]*scale; - out->homogeneous[2] += gradients->homogeneous[2]*scale; - out->homogeneous[3] += gradients->homogeneous[3]*scale; + // Add gradients to Texture coordinates + out->texcoord[0] += gradients->texcoord[0]*scale; + out->texcoord[1] += gradients->texcoord[1]*scale; + + // Add gradients to Pipeline coordinates + out->coord[0] += gradients->coord[0]*scale; + out->coord[1] += gradients->coord[1]*scale; + out->coord[2] += gradients->coord[2]*scale; + out->coord[3] += gradients->coord[3]*scale; +} + +static inline void sw_get_vertex_grad_CH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale) +{ + // Calculate gradients for Color + out->color[0] = (b->color[0] - a->color[0])*scale; + out->color[1] = (b->color[1] - a->color[1])*scale; + out->color[2] = (b->color[2] - a->color[2])*scale; + out->color[3] = (b->color[3] - a->color[3])*scale; + + // Calculate gradients for Pipeline coordinates + out->coord[0] = (b->coord[0] - a->coord[0])*scale; + out->coord[1] = (b->coord[1] - a->coord[1])*scale; + out->coord[2] = (b->coord[2] - a->coord[2])*scale; + out->coord[3] = (b->coord[3] - a->coord[3])*scale; +} + +static inline void sw_add_vertex_grad_CH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients) +{ + // Add gradients to Color + out->color[0] += gradients->color[0]; + out->color[1] += gradients->color[1]; + out->color[2] += gradients->color[2]; + out->color[3] += gradients->color[3]; + + // Add gradients to Pipeline coordinates + out->coord[0] += gradients->coord[0]; + out->coord[1] += gradients->coord[1]; + out->coord[2] += gradients->coord[2]; + out->coord[3] += gradients->coord[3]; +} + +static inline void sw_add_vertex_grad_scaled_CH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients, float scale) +{ + // Add gradients to Color + out->color[0] += gradients->color[0]*scale; + out->color[1] += gradients->color[1]*scale; + out->color[2] += gradients->color[2]*scale; + out->color[3] += gradients->color[3]*scale; + + // Add gradients to Pipeline coordinates + out->coord[0] += gradients->coord[0]*scale; + out->coord[1] += gradients->coord[1]*scale; + out->coord[2] += gradients->coord[2]*scale; + out->coord[3] += gradients->coord[3]*scale; } // Half conversion functions @@ -1331,13 +1410,6 @@ static inline uint8_t sw_expand_4to8(uint32_t v) { return (uint8_t)((v << 4) | v static inline uint8_t sw_expand_5to8(uint32_t v) { return (uint8_t)((v << 3) | (v >> 2)); } static inline uint8_t sw_expand_6to8(uint32_t v) { return (uint8_t)((v << 2) | (v >> 4)); } -static inline float sw_expand_1tof(uint32_t v) { return v? 1.0f : 0.0f; } -static inline float sw_expand_2tof(uint32_t v) { return (float)v*(1.0f/3.0f); } -static inline float sw_expand_3tof(uint32_t v) { return (float)v*(1.0f/7.0f); } -static inline float sw_expand_4tof(uint32_t v) { return (float)v*(1.0f/15.0f); } -static inline float sw_expand_5tof(uint32_t v) { return (float)v*(1.0f/31.0f); } -static inline float sw_expand_6tof(uint32_t v) { return (float)v*(1.0f/63.0f); } - static inline uint32_t sw_compress_8to1(uint8_t v) { return v >> 7; } static inline uint32_t sw_compress_8to2(uint8_t v) { return v >> 6; } static inline uint32_t sw_compress_8to3(uint8_t v) { return v >> 5; } @@ -1345,19 +1417,106 @@ static inline uint32_t sw_compress_8to4(uint8_t v) { return v >> 4; } static inline uint32_t sw_compress_8to5(uint8_t v) { return v >> 3; } static inline uint32_t sw_compress_8to6(uint8_t v) { return v >> 2; } -static inline uint32_t sw_compress_fto1(float v) { return (v >= 0.5f)? 1 : 0; } -static inline uint32_t sw_compress_fto2(float v) { return (uint32_t)(v*3.0f + 0.5f) & 0x03; } -static inline uint32_t sw_compress_fto3(float v) { return (uint32_t)(v*7.0f + 0.5f) & 0x07; } -static inline uint32_t sw_compress_fto4(float v) { return (uint32_t)(v*15.0f + 0.5f) & 0x0F; } -static inline uint32_t sw_compress_fto5(float v) { return (uint32_t)(v*31.0f + 0.5f) & 0x1F; } -static inline uint32_t sw_compress_fto6(float v) { return (uint32_t)(v*63.0f + 0.5f) & 0x3F; } +static inline void sw_color8_to_color(float *SW_RESTRICT dst, const uint8_t *SW_RESTRICT src) +{ +#if defined(SW_HAS_NEON) + uint8x8_t bytes = vreinterpret_u8_u32(vld1_dup_u32((const uint32_t *)src)); + uint16x8_t words = vmovl_u8(bytes); + uint32x4_t dwords = vmovl_u16(vget_low_u16(words)); + float32x4_t fvals = vmulq_f32(vcvtq_f32_u32(dwords), vdupq_n_f32(SW_INV_255)); + vst1q_f32(dst, fvals); + +#elif defined(SW_HAS_SSE41) + __m128i bytes = _mm_loadu_si32(src); + __m128 fvals = _mm_mul_ps(_mm_cvtepi32_ps(_mm_cvtepu8_epi32(bytes)), _mm_set1_ps(SW_INV_255)); + _mm_storeu_ps(dst, fvals); + +#elif defined(SW_HAS_SSE2) + __m128i zero = _mm_setzero_si128(); + __m128i bytes = _mm_loadu_si32(src); + __m128i words = _mm_unpacklo_epi8(bytes, zero); + __m128i dwords = _mm_unpacklo_epi16(words, zero); + __m128 fvals = _mm_mul_ps(_mm_cvtepi32_ps(dwords), _mm_set1_ps(SW_INV_255)); + _mm_storeu_ps(dst, fvals); + +#elif defined(SW_HAS_RVV) + // TODO: WARNING: Sample code generated by AI, needs testing and review + size_t vl = __riscv_vsetvl_e8m1(4); // Set vector length for 8-bit input elements + vuint8m1_t vsrc_u8 = __riscv_vle8_v_u8m1(src, vl); // Load 4 unsigned 8-bit integers + vuint32m1_t vsrc_u32 = __riscv_vwcvt_xu_u_v_u32m1(vsrc_u8, vl); // Widen to 32-bit unsigned integers + vfloat32m1_t vsrc_f32 = __riscv_vfcvt_f_xu_v_f32m1(vsrc_u32, vl); // Convert to float32 + vfloat32m1_t vnorm = __riscv_vfmul_vf_f32m1(vsrc_f32, SW_INV_255, vl); // Multiply by 1/255.0 to normalize + __riscv_vse32_v_f32m1(dst, vnorm, vl); // Store result + +#elif SW_USE_COLOR_LUT + dst[0] = SW_LUT_UINT8_TO_FLOAT[src[0]]; + dst[1] = SW_LUT_UINT8_TO_FLOAT[src[1]]; + dst[2] = SW_LUT_UINT8_TO_FLOAT[src[2]]; + dst[3] = SW_LUT_UINT8_TO_FLOAT[src[3]]; + +#else + dst[0] = (float)src[0]*SW_INV_255; + dst[1] = (float)src[1]*SW_INV_255; + dst[2] = (float)src[2]*SW_INV_255; + dst[3] = (float)src[3]*SW_INV_255; +#endif +} + +static inline void sw_color_to_color8(uint8_t *SW_RESTRICT dst, const float *SW_RESTRICT src) +{ +#if defined(SW_HAS_NEON) + float32x4_t fvals = vmulq_f32(vld1q_f32(src), vdupq_n_f32(255.0f)); + uint32x4_t i32 = vcvtq_u32_f32(fvals); + uint16x4_t i16 = vmovn_u32(i32); + uint8x8_t i8 = vmovn_u16(vcombine_u16(i16, i16)); + vst1_lane_u32((uint32_t *)dst, vreinterpret_u32_u8(i8), 0); + +#elif defined(SW_HAS_SSE41) + __m128 fvals = _mm_mul_ps(_mm_loadu_ps(src), _mm_set1_ps(255.0f)); + __m128i i32 = _mm_cvttps_epi32(fvals); + __m128i i16 = _mm_packus_epi32(i32, i32); + __m128i i8 = _mm_packus_epi16(i16, i16); + _mm_storeu_si32(dst, i8); + +#elif defined(SW_HAS_SSE2) + __m128 fvals = _mm_mul_ps(_mm_loadu_ps(src), _mm_set1_ps(255.0f)); + __m128i i32 = _mm_cvttps_epi32(fvals); + __m128i i16 = _mm_packs_epi32(i32, i32); + __m128i i8 = _mm_packus_epi16(i16, i16); + _mm_storeu_si32(dst, i8); + +#elif defined(SW_HAS_RVV) + // TODO: WARNING: Sample code generated by AI, needs testing and review + // REVIEW: It shouldn't perform so many operations; take inspiration from other versions + // NOTE: RVV 1.0 specs define the use of __riscv_ prefix for instrinsic functions + size_t vl = __riscv_vsetvl_e32m1(4); // Load up to 4 floats into a vector register + vfloat32m1_t vsrc = __riscv_vle32_v_f32m1(src, vl); // Load float32 values + + // Multiply by 255.0f and add 0.5f for rounding + vfloat32m1_t vscaled = __riscv_vfmul_vf_f32m1(vsrc, 255.0f, vl); + vscaled = __riscv_vfadd_vf_f32m1(vscaled, 0.5f, vl); + + // Convert to unsigned integer (truncate toward zero) + vuint32m1_t vu32 = __riscv_vfcvt_xu_f_v_u32m1(vscaled, vl); + + // Narrow from u32 -> u8 + vuint8m1_t vu8 = __riscv_vnclipu_wx_u8m1(vu32, 0, vl); // Round toward zero + __riscv_vse8_v_u8m1(dst, vu8, vl); // Store result + +#else + dst[0] = (uint8_t)(src[0]*255.0f); + dst[1] = (uint8_t)(src[1]*255.0f); + dst[2] = (uint8_t)(src[2]*255.0f); + dst[3] = (uint8_t)(src[3]*255.0f); +#endif +} //------------------------------------------------------------------------------------------- // Object pool functions //------------------------------------------------------------------------------------------- static bool sw_pool_init(sw_pool_t *pool, int capacity, size_t stride) { - *pool = (sw_pool_t){ 0 }; + *pool = (sw_pool_t) { 0 }; pool->data = SW_CALLOC(capacity, stride); pool->gen = SW_CALLOC(capacity, sizeof(uint8_t)); @@ -1492,51 +1651,6 @@ static inline bool sw_is_face_valid(int face) return (face == SW_FRONT || face == SW_BACK); } -static inline bool sw_is_blend_src_factor_valid(int blend) -{ - bool result = false; - - switch (blend) - { - case SW_ZERO: - case SW_ONE: - case SW_SRC_COLOR: - case SW_ONE_MINUS_SRC_COLOR: - case SW_SRC_ALPHA: - case SW_ONE_MINUS_SRC_ALPHA: - case SW_DST_ALPHA: - case SW_ONE_MINUS_DST_ALPHA: - case SW_DST_COLOR: - case SW_ONE_MINUS_DST_COLOR: - case SW_SRC_ALPHA_SATURATE: result = true; break; - default: break; - } - - return result; -} - -static inline bool sw_is_blend_dst_factor_valid(int blend) -{ - bool result = false; - - switch (blend) - { - case SW_ZERO: - case SW_ONE: - case SW_SRC_COLOR: - case SW_ONE_MINUS_SRC_COLOR: - case SW_SRC_ALPHA: - case SW_ONE_MINUS_SRC_ALPHA: - case SW_DST_ALPHA: - case SW_ONE_MINUS_DST_ALPHA: - case SW_DST_COLOR: - case SW_ONE_MINUS_DST_COLOR: result = true; break; - default: break; - } - - return result; -} - static inline bool sw_is_ready_to_render(void) { return (swCheckFramebufferStatus() == SW_FRAMEBUFFER_COMPLETE); @@ -1623,7 +1737,20 @@ static inline int sw_pixel_get_format(SWformat format, SWtype type) return SW_PIXELFORMAT_UNKNOWN; } -static inline void sw_pixel_get_color8_GRAYSCALE(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline bool sw_pixel_is_depth_format(sw_pixelformat_t format) +{ + switch (format) + { + case SW_PIXELFORMAT_DEPTH_D8: + case SW_PIXELFORMAT_DEPTH_D16: + case SW_PIXELFORMAT_DEPTH_D32: return true; + default: break; + } + + return false; +} + +static inline void sw_pixel_read_color8_GRAYSCALE(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { uint8_t gray = ((const uint8_t *)pixels)[offset]; color[0] = gray; @@ -1632,7 +1759,7 @@ static inline void sw_pixel_get_color8_GRAYSCALE(uint8_t *SW_RESTRICT color, con color[3] = 255; } -static inline void sw_pixel_get_color8_GRAYALPHA(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color8_GRAYALPHA(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { const uint8_t *src = &((const uint8_t *)pixels)[offset*2]; color[0] = src[0]; @@ -1641,7 +1768,7 @@ static inline void sw_pixel_get_color8_GRAYALPHA(uint8_t *SW_RESTRICT color, con color[3] = src[1]; } -static inline void sw_pixel_get_color8_R3G3B2(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color8_R3G3B2(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { uint8_t pixel = ((const uint8_t *)pixels)[offset]; color[0] = sw_expand_3to8((pixel >> 5) & 0x07); @@ -1650,7 +1777,7 @@ static inline void sw_pixel_get_color8_R3G3B2(uint8_t *SW_RESTRICT color, const color[3] = 255; } -static inline void sw_pixel_get_color8_R5G6B5(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color8_R5G6B5(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { uint16_t pixel = ((const uint16_t *)pixels)[offset]; color[0] = sw_expand_5to8((pixel >> 11) & 0x1F); @@ -1659,7 +1786,7 @@ static inline void sw_pixel_get_color8_R5G6B5(uint8_t *SW_RESTRICT color, const color[3] = 255; } -static inline void sw_pixel_get_color8_R8G8B8(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color8_R8G8B8(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { const uint8_t *src = &((const uint8_t *)pixels)[offset*3]; color[0] = src[0]; @@ -1668,7 +1795,7 @@ static inline void sw_pixel_get_color8_R8G8B8(uint8_t *SW_RESTRICT color, const color[3] = 255; } -static inline void sw_pixel_get_color8_R5G5B5A1(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color8_R5G5B5A1(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { uint16_t pixel = ((const uint16_t *)pixels)[offset]; color[0] = sw_expand_5to8((pixel >> 11) & 0x1F); @@ -1677,7 +1804,7 @@ static inline void sw_pixel_get_color8_R5G5B5A1(uint8_t *SW_RESTRICT color, cons color[3] = sw_expand_1to8( pixel & 0x01); } -static inline void sw_pixel_get_color8_R4G4B4A4(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color8_R4G4B4A4(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { uint16_t pixel = ((const uint16_t *)pixels)[offset]; color[0] = sw_expand_4to8((pixel >> 12) & 0x0F); @@ -1686,7 +1813,7 @@ static inline void sw_pixel_get_color8_R4G4B4A4(uint8_t *SW_RESTRICT color, cons color[3] = sw_expand_4to8( pixel & 0x0F); } -static inline void sw_pixel_get_color8_R8G8B8A8(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color8_R8G8B8A8(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { const uint8_t *src = &((const uint8_t *)pixels)[offset*4]; color[0] = src[0]; @@ -1695,7 +1822,7 @@ static inline void sw_pixel_get_color8_R8G8B8A8(uint8_t *SW_RESTRICT color, cons color[3] = src[3]; } -static inline void sw_pixel_get_color8_R32(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color8_R32(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { uint8_t gray = (uint8_t)(((const float *)pixels)[offset]*255.0f); color[0] = gray; @@ -1704,7 +1831,7 @@ static inline void sw_pixel_get_color8_R32(uint8_t *SW_RESTRICT color, const voi color[3] = 255; } -static inline void sw_pixel_get_color8_R32G32B32(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color8_R32G32B32(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { const float *src = &((const float *)pixels)[offset*3]; color[0] = (uint8_t)(src[0]*255.0f); @@ -1713,7 +1840,7 @@ static inline void sw_pixel_get_color8_R32G32B32(uint8_t *SW_RESTRICT color, con color[3] = 255; } -static inline void sw_pixel_get_color8_R32G32B32A32(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color8_R32G32B32A32(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { const float *src = &((const float *)pixels)[offset*4]; color[0] = (uint8_t)(src[0]*255.0f); @@ -1722,7 +1849,7 @@ static inline void sw_pixel_get_color8_R32G32B32A32(uint8_t *SW_RESTRICT color, color[3] = (uint8_t)(src[3]*255.0f); } -static inline void sw_pixel_get_color8_R16(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color8_R16(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { uint8_t gray = (uint8_t)(sw_half_to_float(((const uint16_t *)pixels)[offset])*255.0f); color[0] = gray; @@ -1731,7 +1858,7 @@ static inline void sw_pixel_get_color8_R16(uint8_t *SW_RESTRICT color, const voi color[3] = 255; } -static inline void sw_pixel_get_color8_R16G16B16(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color8_R16G16B16(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { const uint16_t *src = &((const uint16_t *)pixels)[offset*3]; color[0] = (uint8_t)(sw_half_to_float(src[0])*255.0f); @@ -1740,7 +1867,7 @@ static inline void sw_pixel_get_color8_R16G16B16(uint8_t *SW_RESTRICT color, con color[3] = 255; } -static inline void sw_pixel_get_color8_R16G16B16A16(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color8_R16G16B16A16(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { const uint16_t *src = &((const uint16_t *)pixels)[offset*4]; color[0] = (uint8_t)(sw_half_to_float(src[0])*255.0f); @@ -1749,53 +1876,49 @@ static inline void sw_pixel_get_color8_R16G16B16A16(uint8_t *SW_RESTRICT color, color[3] = (uint8_t)(sw_half_to_float(src[3])*255.0f); } -static inline void sw_pixel_get_color8(uint8_t *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset, sw_pixelformat_t format) +static inline sw_pixel_read_color8_f sw_pixel_get_read_color8_func(sw_pixelformat_t format) { switch (format) { - case SW_PIXELFORMAT_COLOR_GRAYSCALE: sw_pixel_get_color8_GRAYSCALE(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_GRAYALPHA: sw_pixel_get_color8_GRAYALPHA(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R3G3B2: sw_pixel_get_color8_R3G3B2(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R5G6B5: sw_pixel_get_color8_R5G6B5(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R8G8B8: sw_pixel_get_color8_R8G8B8(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R5G5B5A1: sw_pixel_get_color8_R5G5B5A1(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R4G4B4A4: sw_pixel_get_color8_R4G4B4A4(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R8G8B8A8: sw_pixel_get_color8_R8G8B8A8(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R32: sw_pixel_get_color8_R32(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R32G32B32: sw_pixel_get_color8_R32G32B32(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R32G32B32A32: sw_pixel_get_color8_R32G32B32A32(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R16: sw_pixel_get_color8_R16(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R16G16B16: sw_pixel_get_color8_R16G16B16(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R16G16B16A16: sw_pixel_get_color8_R16G16B16A16(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_GRAYSCALE: return sw_pixel_read_color8_GRAYSCALE; + case SW_PIXELFORMAT_COLOR_GRAYALPHA: return sw_pixel_read_color8_GRAYALPHA; + case SW_PIXELFORMAT_COLOR_R3G3B2: return sw_pixel_read_color8_R3G3B2; + case SW_PIXELFORMAT_COLOR_R5G6B5: return sw_pixel_read_color8_R5G6B5; + case SW_PIXELFORMAT_COLOR_R8G8B8: return sw_pixel_read_color8_R8G8B8; + case SW_PIXELFORMAT_COLOR_R5G5B5A1: return sw_pixel_read_color8_R5G5B5A1; + case SW_PIXELFORMAT_COLOR_R4G4B4A4: return sw_pixel_read_color8_R4G4B4A4; + case SW_PIXELFORMAT_COLOR_R8G8B8A8: return sw_pixel_read_color8_R8G8B8A8; + case SW_PIXELFORMAT_COLOR_R32: return sw_pixel_read_color8_R32; + case SW_PIXELFORMAT_COLOR_R32G32B32: return sw_pixel_read_color8_R32G32B32; + case SW_PIXELFORMAT_COLOR_R32G32B32A32: return sw_pixel_read_color8_R32G32B32A32; + case SW_PIXELFORMAT_COLOR_R16: return sw_pixel_read_color8_R16; + case SW_PIXELFORMAT_COLOR_R16G16B16: return sw_pixel_read_color8_R16G16B16; + case SW_PIXELFORMAT_COLOR_R16G16B16A16: return sw_pixel_read_color8_R16G16B16A16; case SW_PIXELFORMAT_UNKNOWN: case SW_PIXELFORMAT_DEPTH_D8: case SW_PIXELFORMAT_DEPTH_D16: case SW_PIXELFORMAT_DEPTH_D32: case SW_PIXELFORMAT_COUNT: - { - color[0] = 0.0f; - color[1] = 0.0f; - color[2] = 0.0f; - color[3] = 0.0f; - } break; default: break; } + + return NULL; } -static inline void sw_pixel_set_color8_GRAYSCALE(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color8_GRAYSCALE(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) { ((uint8_t *)pixels)[offset] = sw_luminance8(color); } -static inline void sw_pixel_set_color8_GRAYALPHA(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color8_GRAYALPHA(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) { uint8_t *dst = &((uint8_t *)pixels)[offset*2]; dst[0] = sw_luminance8(color); dst[1] = color[3]; } -static inline void sw_pixel_set_color8_R3G3B2(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color8_R3G3B2(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) { uint8_t pixel = (sw_compress_8to3(color[0]) << 5) | (sw_compress_8to3(color[1]) << 2) @@ -1803,7 +1926,7 @@ static inline void sw_pixel_set_color8_R3G3B2(void *SW_RESTRICT pixels, const ui ((uint8_t *)pixels)[offset] = pixel; } -static inline void sw_pixel_set_color8_R5G6B5(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color8_R5G6B5(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) { uint16_t pixel = (sw_compress_8to5(color[0]) << 11) | (sw_compress_8to6(color[1]) << 5) @@ -1811,7 +1934,7 @@ static inline void sw_pixel_set_color8_R5G6B5(void *SW_RESTRICT pixels, const ui ((uint16_t *)pixels)[offset] = pixel; } -static inline void sw_pixel_set_color8_R8G8B8(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color8_R8G8B8(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) { uint8_t *dst = &((uint8_t *)pixels)[offset*3]; dst[0] = color[0]; @@ -1819,7 +1942,7 @@ static inline void sw_pixel_set_color8_R8G8B8(void *SW_RESTRICT pixels, const ui dst[2] = color[2]; } -static inline void sw_pixel_set_color8_R5G5B5A1(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color8_R5G5B5A1(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) { uint16_t pixel = (sw_compress_8to5(color[0]) << 11) | (sw_compress_8to5(color[1]) << 6) @@ -1828,7 +1951,7 @@ static inline void sw_pixel_set_color8_R5G5B5A1(void *SW_RESTRICT pixels, const ((uint16_t *)pixels)[offset] = pixel; } -static inline void sw_pixel_set_color8_R4G4B4A4(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color8_R4G4B4A4(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) { uint16_t pixel = (sw_compress_8to4(color[0]) << 12) | (sw_compress_8to4(color[1]) << 8) @@ -1837,7 +1960,7 @@ static inline void sw_pixel_set_color8_R4G4B4A4(void *SW_RESTRICT pixels, const ((uint16_t *)pixels)[offset] = pixel; } -static inline void sw_pixel_set_color8_R8G8B8A8(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color8_R8G8B8A8(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) { uint8_t *dst = &((uint8_t *)pixels)[offset*4]; dst[0] = color[0]; @@ -1846,12 +1969,12 @@ static inline void sw_pixel_set_color8_R8G8B8A8(void *SW_RESTRICT pixels, const dst[3] = color[3]; } -static inline void sw_pixel_set_color8_R32(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color8_R32(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) { ((float *)pixels)[offset] = sw_luminance8(color)*SW_INV_255; } -static inline void sw_pixel_set_color8_R32G32B32(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color8_R32G32B32(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) { float *dst = &((float *)pixels)[offset*3]; dst[0] = color[0]*SW_INV_255; @@ -1859,7 +1982,7 @@ static inline void sw_pixel_set_color8_R32G32B32(void *SW_RESTRICT pixels, const dst[2] = color[2]*SW_INV_255; } -static inline void sw_pixel_set_color8_R32G32B32A32(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color8_R32G32B32A32(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) { float *dst = &((float *)pixels)[offset*4]; dst[0] = color[0]*SW_INV_255; @@ -1868,12 +1991,12 @@ static inline void sw_pixel_set_color8_R32G32B32A32(void *SW_RESTRICT pixels, co dst[3] = color[3]*SW_INV_255; } -static inline void sw_pixel_set_color8_R16(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color8_R16(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) { ((uint16_t *)pixels)[offset] = sw_float_to_half(sw_luminance8(color)*SW_INV_255); } -static inline void sw_pixel_set_color8_R16G16B16(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color8_R16G16B16(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) { uint16_t *dst = &((uint16_t *)pixels)[offset*3]; dst[0] = sw_float_to_half(color[0]*SW_INV_255); @@ -1881,7 +2004,7 @@ static inline void sw_pixel_set_color8_R16G16B16(void *SW_RESTRICT pixels, const dst[2] = sw_float_to_half(color[2]*SW_INV_255); } -static inline void sw_pixel_set_color8_R16G16B16A16(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color8_R16G16B16A16(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset) { uint16_t *dst = &((uint16_t *)pixels)[offset*4]; dst[0] = sw_float_to_half(color[0]*SW_INV_255); @@ -1890,35 +2013,37 @@ static inline void sw_pixel_set_color8_R16G16B16A16(void *SW_RESTRICT pixels, co dst[3] = sw_float_to_half(color[3]*SW_INV_255); } -static inline void sw_pixel_set_color8(void *SW_RESTRICT pixels, const uint8_t *SW_RESTRICT color, uint32_t offset, sw_pixelformat_t format) +static inline sw_pixel_write_color8_f sw_pixel_get_write_color8_func(sw_pixelformat_t format) { switch (format) { - case SW_PIXELFORMAT_COLOR_GRAYSCALE: sw_pixel_set_color8_GRAYSCALE(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_GRAYALPHA: sw_pixel_set_color8_GRAYALPHA(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R3G3B2: sw_pixel_set_color8_R3G3B2(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R5G6B5: sw_pixel_set_color8_R5G6B5(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R8G8B8: sw_pixel_set_color8_R8G8B8(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R5G5B5A1: sw_pixel_set_color8_R5G5B5A1(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R4G4B4A4: sw_pixel_set_color8_R4G4B4A4(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R8G8B8A8: sw_pixel_set_color8_R8G8B8A8(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R32: sw_pixel_set_color8_R32(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R32G32B32: sw_pixel_set_color8_R32G32B32(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R32G32B32A32: sw_pixel_set_color8_R32G32B32A32(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R16: sw_pixel_set_color8_R16(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R16G16B16: sw_pixel_set_color8_R16G16B16(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R16G16B16A16: sw_pixel_set_color8_R16G16B16A16(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_GRAYSCALE: return sw_pixel_write_color8_GRAYSCALE; + case SW_PIXELFORMAT_COLOR_GRAYALPHA: return sw_pixel_write_color8_GRAYALPHA; + case SW_PIXELFORMAT_COLOR_R3G3B2: return sw_pixel_write_color8_R3G3B2; + case SW_PIXELFORMAT_COLOR_R5G6B5: return sw_pixel_write_color8_R5G6B5; + case SW_PIXELFORMAT_COLOR_R8G8B8: return sw_pixel_write_color8_R8G8B8; + case SW_PIXELFORMAT_COLOR_R5G5B5A1: return sw_pixel_write_color8_R5G5B5A1; + case SW_PIXELFORMAT_COLOR_R4G4B4A4: return sw_pixel_write_color8_R4G4B4A4; + case SW_PIXELFORMAT_COLOR_R8G8B8A8: return sw_pixel_write_color8_R8G8B8A8; + case SW_PIXELFORMAT_COLOR_R32: return sw_pixel_write_color8_R32; + case SW_PIXELFORMAT_COLOR_R32G32B32: return sw_pixel_write_color8_R32G32B32; + case SW_PIXELFORMAT_COLOR_R32G32B32A32: return sw_pixel_write_color8_R32G32B32A32; + case SW_PIXELFORMAT_COLOR_R16: return sw_pixel_write_color8_R16; + case SW_PIXELFORMAT_COLOR_R16G16B16: return sw_pixel_write_color8_R16G16B16; + case SW_PIXELFORMAT_COLOR_R16G16B16A16: return sw_pixel_write_color8_R16G16B16A16; case SW_PIXELFORMAT_UNKNOWN: case SW_PIXELFORMAT_DEPTH_D8: case SW_PIXELFORMAT_DEPTH_D16: case SW_PIXELFORMAT_DEPTH_D32: - case SW_PIXELFORMAT_COUNT: break; + case SW_PIXELFORMAT_COUNT: default: break; } + + return NULL; } -static inline void sw_pixel_get_color_GRAYSCALE(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color_GRAYSCALE(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { float gray = ((const uint8_t *)pixels)[offset]*SW_INV_255; color[0] = gray; @@ -1927,7 +2052,7 @@ static inline void sw_pixel_get_color_GRAYSCALE(float *SW_RESTRICT color, const color[3] = 1.0f; } -static inline void sw_pixel_get_color_GRAYALPHA(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color_GRAYALPHA(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { const uint8_t *src = &((const uint8_t *)pixels)[offset*2]; float gray = src[0]*SW_INV_255; @@ -1937,93 +2062,47 @@ static inline void sw_pixel_get_color_GRAYALPHA(float *SW_RESTRICT color, const color[3] = src[1]*SW_INV_255; } -static inline void sw_pixel_get_color_R3G3B2(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color_R3G3B2(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { - uint8_t pixel = ((const uint8_t *)pixels)[offset]; - color[0] = sw_expand_3tof((pixel >> 5) & 0x07); - color[1] = sw_expand_3tof((pixel >> 2) & 0x07); - color[2] = sw_expand_2tof( pixel & 0x03); - color[3] = 1.0f; + uint8_t unpack[4]; + sw_pixel_read_color8_R3G3B2(unpack, pixels, offset); + sw_color8_to_color(color, unpack); } -static inline void sw_pixel_get_color_R5G6B5(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color_R5G6B5(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { - uint16_t pixel = ((const uint16_t *)pixels)[offset]; - color[0] = sw_expand_5tof((pixel >> 11) & 0x1F); - color[1] = sw_expand_6tof((pixel >> 5) & 0x3F); - color[2] = sw_expand_5tof( pixel & 0x1F); - color[3] = 1.0f; + uint8_t unpack[4]; + sw_pixel_read_color8_R5G6B5(unpack, pixels, offset); + sw_color8_to_color(color, unpack); } -static inline void sw_pixel_get_color_R8G8B8(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color_R8G8B8(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { - const uint8_t *src = &((const uint8_t *)pixels)[offset*3]; - color[0] = src[0]*SW_INV_255; - color[1] = src[1]*SW_INV_255; - color[2] = src[2]*SW_INV_255; - color[3] = 1.0f; + uint8_t unpack[4]; + sw_pixel_read_color8_R8G8B8(unpack, pixels, offset); + sw_color8_to_color(color, unpack); } -static inline void sw_pixel_get_color_R5G5B5A1(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color_R5G5B5A1(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { - uint16_t pixel = ((const uint16_t *)pixels)[offset]; - color[0] = sw_expand_5tof((pixel >> 11) & 0x1F); - color[1] = sw_expand_5tof((pixel >> 6) & 0x1F); - color[2] = sw_expand_5tof((pixel >> 1) & 0x1F); - color[3] = sw_expand_1tof( pixel & 0x01); + uint8_t unpack[4]; + sw_pixel_read_color8_R5G5B5A1(unpack, pixels, offset); + sw_color8_to_color(color, unpack); } -static inline void sw_pixel_get_color_R4G4B4A4(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color_R4G4B4A4(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { - uint16_t pixel = ((const uint16_t *)pixels)[offset]; - color[0] = sw_expand_4tof((pixel >> 12) & 0x0F); - color[1] = sw_expand_4tof((pixel >> 8) & 0x0F); - color[2] = sw_expand_4tof((pixel >> 4) & 0x0F); - color[3] = sw_expand_4tof( pixel & 0x0F); + uint8_t unpack[4]; + sw_pixel_read_color8_R4G4B4A4(unpack, pixels, offset); + sw_color8_to_color(color, unpack); } -static inline void sw_pixel_get_color_R8G8B8A8(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color_R8G8B8A8(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { - const uint8_t *src = &((const uint8_t *)pixels)[offset*4]; - -#if defined(SW_HAS_NEON) - uint32_t tmp = (uint32_t)src[0] | ((uint32_t)src[1] << 8) | ((uint32_t)src[2] << 16) | ((uint32_t)src[3] << 24); - uint8x8_t bytes = vreinterpret_u8_u32(vdup_n_u32(tmp)); - uint16x8_t words = vmovl_u8(bytes); - uint32x4_t dwords = vmovl_u16(vget_low_u16(words)); - float32x4_t fvals = vmulq_f32(vcvtq_f32_u32(dwords), vdupq_n_f32(SW_INV_255)); - vst1q_f32(color, fvals); - -#elif defined(SW_HAS_SSE41) - __m128i bytes = _mm_loadu_si32(src); - __m128 fvals = _mm_mul_ps(_mm_cvtepi32_ps(_mm_cvtepu8_epi32(bytes)), _mm_set1_ps(SW_INV_255)); - _mm_storeu_ps(color, fvals); - -#elif defined(SW_HAS_SSE2) - __m128i bytes = _mm_loadu_si32(src); - __m128i words = _mm_unpacklo_epi8(bytes, _mm_setzero_si128()); - __m128i dwords = _mm_unpacklo_epi16(words, _mm_setzero_si128()); - __m128 fvals = _mm_mul_ps(_mm_cvtepi32_ps(dwords), _mm_set1_ps(SW_INV_255)); - _mm_storeu_ps(color, fvals); - -#elif defined(SW_HAS_RVV) - // TODO: WARNING: Sample code generated by AI, needs testing and review - size_t vl = __riscv_vsetvl_e8m1(4); // Set vector length for 8-bit input elements - vuint8m1_t vsrc_u8 = __riscv_vle8_v_u8m1(src, vl); // Load 4 unsigned 8-bit integers - vuint32m1_t vsrc_u32 = __riscv_vwcvt_xu_u_v_u32m1(vsrc_u8, vl); // Widen to 32-bit unsigned integers - vfloat32m1_t vsrc_f32 = __riscv_vfcvt_f_xu_v_f32m1(vsrc_u32, vl); // Convert to float32 - vfloat32m1_t vnorm = __riscv_vfmul_vf_f32m1(vsrc_f32, SW_INV_255, vl); // Multiply by 1/255.0 to normalize - __riscv_vse32_v_f32m1(color, vnorm, vl); // Store result - -#else - color[0] = (float)src[0]*SW_INV_255; - color[1] = (float)src[1]*SW_INV_255; - color[2] = (float)src[2]*SW_INV_255; - color[3] = (float)src[3]*SW_INV_255; -#endif + sw_color8_to_color(color, &((const uint8_t *)pixels)[offset*4]); } -static inline void sw_pixel_get_color_R32(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color_R32(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { float val = ((const float *)pixels)[offset]; color[0] = val; @@ -2032,7 +2111,7 @@ static inline void sw_pixel_get_color_R32(float *SW_RESTRICT color, const void * color[3] = 1.0f; } -static inline void sw_pixel_get_color_R32G32B32(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color_R32G32B32(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { const float *src = &((const float *)pixels)[offset*3]; color[0] = src[0]; @@ -2041,7 +2120,7 @@ static inline void sw_pixel_get_color_R32G32B32(float *SW_RESTRICT color, const color[3] = 1.0f; } -static inline void sw_pixel_get_color_R32G32B32A32(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color_R32G32B32A32(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { const float *src = &((const float *)pixels)[offset*4]; color[0] = src[0]; @@ -2050,7 +2129,7 @@ static inline void sw_pixel_get_color_R32G32B32A32(float *SW_RESTRICT color, con color[3] = src[3]; } -static inline void sw_pixel_get_color_R16(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color_R16(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { float val = sw_half_to_float(((const uint16_t *)pixels)[offset]); color[0] = val; @@ -2059,7 +2138,7 @@ static inline void sw_pixel_get_color_R16(float *SW_RESTRICT color, const void * color[3] = 1.0f; } -static inline void sw_pixel_get_color_R16G16B16(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color_R16G16B16(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { const uint16_t *src = &((const uint16_t *)pixels)[offset*3]; color[0] = sw_half_to_float(src[0]); @@ -2068,7 +2147,7 @@ static inline void sw_pixel_get_color_R16G16B16(float *SW_RESTRICT color, const color[3] = 1.0f; } -static inline void sw_pixel_get_color_R16G16B16A16(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) +static inline void sw_pixel_read_color_R16G16B16A16(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset) { const uint16_t *src = &((const uint16_t *)pixels)[offset*4]; color[0] = sw_half_to_float(src[0]); @@ -2077,154 +2156,94 @@ static inline void sw_pixel_get_color_R16G16B16A16(float *SW_RESTRICT color, con color[3] = sw_half_to_float(src[3]); } -static inline void sw_pixel_get_color(float *SW_RESTRICT color, const void *SW_RESTRICT pixels, uint32_t offset, sw_pixelformat_t format) +static inline sw_pixel_read_color_f sw_pixel_get_read_color_func(sw_pixelformat_t format) { switch (format) { - case SW_PIXELFORMAT_COLOR_GRAYSCALE: sw_pixel_get_color_GRAYSCALE(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_GRAYALPHA: sw_pixel_get_color_GRAYALPHA(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R3G3B2: sw_pixel_get_color_R3G3B2(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R5G6B5: sw_pixel_get_color_R5G6B5(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R8G8B8: sw_pixel_get_color_R8G8B8(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R5G5B5A1: sw_pixel_get_color_R5G5B5A1(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R4G4B4A4: sw_pixel_get_color_R4G4B4A4(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R8G8B8A8: sw_pixel_get_color_R8G8B8A8(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R32: sw_pixel_get_color_R32(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R32G32B32: sw_pixel_get_color_R32G32B32(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R32G32B32A32: sw_pixel_get_color_R32G32B32A32(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R16: sw_pixel_get_color_R16(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R16G16B16: sw_pixel_get_color_R16G16B16(color, pixels, offset); break; - case SW_PIXELFORMAT_COLOR_R16G16B16A16: sw_pixel_get_color_R16G16B16A16(color, pixels, offset); break; + case SW_PIXELFORMAT_COLOR_GRAYSCALE: return sw_pixel_read_color_GRAYSCALE; + case SW_PIXELFORMAT_COLOR_GRAYALPHA: return sw_pixel_read_color_GRAYALPHA; + case SW_PIXELFORMAT_COLOR_R3G3B2: return sw_pixel_read_color_R3G3B2; + case SW_PIXELFORMAT_COLOR_R5G6B5: return sw_pixel_read_color_R5G6B5; + case SW_PIXELFORMAT_COLOR_R8G8B8: return sw_pixel_read_color_R8G8B8; + case SW_PIXELFORMAT_COLOR_R5G5B5A1: return sw_pixel_read_color_R5G5B5A1; + case SW_PIXELFORMAT_COLOR_R4G4B4A4: return sw_pixel_read_color_R4G4B4A4; + case SW_PIXELFORMAT_COLOR_R8G8B8A8: return sw_pixel_read_color_R8G8B8A8; + case SW_PIXELFORMAT_COLOR_R32: return sw_pixel_read_color_R32; + case SW_PIXELFORMAT_COLOR_R32G32B32: return sw_pixel_read_color_R32G32B32; + case SW_PIXELFORMAT_COLOR_R32G32B32A32: return sw_pixel_read_color_R32G32B32A32; + case SW_PIXELFORMAT_COLOR_R16: return sw_pixel_read_color_R16; + case SW_PIXELFORMAT_COLOR_R16G16B16: return sw_pixel_read_color_R16G16B16; + case SW_PIXELFORMAT_COLOR_R16G16B16A16: return sw_pixel_read_color_R16G16B16A16; case SW_PIXELFORMAT_UNKNOWN: case SW_PIXELFORMAT_DEPTH_D8: case SW_PIXELFORMAT_DEPTH_D16: case SW_PIXELFORMAT_DEPTH_D32: case SW_PIXELFORMAT_COUNT: - { - color[0] = 0.0f; - color[1] = 0.0f; - color[2] = 0.0f; - color[3] = 0.0f; - } break; default: break; } + + return NULL; } -static inline void sw_pixel_set_color_GRAYSCALE(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color_GRAYSCALE(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) { ((uint8_t *)pixels)[offset] = (uint8_t)(sw_luminance(color)*255.0f); } -static inline void sw_pixel_set_color_GRAYALPHA(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color_GRAYALPHA(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) { uint8_t *dst = &((uint8_t *)pixels)[offset*2]; dst[0] = (uint8_t)(sw_luminance(color)*255.0f); dst[1] = (uint8_t)(color[3]*255.0f); } -static inline void sw_pixel_set_color_R3G3B2(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color_R3G3B2(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) { - uint8_t pixel = (sw_compress_fto3(color[0]) << 5) - | (sw_compress_fto3(color[1]) << 2) - | sw_compress_fto2(color[2]); - ((uint8_t *)pixels)[offset] = pixel; + uint8_t color8[4]; + sw_color_to_color8(color8, color); + sw_pixel_write_color8_R3G3B2(pixels, color8, offset); } -static inline void sw_pixel_set_color_R5G6B5(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color_R5G6B5(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) { - uint16_t pixel = (sw_compress_fto5(color[0]) << 11) - | (sw_compress_fto6(color[1]) << 5) - | sw_compress_fto5(color[2]); - ((uint16_t *)pixels)[offset] = pixel; + uint8_t color8[4]; + sw_color_to_color8(color8, color); + sw_pixel_write_color8_R5G6B5(pixels, color8, offset); } -static inline void sw_pixel_set_color_R8G8B8(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color_R8G8B8(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) { - uint8_t *dst = &((uint8_t *)pixels)[offset*3]; - dst[0] = (uint8_t)(color[0]*255.0f); - dst[1] = (uint8_t)(color[1]*255.0f); - dst[2] = (uint8_t)(color[2]*255.0f); + uint8_t color8[4]; + sw_color_to_color8(color8, color); + sw_pixel_write_color8_R8G8B8(pixels, color8, offset); } -static inline void sw_pixel_set_color_R5G5B5A1(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color_R5G5B5A1(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) { - uint16_t pixel = (sw_compress_fto5(color[0]) << 11) - | (sw_compress_fto5(color[1]) << 6) - | (sw_compress_fto5(color[2]) << 1) - | sw_compress_fto1(color[3]); - ((uint16_t *)pixels)[offset] = pixel; + uint8_t color8[4]; + sw_color_to_color8(color8, color); + sw_pixel_write_color8_R5G5B5A1(pixels, color8, offset); } -static inline void sw_pixel_set_color_R4G4B4A4(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color_R4G4B4A4(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) { - uint16_t pixel = (sw_compress_fto4(color[0]) << 12) - | (sw_compress_fto4(color[1]) << 8) - | (sw_compress_fto4(color[2]) << 4) - | sw_compress_fto4(color[3]); - ((uint16_t *)pixels)[offset] = pixel; + uint8_t color8[4]; + sw_color_to_color8(color8, color); + sw_pixel_write_color8_R4G4B4A4(pixels, color8, offset); } -static inline void sw_pixel_set_color_R8G8B8A8(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color_R8G8B8A8(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) { - uint8_t *dst = &((uint8_t *)pixels)[offset*4]; - -#if defined(SW_HAS_NEON) - float32x4_t fvals = vmulq_f32(vld1q_f32(color), vdupq_n_f32(255.0f)); - uint32x4_t i32 = vcvtq_u32_f32(fvals); - uint16x4_t i16 = vmovn_u32(i32); - uint8x8_t i8 = vmovn_u16(vcombine_u16(i16, i16)); - dst[0] = vget_lane_u8(i8, 0); - dst[1] = vget_lane_u8(i8, 1); - dst[2] = vget_lane_u8(i8, 2); - dst[3] = vget_lane_u8(i8, 3); - -#elif defined(SW_HAS_SSE41) - __m128 fvals = _mm_mul_ps(_mm_loadu_ps(color), _mm_set1_ps(255.0f)); - __m128i i32 = _mm_cvttps_epi32(fvals); - __m128i i16 = _mm_packus_epi32(i32, i32); - __m128i i8 = _mm_packus_epi16(i16, i16); - _mm_storeu_si32(dst, i8); - -#elif defined(SW_HAS_SSE2) - __m128 fvals = _mm_mul_ps(_mm_loadu_ps(color), _mm_set1_ps(255.0f)); - __m128i i32 = _mm_cvttps_epi32(fvals); - __m128i i16 = _mm_packs_epi32(i32, i32); - __m128i i8 = _mm_packus_epi16(i16, i16); - _mm_storeu_si32(dst, i8); - -#elif defined(SW_HAS_RVV) - // TODO: WARNING: Sample code generated by AI, needs testing and review - // REVIEW: It shouldn't perform so many operations; take inspiration from other versions - // NOTE: RVV 1.0 specs define the use of __riscv_ prefix for instrinsic functions - size_t vl = __riscv_vsetvl_e32m1(4); // Load up to 4 floats into a vector register - vfloat32m1_t vsrc = __riscv_vle32_v_f32m1(src, vl); // Load float32 values - - // Multiply by 255.0f and add 0.5f for rounding - vfloat32m1_t vscaled = __riscv_vfmul_vf_f32m1(vsrc, 255.0f, vl); - vscaled = __riscv_vfadd_vf_f32m1(vscaled, 0.5f, vl); - - // Convert to unsigned integer (truncate toward zero) - vuint32m1_t vu32 = __riscv_vfcvt_xu_f_v_u32m1(vscaled, vl); - - // Narrow from u32 -> u8 - vuint8m1_t vu8 = __riscv_vnclipu_wx_u8m1(vu32, 0, vl); // Round toward zero - __riscv_vse8_v_u8m1(dst, vu8, vl); // Store result - -#else - dst[0] = (uint8_t)(color[0]*255.0f); - dst[1] = (uint8_t)(color[1]*255.0f); - dst[2] = (uint8_t)(color[2]*255.0f); - dst[3] = (uint8_t)(color[3]*255.0f); -#endif + sw_color_to_color8(&((uint8_t *)pixels)[offset*4], color); } -static inline void sw_pixel_set_color_R32(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color_R32(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) { ((float *)pixels)[offset] = sw_luminance(color); } -static inline void sw_pixel_set_color_R32G32B32(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color_R32G32B32(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) { float *dst = &((float *)pixels)[offset*3]; dst[0] = color[0]; @@ -2232,7 +2251,7 @@ static inline void sw_pixel_set_color_R32G32B32(void *SW_RESTRICT pixels, const dst[2] = color[2]; } -static inline void sw_pixel_set_color_R32G32B32A32(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color_R32G32B32A32(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) { float *dst = &((float *)pixels)[offset*4]; dst[0] = color[0]; @@ -2241,12 +2260,12 @@ static inline void sw_pixel_set_color_R32G32B32A32(void *SW_RESTRICT pixels, con dst[3] = color[3]; } -static inline void sw_pixel_set_color_R16(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color_R16(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) { ((uint16_t *)pixels)[offset] = sw_float_to_half(sw_luminance(color)); } -static inline void sw_pixel_set_color_R16G16B16(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color_R16G16B16(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) { uint16_t *dst = &((uint16_t *)pixels)[offset*3]; dst[0] = sw_float_to_half(color[0]); @@ -2254,7 +2273,7 @@ static inline void sw_pixel_set_color_R16G16B16(void *SW_RESTRICT pixels, const dst[2] = sw_float_to_half(color[2]); } -static inline void sw_pixel_set_color_R16G16B16A16(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) +static inline void sw_pixel_write_color_R16G16B16A16(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset) { uint16_t *dst = &((uint16_t *)pixels)[offset*4]; dst[0] = sw_float_to_half(color[0]); @@ -2263,124 +2282,72 @@ static inline void sw_pixel_set_color_R16G16B16A16(void *SW_RESTRICT pixels, con dst[3] = sw_float_to_half(color[3]); } -static inline void sw_pixel_set_color(void *SW_RESTRICT pixels, const float *SW_RESTRICT color, uint32_t offset, sw_pixelformat_t format) +static inline sw_pixel_write_color_f sw_pixel_get_write_color_func(sw_pixelformat_t format) { switch (format) { - case SW_PIXELFORMAT_COLOR_GRAYSCALE: sw_pixel_set_color_GRAYSCALE(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_GRAYALPHA: sw_pixel_set_color_GRAYALPHA(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R3G3B2: sw_pixel_set_color_R3G3B2(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R5G6B5: sw_pixel_set_color_R5G6B5(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R8G8B8: sw_pixel_set_color_R8G8B8(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R5G5B5A1: sw_pixel_set_color_R5G5B5A1(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R4G4B4A4: sw_pixel_set_color_R4G4B4A4(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R8G8B8A8: sw_pixel_set_color_R8G8B8A8(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R32: sw_pixel_set_color_R32(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R32G32B32: sw_pixel_set_color_R32G32B32(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R32G32B32A32: sw_pixel_set_color_R32G32B32A32(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R16: sw_pixel_set_color_R16(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R16G16B16: sw_pixel_set_color_R16G16B16(pixels, color, offset); break; - case SW_PIXELFORMAT_COLOR_R16G16B16A16: sw_pixel_set_color_R16G16B16A16(pixels, color, offset); break; + case SW_PIXELFORMAT_COLOR_GRAYSCALE: return sw_pixel_write_color_GRAYSCALE; + case SW_PIXELFORMAT_COLOR_GRAYALPHA: return sw_pixel_write_color_GRAYALPHA; + case SW_PIXELFORMAT_COLOR_R3G3B2: return sw_pixel_write_color_R3G3B2; + case SW_PIXELFORMAT_COLOR_R5G6B5: return sw_pixel_write_color_R5G6B5; + case SW_PIXELFORMAT_COLOR_R8G8B8: return sw_pixel_write_color_R8G8B8; + case SW_PIXELFORMAT_COLOR_R5G5B5A1: return sw_pixel_write_color_R5G5B5A1; + case SW_PIXELFORMAT_COLOR_R4G4B4A4: return sw_pixel_write_color_R4G4B4A4; + case SW_PIXELFORMAT_COLOR_R8G8B8A8: return sw_pixel_write_color_R8G8B8A8; + case SW_PIXELFORMAT_COLOR_R32: return sw_pixel_write_color_R32; + case SW_PIXELFORMAT_COLOR_R32G32B32: return sw_pixel_write_color_R32G32B32; + case SW_PIXELFORMAT_COLOR_R32G32B32A32: return sw_pixel_write_color_R32G32B32A32; + case SW_PIXELFORMAT_COLOR_R16: return sw_pixel_write_color_R16; + case SW_PIXELFORMAT_COLOR_R16G16B16: return sw_pixel_write_color_R16G16B16; + case SW_PIXELFORMAT_COLOR_R16G16B16A16: return sw_pixel_write_color_R16G16B16A16; case SW_PIXELFORMAT_UNKNOWN: case SW_PIXELFORMAT_DEPTH_D8: case SW_PIXELFORMAT_DEPTH_D16: case SW_PIXELFORMAT_DEPTH_D32: - case SW_PIXELFORMAT_COUNT: break; + case SW_PIXELFORMAT_COUNT: + default: break; } + + return NULL; } -static inline float sw_pixel_get_depth_D8(const void *pixels, uint32_t offset) +static inline float sw_pixel_read_depth_D8(const void *pixels, uint32_t offset) { return (float)((uint8_t *)pixels)[offset]*SW_INV_255; } -static inline float sw_pixel_get_depth_D16(const void *pixels, uint32_t offset) +static inline float sw_pixel_read_depth_D16(const void *pixels, uint32_t offset) { return (float)((uint16_t *)pixels)[offset]/UINT16_MAX; } -static inline float sw_pixel_get_depth_D32(const void *pixels, uint32_t offset) +static inline float sw_pixel_read_depth_D32(const void *pixels, uint32_t offset) { return ((float *)pixels)[offset]; } -static inline float sw_pixel_get_depth(const void *pixels, uint32_t offset, sw_pixelformat_t format) -{ - switch (format) - { - case SW_PIXELFORMAT_DEPTH_D8: return sw_pixel_get_depth_D8(pixels, offset); - case SW_PIXELFORMAT_DEPTH_D16: return sw_pixel_get_depth_D16(pixels, offset); - case SW_PIXELFORMAT_DEPTH_D32: return sw_pixel_get_depth_D32(pixels, offset); - - case SW_PIXELFORMAT_UNKNOWN: - case SW_PIXELFORMAT_COLOR_GRAYSCALE: - case SW_PIXELFORMAT_COLOR_GRAYALPHA: - case SW_PIXELFORMAT_COLOR_R3G3B2: - case SW_PIXELFORMAT_COLOR_R5G6B5: - case SW_PIXELFORMAT_COLOR_R8G8B8: - case SW_PIXELFORMAT_COLOR_R5G5B5A1: - case SW_PIXELFORMAT_COLOR_R4G4B4A4: - case SW_PIXELFORMAT_COLOR_R8G8B8A8: - case SW_PIXELFORMAT_COLOR_R32: - case SW_PIXELFORMAT_COLOR_R32G32B32: - case SW_PIXELFORMAT_COLOR_R32G32B32A32: - case SW_PIXELFORMAT_COLOR_R16: - case SW_PIXELFORMAT_COLOR_R16G16B16: - case SW_PIXELFORMAT_COLOR_R16G16B16A16: - case SW_PIXELFORMAT_COUNT: break; - } - - return 0.0f; -} - -static inline void sw_pixel_set_depth_D8(void *pixels, float depth, uint32_t offset) +static inline void sw_pixel_write_depth_D8(void *pixels, float depth, uint32_t offset) { ((uint8_t *)pixels)[offset] = (uint8_t)(depth*UINT8_MAX); } -static inline void sw_pixel_set_depth_D16(void *pixels, float depth, uint32_t offset) +static inline void sw_pixel_write_depth_D16(void *pixels, float depth, uint32_t offset) { ((uint16_t *)pixels)[offset] = (uint16_t)(depth*UINT16_MAX); } -static inline void sw_pixel_set_depth_D32(void *pixels, float depth, uint32_t offset) +static inline void sw_pixel_write_depth_D32(void *pixels, float depth, uint32_t offset) { ((float *)pixels)[offset] = depth; } - -static inline void sw_pixel_set_depth(void *pixels, float depth, uint32_t offset, sw_pixelformat_t format) -{ - switch (format) - { - case SW_PIXELFORMAT_DEPTH_D8: sw_pixel_set_depth_D8(pixels, depth, offset); break; - case SW_PIXELFORMAT_DEPTH_D16: sw_pixel_set_depth_D16(pixels, depth, offset); break; - case SW_PIXELFORMAT_DEPTH_D32: sw_pixel_set_depth_D32(pixels, depth, offset); break; - - case SW_PIXELFORMAT_UNKNOWN: - case SW_PIXELFORMAT_COLOR_GRAYSCALE: - case SW_PIXELFORMAT_COLOR_GRAYALPHA: - case SW_PIXELFORMAT_COLOR_R3G3B2: - case SW_PIXELFORMAT_COLOR_R5G6B5: - case SW_PIXELFORMAT_COLOR_R8G8B8: - case SW_PIXELFORMAT_COLOR_R5G5B5A1: - case SW_PIXELFORMAT_COLOR_R4G4B4A4: - case SW_PIXELFORMAT_COLOR_R8G8B8A8: - case SW_PIXELFORMAT_COLOR_R32: - case SW_PIXELFORMAT_COLOR_R32G32B32: - case SW_PIXELFORMAT_COLOR_R32G32B32A32: - case SW_PIXELFORMAT_COLOR_R16: - case SW_PIXELFORMAT_COLOR_R16G16B16: - case SW_PIXELFORMAT_COLOR_R16G16B16A16: - case SW_PIXELFORMAT_COUNT: break; - } -} //------------------------------------------------------------------------------------------- // Texture functionality //------------------------------------------------------------------------------------------- static inline bool sw_texture_alloc(sw_texture_t *texture, const void *data, int w, int h, sw_pixelformat_t format) { + bool isDepth = sw_pixel_is_depth_format(format); int bpp = SW_PIXELFORMAT_SIZE[format]; int newSize = w*h*bpp; @@ -2395,10 +2362,39 @@ static inline bool sw_texture_alloc(sw_texture_t *texture, const void *data, int uint8_t *dst = texture->pixels; const uint8_t *src = data; - if (data) for (int i = 0; i < newSize; i++) dst[i] = src[i]; - else for (int i = 0; i < newSize; i++) dst[i] = 0; + sw_pixel_read_color8_f readColor8 = NULL; + sw_pixel_read_color_f readColor = NULL; + if (!isDepth) { + readColor8 = sw_pixel_get_read_color8_func(format); + readColor = sw_pixel_get_read_color_func(format); + } + sw_pixel_alpha_t pixelAlpha = SW_PIXELFORMAT_ALPHA[format]; + bool alphaFound = !data; // No data: assume transparency + + if (data && !isDepth) + { + for (int i = 0; i < newSize; i++) dst[i] = src[i]; + + if (pixelAlpha != SW_PIXEL_ALPHA_NONE) + { + for (int i = 0; i < newSize; i += bpp) + { + uint8_t color[4] = { 0 }; + readColor8(color, &src[i], 0); + if (color[3] < 255) { alphaFound = true; break; } + } + } + } + else + { + for (int i = 0; i < newSize; i++) dst[i] = 0; + } + + texture->readColor8 = readColor8; + texture->readColor = readColor; texture->format = format; + texture->alpha = alphaFound? pixelAlpha : SW_PIXEL_ALPHA_NONE; texture->width = w; texture->height = h; texture->wMinus1 = w - 1; @@ -2414,11 +2410,6 @@ static inline void sw_texture_free(sw_texture_t *texture) SW_FREE(texture->pixels); } -static inline void sw_texture_fetch(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, int x, int y) -{ - sw_pixel_get_color(color, tex->pixels, y*tex->width + x, tex->format); -} - static inline void sw_texture_sample_nearest(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, float u, float v) { u = (tex->sWrap == SW_REPEAT)? sw_fract(u) : sw_saturate(u); @@ -2427,7 +2418,7 @@ static inline void sw_texture_sample_nearest(float *SW_RESTRICT color, const sw_ int x = u*tex->width; int y = v*tex->height; - sw_texture_fetch(color, tex, x, y); + tex->readColor(color, tex->pixels, y*tex->width + x); } static inline void sw_texture_sample_linear(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, float u, float v) @@ -2472,10 +2463,10 @@ static inline void sw_texture_sample_linear(float *SW_RESTRICT color, const sw_t } float c00[4], c10[4], c01[4], c11[4]; - sw_texture_fetch(c00, tex, x0, y0); - sw_texture_fetch(c10, tex, x1, y0); - sw_texture_fetch(c01, tex, x0, y1); - sw_texture_fetch(c11, tex, x1, y1); + tex->readColor(c00, tex->pixels, y0*tex->width + x0); + tex->readColor(c10, tex->pixels, y0*tex->width + x1); + tex->readColor(c01, tex->pixels, y1*tex->width + x0); + tex->readColor(c11, tex->pixels, y1*tex->width + x1); for (int i = 0; i < 4; i++) { @@ -2543,7 +2534,7 @@ static inline void sw_framebuffer_fill_color(sw_texture_t *colorBuffer, const fl uint8_t *dst = (uint8_t *)colorBuffer->pixels; - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + if (RLSW.userState & SW_STATE_SCISSOR_TEST) { int xMin = sw_clamp_int(RLSW.scMin[0], 0, colorBuffer->width - 1); int xMax = sw_clamp_int(RLSW.scMax[0], 0, colorBuffer->width - 1); @@ -2582,7 +2573,7 @@ static inline void sw_framebuffer_fill_depth(sw_texture_t *depthBuffer, float de uint8_t *dst = (uint8_t *)depthBuffer->pixels; - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + if (RLSW.userState & SW_STATE_SCISSOR_TEST) { int xMin = sw_clamp_int(RLSW.scMin[0], 0, depthBuffer->width - 1); int xMax = sw_clamp_int(RLSW.scMax[0], 0, depthBuffer->width - 1); @@ -2655,8 +2646,9 @@ static inline void sw_framebuffer_output_fast(void *dst, const sw_texture_t *buf static inline void sw_framebuffer_output_copy(void *dst, const sw_texture_t *buffer, int x, int y, int w, int h, sw_pixelformat_t format) { - int dstPixelSize = SW_PIXELFORMAT_SIZE[format]; int stride = buffer->width; + int dstPixelSize = SW_PIXELFORMAT_SIZE[format]; + sw_pixel_write_color8_f setColor8 = sw_pixel_get_write_color8_func(format); const uint8_t *src = (uint8_t *)(buffer->pixels) + ((y + h - 1)*stride + x)*SW_FRAMEBUFFER_COLOR_SIZE; uint8_t *d = dst; @@ -2678,8 +2670,8 @@ static inline void sw_framebuffer_output_copy(void *dst, const sw_texture_t *buf } #endif - sw_pixel_set_color8(dline, color, 0, format); - line += SW_FRAMEBUFFER_COLOR_SIZE; + setColor8(dline, color, 0); + line += SW_FRAMEBUFFER_COLOR_SIZE; dline += dstPixelSize; } @@ -2695,12 +2687,12 @@ static inline void sw_framebuffer_output_blit(void *dst, const sw_texture_t *buf int fbWidth = buffer->width; int dstPixelSize = SW_PIXELFORMAT_SIZE[format]; + sw_pixel_write_color8_f setColor8 = sw_pixel_get_write_color8_func(format); uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; int ySrcLast = ySrc + hSrc - 1; - uint8_t *d = (uint8_t *)dst; for (int dy = 0; dy < hDst; dy++) @@ -2724,7 +2716,7 @@ static inline void sw_framebuffer_output_blit(void *dst, const sw_texture_t *buf } #endif - sw_pixel_set_color8(dline, color, 0, format); + setColor8(dline, color, 0); dline += dstPixelSize; } @@ -2735,86 +2727,138 @@ static inline void sw_framebuffer_output_blit(void *dst, const sw_texture_t *buf // Color blending functionality //------------------------------------------------------------------------------------------- -static inline void sw_factor_zero(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = factor[1] = factor[2] = factor[3] = 0.0f; +// Blend factor component macros: SW_BF_XXX(src, dst, component_index) +// Each expands to the scalar factor value for one RGBA channel +#define SW_BF_ZERO(s,d,i) 0.0f +#define SW_BF_ONE(s,d,i) 1.0f +#define SW_BF_SRC_COLOR(s,d,i) (s)[i] +#define SW_BF_ONE_MINUS_SRC_COLOR(s,d,i) (1.0f-(s)[i]) +#define SW_BF_SRC_ALPHA(s,d,i) (s)[3] +#define SW_BF_ONE_MINUS_SRC_ALPHA(s,d,i) (1.0f-(s)[3]) +#define SW_BF_DST_ALPHA(s,d,i) (d)[3] +#define SW_BF_ONE_MINUS_DST_ALPHA(s,d,i) (1.0f-(d)[3]) +#define SW_BF_DST_COLOR(s,d,i) (d)[i] +#define SW_BF_ONE_MINUS_DST_COLOR(s,d,i) (1.0f-(d)[i]) +#define SW_BF_SRC_ALPHA_SATURATE(s,d,i) (((i)<3)? 1.0f : (((s)[3]<1.0f)?(s)[3]:1.0f)) + +// Generates one specialized blend function for a (sfactor, dfactor) pair +#define DEFINE_BLEND_FUNC(sn, dn, SF, DF) \ +static void sw_blend_##sn##_##dn(float *SW_RESTRICT dst, const float *SW_RESTRICT src) \ +{ \ + dst[0] = SF(src,dst,0)*src[0] + DF(src,dst,0)*dst[0]; \ + dst[1] = SF(src,dst,1)*src[1] + DF(src,dst,1)*dst[1]; \ + dst[2] = SF(src,dst,2)*src[2] + DF(src,dst,2)*dst[2]; \ + dst[3] = SF(src,dst,3)*src[3] + DF(src,dst,3)*dst[3]; \ } -static inline void sw_factor_one(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) +// Master factor list: X(c_name, gl_enum, compact_index, SW_BF_macro) +// compact_index is used to index SW_BLEND_TABLE (GL enums are non contiguous) +#define FOREACH_FACTOR(X) \ + X(ZERO, SW_ZERO, 0, SW_BF_ZERO ) \ + X(ONE, SW_ONE, 1, SW_BF_ONE ) \ + X(SRC_COLOR, SW_SRC_COLOR, 2, SW_BF_SRC_COLOR ) \ + X(ONE_MINUS_SRC_COLOR, SW_ONE_MINUS_SRC_COLOR, 3, SW_BF_ONE_MINUS_SRC_COLOR) \ + X(SRC_ALPHA, SW_SRC_ALPHA, 4, SW_BF_SRC_ALPHA ) \ + X(ONE_MINUS_SRC_ALPHA, SW_ONE_MINUS_SRC_ALPHA, 5, SW_BF_ONE_MINUS_SRC_ALPHA) \ + X(DST_ALPHA, SW_DST_ALPHA, 6, SW_BF_DST_ALPHA ) \ + X(ONE_MINUS_DST_ALPHA, SW_ONE_MINUS_DST_ALPHA, 7, SW_BF_ONE_MINUS_DST_ALPHA) \ + X(DST_COLOR, SW_DST_COLOR, 8, SW_BF_DST_COLOR ) \ + X(ONE_MINUS_DST_COLOR, SW_ONE_MINUS_DST_COLOR, 9, SW_BF_ONE_MINUS_DST_COLOR) \ + X(SRC_ALPHA_SATURATE, SW_SRC_ALPHA_SATURATE, 10, SW_BF_SRC_ALPHA_SATURATE ) + +// Same list but forwards 3 extra args (A, B, C) to X +#define FOREACH_FACTOR_WITH(X, A, B, C) \ + X(ZERO, SW_ZERO, 0, SW_BF_ZERO, A,B,C) \ + X(ONE, SW_ONE, 1, SW_BF_ONE, A,B,C) \ + X(SRC_COLOR, SW_SRC_COLOR, 2, SW_BF_SRC_COLOR, A,B,C) \ + X(ONE_MINUS_SRC_COLOR, SW_ONE_MINUS_SRC_COLOR, 3, SW_BF_ONE_MINUS_SRC_COLOR,A,B,C) \ + X(SRC_ALPHA, SW_SRC_ALPHA, 4, SW_BF_SRC_ALPHA, A,B,C) \ + X(ONE_MINUS_SRC_ALPHA, SW_ONE_MINUS_SRC_ALPHA, 5, SW_BF_ONE_MINUS_SRC_ALPHA,A,B,C) \ + X(DST_ALPHA, SW_DST_ALPHA, 6, SW_BF_DST_ALPHA, A,B,C) \ + X(ONE_MINUS_DST_ALPHA, SW_ONE_MINUS_DST_ALPHA, 7, SW_BF_ONE_MINUS_DST_ALPHA,A,B,C) \ + X(DST_COLOR, SW_DST_COLOR, 8, SW_BF_DST_COLOR, A,B,C) \ + X(ONE_MINUS_DST_COLOR, SW_ONE_MINUS_DST_COLOR, 9, SW_BF_ONE_MINUS_DST_COLOR,A,B,C) \ + X(SRC_ALPHA_SATURATE, SW_SRC_ALPHA_SATURATE, 10, SW_BF_SRC_ALPHA_SATURATE, A,B,C) + +// Inner loop: receives dst factor + forwarded (sn, si, sf) from outer loop +#define GEN_COMBO(dn, de, di, df, sn, si, sf) DEFINE_BLEND_FUNC(sn, dn, sf, df) + +// Outer loop: for each src factor, iterate all dst factors +#define GEN_ROW(sn, se, si, sf) FOREACH_FACTOR_WITH(GEN_COMBO, sn, si, sf) + +// Generates all 121 sw_blend_SFACTOR_DFACTOR functions +FOREACH_FACTOR(GEN_ROW) + +#undef GEN_COMBO +#undef GEN_ROW + +// Inner loop: emits one table entry using compact indices (not GL enum values) +#define GEN_TABLE_ENTRY(dn, de, di, df, sn, si, sf) [si][di] = sw_blend_##sn##_##dn, + +// Outer loop: fills one row of the table for a given src factor +#define GEN_TABLE_ROW(sn, se, si, sf) FOREACH_FACTOR_WITH(GEN_TABLE_ENTRY, sn, si, sf) + +// 2D dispatch table indexed by compact src/dst factor indices +#define SW_BLEND_FACTOR_COUNT 11 +static const sw_blend_f SW_BLEND_TABLE[SW_BLEND_FACTOR_COUNT][SW_BLEND_FACTOR_COUNT] = { + FOREACH_FACTOR(GEN_TABLE_ROW) +}; + +#undef GEN_TABLE_ENTRY +#undef GEN_TABLE_ROW + +// Maps a GL blend factor enum to its compact table index +static inline int sw_blend_factor_index(SWfactor f) { - factor[0] = factor[1] = factor[2] = factor[3] = 1.0f; + switch (f) { + case SW_ZERO: return 0; + case SW_ONE: return 1; + case SW_SRC_COLOR: return 2; + case SW_ONE_MINUS_SRC_COLOR: return 3; + case SW_SRC_ALPHA: return 4; + case SW_ONE_MINUS_SRC_ALPHA: return 5; + case SW_DST_ALPHA: return 6; + case SW_ONE_MINUS_DST_ALPHA: return 7; + case SW_DST_COLOR: return 8; + case SW_ONE_MINUS_DST_COLOR: return 9; + case SW_SRC_ALPHA_SATURATE: return 10; + default: return -1; + } } -static inline void sw_factor_src_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) +static bool sw_blend_factor_needs_alpha(SWfactor f) { - factor[0] = src[0]; factor[1] = src[1]; factor[2] = src[2]; factor[3] = src[3]; + switch (f) { + case SW_SRC_ALPHA: + case SW_ONE_MINUS_SRC_ALPHA: + case SW_DST_ALPHA: + case SW_ONE_MINUS_DST_ALPHA: + case SW_SRC_ALPHA_SATURATE: return true; + default: break; + } + return false; } -static inline void sw_factor_one_minus_src_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) +static uint32_t sw_blend_compute_flags(SWfactor src, SWfactor dst) { - factor[0] = 1.0f - src[0]; factor[1] = 1.0f - src[1]; - factor[2] = 1.0f - src[2]; factor[3] = 1.0f - src[3]; -} + uint32_t flags = 0; -static inline void sw_factor_src_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = factor[1] = factor[2] = factor[3] = src[3]; -} + // Blend is a no-op: result = src*1 + dst*0 = src + if (src == SW_ONE && dst == SW_ZERO) flags |= SW_BLEND_FLAG_NOOP; -static inline void sw_factor_one_minus_src_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - float invAlpha = 1.0f - src[3]; - factor[0] = factor[1] = factor[2] = factor[3] = invAlpha; -} + // Factors that depend on the alpha channel + if (sw_blend_factor_needs_alpha(src) || sw_blend_factor_needs_alpha(dst)) flags |= SW_BLEND_FLAG_NEEDS_ALPHA; -static inline void sw_factor_dst_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = factor[1] = factor[2] = factor[3] = dst[3]; -} - -static inline void sw_factor_one_minus_dst_alpha(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - float invAlpha = 1.0f - dst[3]; - factor[0] = factor[1] = factor[2] = factor[3] = invAlpha; -} - -static inline void sw_factor_dst_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = dst[0]; factor[1] = dst[1]; factor[2] = dst[2]; factor[3] = dst[3]; -} - -static inline void sw_factor_one_minus_dst_color(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = 1.0f - dst[0]; factor[1] = 1.0f - dst[1]; - factor[2] = 1.0f - dst[2]; factor[3] = 1.0f - dst[3]; -} - -static inline void sw_factor_src_alpha_saturate(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst) -{ - factor[0] = factor[1] = factor[2] = 1.0f; - factor[3] = (src[3] < 1.0f)? src[3] : 1.0f; -} - -static inline void sw_blend_colors(float *SW_RESTRICT dst/*[4]*/, const float *SW_RESTRICT src/*[4]*/) -{ - float srcFactor[4], dstFactor[4]; - - RLSW.srcFactorFunc(srcFactor, src, dst); - RLSW.dstFactorFunc(dstFactor, src, dst); - - dst[0] = srcFactor[0]*src[0] + dstFactor[0]*dst[0]; - dst[1] = srcFactor[1]*src[1] + dstFactor[1]*dst[1]; - dst[2] = srcFactor[2]*src[2] + dstFactor[2]*dst[2]; - dst[3] = srcFactor[3]*src[3] + dstFactor[3]*dst[3]; + return flags; } //------------------------------------------------------------------------------------------- // Projection helper functions //------------------------------------------------------------------------------------------- -static inline void sw_project_ndc_to_screen(float screen[2], const float ndc[4]) +static inline void sw_project_ndc_to_screen(float ndc[4]) { - screen[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalf[0] + 0.5f; - screen[1] = RLSW.vpCenter[1] + ndc[1]*RLSW.vpHalf[1] + 0.5f; + ndc[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalf[0] + 0.5f; + ndc[1] = RLSW.vpCenter[1] + ndc[1]*RLSW.vpHalf[1] + 0.5f; } //------------------------------------------------------------------------------------------- @@ -2827,17 +2871,17 @@ static int sw_clip_##name( int n) \ { \ const sw_vertex_t *prev = &input[n - 1]; \ - int prevInside = FUNC_IS_INSIDE(prev->homogeneous); \ + int prevInside = FUNC_IS_INSIDE(prev->coord); \ int outputCount = 0; \ \ for (int i = 0; i < n; i++) { \ const sw_vertex_t *curr = &input[i]; \ - int currInside = FUNC_IS_INSIDE(curr->homogeneous); \ + int currInside = FUNC_IS_INSIDE(curr->coord); \ \ /* If transition between interior/exterior, calculate intersection point */ \ if (prevInside != currInside) { \ - float t = FUNC_COMPUTE_T(prev->homogeneous, curr->homogeneous); \ - sw_lerp_vertex_PTCH(&output[outputCount++], prev, curr, t); \ + float t = FUNC_COMPUTE_T(prev->coord, curr->coord); \ + sw_lerp_vertex_PCTH(&output[outputCount++], prev, curr, t); \ } \ \ /* If current vertex inside, add it */ \ @@ -2924,7 +2968,7 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES] CLIP_AGAINST_PLANE(sw_clip_z_pos); CLIP_AGAINST_PLANE(sw_clip_z_neg); - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + if (RLSW.userState & SW_STATE_SCISSOR_TEST) { CLIP_AGAINST_PLANE(sw_clip_scissor_x_min); CLIP_AGAINST_PLANE(sw_clip_scissor_x_max); @@ -3025,7 +3069,7 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES] // Dispatch table (auto-generated from SW_RASTER_VARIANTS) #define SW_TABLE_ENTRY(NAME, FLAGS) [FLAGS] = sw_raster_triangle_##NAME, - static const sw_raster_triangle_f SW_RASTER_TRIANGLE_FUNCS[] = { + static const sw_raster_triangle_f SW_RASTER_TRIANGLE_TABLE[] = { SW_RASTER_VARIANTS(SW_TABLE_ENTRY) }; #undef SW_TABLE_ENTRY @@ -3124,7 +3168,7 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES] // Dispatch table (auto-generated from SW_RASTER_VARIANTS) #define SW_TABLE_ENTRY(NAME, FLAGS) [FLAGS] = sw_raster_quad_##NAME, - static const sw_raster_quad_f SW_RASTER_QUAD_FUNCS[] = { + static const sw_raster_quad_f SW_RASTER_QUAD_TABLE[] = { SW_RASTER_VARIANTS(SW_TABLE_ENTRY) }; #undef SW_TABLE_ENTRY @@ -3189,8 +3233,8 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES] // Dispatch table (auto-generated from SW_RASTER_VARIANTS) #define SW_TABLE_ENTRY0(NAME, FLAGS) [FLAGS] = sw_raster_line_##NAME, #define SW_TABLE_ENTRY1(NAME, FLAGS) [FLAGS] = sw_raster_line_thick_##NAME, - static const sw_raster_line_f SW_RASTER_LINE_FUNCS[] = { SW_RASTER_VARIANTS(SW_TABLE_ENTRY0) }; - static const sw_raster_line_f SW_RASTER_LINE_THICK_FUNCS[] = { SW_RASTER_VARIANTS(SW_TABLE_ENTRY1) }; + static const sw_raster_line_f SW_RASTER_LINE_TABLE[] = { SW_RASTER_VARIANTS(SW_TABLE_ENTRY0) }; + static const sw_raster_line_f SW_RASTER_LINE_THICK_TABLE[] = { SW_RASTER_VARIANTS(SW_TABLE_ENTRY1) }; #undef SW_TABLE_ENTRY0 #undef SW_TABLE_ENTRY1 @@ -3252,7 +3296,7 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES] // Dispatch table (auto-generated from SW_RASTER_VARIANTS) #define SW_TABLE_ENTRY(NAME, FLAGS) [FLAGS] = sw_raster_point_##NAME, - static const sw_raster_point_f SW_RASTER_POINT_FUNCS[] = { + static const sw_raster_point_f SW_RASTER_POINT_TABLE[] = { SW_RASTER_VARIANTS(SW_TABLE_ENTRY) }; #undef SW_TABLE_ENTRY @@ -3269,21 +3313,21 @@ static inline bool sw_triangle_face_culling(void) { // NOTE: Face culling is done before clipping to avoid unnecessary computations // To handle triangles crossing the w=0 plane correctly, - // the winding order test is performeed in homogeneous coordinates directly, + // the winding order test is performeed in clip space directly, // before the perspective division (division by w) // This test determines the orientation of the triangle in the (x,y,w) plane, // which corresponds to the projected 2D winding order sign, // even with negative w values - // Preload homogeneous coordinates into local variables - const float *h0 = RLSW.vertexBuffer[0].homogeneous; - const float *h1 = RLSW.vertexBuffer[1].homogeneous; - const float *h2 = RLSW.vertexBuffer[2].homogeneous; + // Preload clip coordinates into local variables + const float *h0 = RLSW.primitive.buffer[0].coord; + const float *h1 = RLSW.primitive.buffer[1].coord; + const float *h2 = RLSW.primitive.buffer[2].coord; // Compute a value proportional to the signed area in the projected 2D plane, - // calculated directly using homogeneous coordinates BEFORE division by w + // calculated directly using clip coordinates BEFORE division by w // This is the determinant of the matrix formed by the (x, y, w) components - // of the vertices, which correctly captures the winding order in homogeneous + // of the vertices, which correctly captures the winding order in clip // space and its relationship to the projected 2D winding order, even with // negative w values // The determinant formula used here is: @@ -3313,8 +3357,8 @@ static inline bool sw_triangle_face_culling(void) static void sw_triangle_clip_and_project(void) { - sw_vertex_t *polygon = RLSW.vertexBuffer; - int *vertexCounter = &RLSW.vertexCounter; + sw_vertex_t *polygon = RLSW.primitive.buffer; + int *vertexCounter = &RLSW.primitive.vertexCount; if (sw_polygon_clip(polygon, vertexCounter)) { @@ -3325,13 +3369,13 @@ static void sw_triangle_clip_and_project(void) // Calculation of the reciprocal of W for normalization // as well as perspective-correct attributes - const float wRcp = 1.0f/v->homogeneous[3]; - v->homogeneous[3] = wRcp; + const float wRcp = 1.0f/v->coord[3]; + v->coord[3] = wRcp; // Division of XYZ coordinates by weight - v->homogeneous[0] *= wRcp; - v->homogeneous[1] *= wRcp; - v->homogeneous[2] *= wRcp; + v->coord[0] *= wRcp; + v->coord[1] *= wRcp; + v->coord[2] *= wRcp; // Division of texture coordinates (perspective-correct) v->texcoord[0] *= wRcp; @@ -3344,29 +3388,29 @@ static void sw_triangle_clip_and_project(void) v->color[3] *= wRcp; // Transformation to screen space - sw_project_ndc_to_screen(v->screen, v->homogeneous); + sw_project_ndc_to_screen(v->coord); } } } static void sw_triangle_render(uint32_t state) { - if (RLSW.stateFlags & SW_STATE_CULL_FACE) + if (RLSW.userState & SW_STATE_CULL_FACE) { if (!sw_triangle_face_culling()) return; } sw_triangle_clip_and_project(); - if (RLSW.vertexCounter < 3) return; + if (RLSW.primitive.vertexCount < 3) return; state &= SW_RASTER_TRIANGLE_STATE_MASK; - for (int i = 0; i < RLSW.vertexCounter - 2; i++) + for (int i = 0; i < RLSW.primitive.vertexCount - 2; i++) { - SW_RASTER_TRIANGLE_FUNCS[state]( - &RLSW.vertexBuffer[0], - &RLSW.vertexBuffer[i + 1], - &RLSW.vertexBuffer[i + 2] + SW_RASTER_TRIANGLE_TABLE[state]( + &RLSW.primitive.buffer[0], + &RLSW.primitive.buffer[i + 1], + &RLSW.primitive.buffer[i + 2] ); } } @@ -3378,27 +3422,27 @@ static inline bool sw_quad_face_culling(void) { // NOTE: Face culling is done before clipping to avoid unnecessary computations // To handle quads crossing the w=0 plane correctly, - // the winding order test is performed in homogeneous coordinates directly, + // the winding order test is performed in clip space directly, // before the perspective division (division by w) // For a convex quad with vertices P0, P1, P2, P3 in sequential order, // the winding order of the quad is the same as the winding order - // of the triangle P0 P1 P2. The homogeneous triangle is used on + // of the triangle P0 P1 P2. The triangle in clip space is used on // winding test on this first triangle - // Preload homogeneous coordinates into local variables - const float *h0 = RLSW.vertexBuffer[0].homogeneous; - const float *h1 = RLSW.vertexBuffer[1].homogeneous; - const float *h2 = RLSW.vertexBuffer[2].homogeneous; + // Preload clip coordinates into local variables + const float *h0 = RLSW.primitive.buffer[0].coord; + const float *h1 = RLSW.primitive.buffer[1].coord; + const float *h2 = RLSW.primitive.buffer[2].coord; // NOTE: h3 is not needed for this test - // const float *h3 = RLSW.vertexBuffer[3].homogeneous; + // const float *h3 = RLSW.primitive.buffer[3].coord; // Compute a value proportional to the signed area of the triangle P0 P1 P2 - // in the projected 2D plane, calculated directly using homogeneous coordinates + // in the projected 2D plane, calculated directly using clip coordinates // BEFORE division by w // This is the determinant of the matrix formed by the (x, y, w) components // of the vertices P0, P1, and P2. Its sign correctly indicates the winding order - // in homogeneous space and its relationship to the projected 2D winding order, + // in clip space and its relationship to the projected 2D winding order, // even with negative w values // The determinant formula used here is: // h0.x*(h1.y*h2.w - h2.y*h1.w) + @@ -3428,8 +3472,8 @@ static inline bool sw_quad_face_culling(void) static void sw_quad_clip_and_project(void) { - sw_vertex_t *polygon = RLSW.vertexBuffer; - int *vertexCounter = &RLSW.vertexCounter; + sw_vertex_t *polygon = RLSW.primitive.buffer; + int *vertexCounter = &RLSW.primitive.vertexCount; if (sw_polygon_clip(polygon, vertexCounter)) { @@ -3440,13 +3484,13 @@ static void sw_quad_clip_and_project(void) // Calculation of the reciprocal of W for normalization // as well as perspective-correct attributes - const float wRcp = 1.0f/v->homogeneous[3]; - v->homogeneous[3] = wRcp; + const float wRcp = 1.0f/v->coord[3]; + v->coord[3] = wRcp; // Division of XYZ coordinates by weight - v->homogeneous[0] *= wRcp; - v->homogeneous[1] *= wRcp; - v->homogeneous[2] *= wRcp; + v->coord[0] *= wRcp; + v->coord[1] *= wRcp; + v->coord[2] *= wRcp; // Division of texture coordinates (perspective-correct) v->texcoord[0] *= wRcp; @@ -3459,7 +3503,7 @@ static void sw_quad_clip_and_project(void) v->color[3] *= wRcp; // Transformation to screen space - sw_project_ndc_to_screen(v->screen, v->homogeneous); + sw_project_ndc_to_screen(v->coord); } } } @@ -3471,17 +3515,17 @@ static bool sw_quad_is_axis_aligned(void) // so it's required for all vertices to have homogeneous w = 1.0 for (int i = 0; i < 4; i++) { - if (RLSW.vertexBuffer[i].homogeneous[3] != 1.0f) return false; + if (RLSW.primitive.buffer[i].coord[3] != 1.0f) return false; } // Epsilon tolerance in screen space (pixels) const float epsilon = 0.5f; // Fetch screen-space positions for the four quad vertices - const float *p0 = RLSW.vertexBuffer[0].screen; - const float *p1 = RLSW.vertexBuffer[1].screen; - const float *p2 = RLSW.vertexBuffer[2].screen; - const float *p3 = RLSW.vertexBuffer[3].screen; + const float *p0 = RLSW.primitive.buffer[0].coord; + const float *p1 = RLSW.primitive.buffer[1].coord; + const float *p2 = RLSW.primitive.buffer[2].coord; + const float *p3 = RLSW.primitive.buffer[3].coord; // Compute edge vectors between consecutive vertices // These define the four sides of the quad in screen space @@ -3502,33 +3546,33 @@ static bool sw_quad_is_axis_aligned(void) static void sw_quad_render(uint32_t state) { - if (RLSW.stateFlags & SW_STATE_CULL_FACE) + if (RLSW.userState & SW_STATE_CULL_FACE) { if (!sw_quad_face_culling()) return; } sw_quad_clip_and_project(); - if (RLSW.vertexCounter < 3) return; + if (RLSW.primitive.vertexCount < 3) return; state &= SW_RASTER_QUAD_STATE_MASK; - if ((RLSW.vertexCounter == 4) && sw_quad_is_axis_aligned()) + if ((RLSW.primitive.vertexCount == 4) && sw_quad_is_axis_aligned()) { - SW_RASTER_QUAD_FUNCS[state]( - &RLSW.vertexBuffer[0], - &RLSW.vertexBuffer[1], - &RLSW.vertexBuffer[2], - &RLSW.vertexBuffer[3] + SW_RASTER_QUAD_TABLE[state]( + &RLSW.primitive.buffer[0], + &RLSW.primitive.buffer[1], + &RLSW.primitive.buffer[2], + &RLSW.primitive.buffer[3] ); } else { - for (int i = 0; i < RLSW.vertexCounter - 2; i++) + for (int i = 0; i < RLSW.primitive.vertexCount - 2; i++) { - SW_RASTER_TRIANGLE_FUNCS[state]( - &RLSW.vertexBuffer[0], - &RLSW.vertexBuffer[i + 1], - &RLSW.vertexBuffer[i + 2] + SW_RASTER_TRIANGLE_TABLE[state]( + &RLSW.primitive.buffer[0], + &RLSW.primitive.buffer[i + 1], + &RLSW.primitive.buffer[i + 2] ); } } @@ -3570,25 +3614,25 @@ static bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1) for (int i = 0; i < 4; i++) { - dH[i] = v1->homogeneous[i] - v0->homogeneous[i]; + dH[i] = v1->coord[i] - v0->coord[i]; dC[i] = v1->color[i] - v0->color[i]; } // Clipping Liang-Barsky - if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[0], -dH[3] + dH[0], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[0], -dH[3] - dH[0], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[1], -dH[3] + dH[1], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[1], -dH[3] - dH[1], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[2], -dH[3] + dH[2], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[2], -dH[3] - dH[2], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->coord[3] - v0->coord[0], -dH[3] + dH[0], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->coord[3] + v0->coord[0], -dH[3] - dH[0], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->coord[3] - v0->coord[1], -dH[3] + dH[1], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->coord[3] + v0->coord[1], -dH[3] - dH[1], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->coord[3] - v0->coord[2], -dH[3] + dH[2], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->coord[3] + v0->coord[2], -dH[3] - dH[2], &t0, &t1)) return false; // Clipping Scissor - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + if (RLSW.userState & SW_STATE_SCISSOR_TEST) { - if (!sw_line_clip_coord(v0->homogeneous[0] - RLSW.scClipMin[0]*v0->homogeneous[3], RLSW.scClipMin[0]*dH[3] - dH[0], &t0, &t1)) return false; - if (!sw_line_clip_coord(RLSW.scClipMax[0]*v0->homogeneous[3] - v0->homogeneous[0], dH[0] - RLSW.scClipMax[0]*dH[3], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->homogeneous[1] - RLSW.scClipMin[1]*v0->homogeneous[3], RLSW.scClipMin[1]*dH[3] - dH[1], &t0, &t1)) return false; - if (!sw_line_clip_coord(RLSW.scClipMax[1]*v0->homogeneous[3] - v0->homogeneous[1], dH[1] - RLSW.scClipMax[1]*dH[3], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->coord[0] - RLSW.scClipMin[0]*v0->coord[3], RLSW.scClipMin[0]*dH[3] - dH[0], &t0, &t1)) return false; + if (!sw_line_clip_coord(RLSW.scClipMax[0]*v0->coord[3] - v0->coord[0], dH[0] - RLSW.scClipMax[0]*dH[3], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->coord[1] - RLSW.scClipMin[1]*v0->coord[3], RLSW.scClipMin[1]*dH[3] - dH[1], &t0, &t1)) return false; + if (!sw_line_clip_coord(RLSW.scClipMax[1]*v0->coord[3] - v0->coord[1], dH[1] - RLSW.scClipMax[1]*dH[3], &t0, &t1)) return false; } // Interpolation of new coordinates @@ -3596,7 +3640,7 @@ static bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1) { for (int i = 0; i < 4; i++) { - v1->homogeneous[i] = v0->homogeneous[i] + t1*dH[i]; + v1->coord[i] = v0->coord[i] + t1*dH[i]; v1->color[i] = v0->color[i] + t1*dC[i]; } } @@ -3605,7 +3649,7 @@ static bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1) { for (int i = 0; i < 4; i++) { - v0->homogeneous[i] += t0*dH[i]; + v0->coord[i] += t0*dH[i]; v0->color[i] += t0*dC[i]; } } @@ -3617,25 +3661,25 @@ static bool sw_line_clip_and_project(sw_vertex_t *v0, sw_vertex_t *v1) { if (!sw_line_clip(v0, v1)) return false; - // Convert homogeneous coordinates to NDC - v0->homogeneous[3] = 1.0f/v0->homogeneous[3]; - v1->homogeneous[3] = 1.0f/v1->homogeneous[3]; + // Convert clip coordinates to NDC + v0->coord[3] = 1.0f/v0->coord[3]; + v1->coord[3] = 1.0f/v1->coord[3]; for (int i = 0; i < 3; i++) { - v0->homogeneous[i] *= v0->homogeneous[3]; - v1->homogeneous[i] *= v1->homogeneous[3]; + v0->coord[i] *= v0->coord[3]; + v1->coord[i] *= v1->coord[3]; } // Convert NDC coordinates to screen space - sw_project_ndc_to_screen(v0->screen, v0->homogeneous); - sw_project_ndc_to_screen(v1->screen, v1->homogeneous); + sw_project_ndc_to_screen(v0->coord); + sw_project_ndc_to_screen(v1->coord); // NDC +1.0 projects to exactly (width + 0.5f), which truncates out of bounds // The clamp is at most 0.5px on a boundary endpoint, it's visually imperceptible - v0->screen[0] = sw_clamp(v0->screen[0], 0.0f, (float)(RLSW.colorBuffer->width - 1) + 0.5f); - v0->screen[1] = sw_clamp(v0->screen[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f); - v1->screen[0] = sw_clamp(v1->screen[0], 0.0f, (float)(RLSW.colorBuffer->width - 1) + 0.5f); - v1->screen[1] = sw_clamp(v1->screen[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f); + v0->coord[0] = sw_clamp(v0->coord[0], 0.0f, (float)(RLSW.colorBuffer->width - 1) + 0.5f); + v0->coord[1] = sw_clamp(v0->coord[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f); + v1->coord[0] = sw_clamp(v1->coord[0], 0.0f, (float)(RLSW.colorBuffer->width - 1) + 0.5f); + v1->coord[1] = sw_clamp(v1->coord[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f); return true; } @@ -3648,11 +3692,11 @@ static void sw_line_render(uint32_t state, sw_vertex_t *vertices) if (RLSW.lineWidth >= 2.0f) { - SW_RASTER_LINE_THICK_FUNCS[state](&vertices[0], &vertices[1]); + SW_RASTER_LINE_THICK_TABLE[state](&vertices[0], &vertices[1]); } else { - SW_RASTER_LINE_FUNCS[state](&vertices[0], &vertices[1]); + SW_RASTER_LINE_TABLE[state](&vertices[0], &vertices[1]); } } //------------------------------------------------------------------------------------------- @@ -3661,25 +3705,25 @@ static void sw_line_render(uint32_t state, sw_vertex_t *vertices) //------------------------------------------------------------------------------------------- static bool sw_point_clip_and_project(sw_vertex_t *v) { - if (v->homogeneous[3] != 1.0f) + if (v->coord[3] != 1.0f) { for (int_fast8_t i = 0; i < 3; i++) { - if ((v->homogeneous[i] < -v->homogeneous[3]) || (v->homogeneous[i] > v->homogeneous[3])) return false; + if ((v->coord[i] < -v->coord[3]) || (v->coord[i] > v->coord[3])) return false; } - v->homogeneous[3] = 1.0f/v->homogeneous[3]; - v->homogeneous[0] *= v->homogeneous[3]; - v->homogeneous[1] *= v->homogeneous[3]; - v->homogeneous[2] *= v->homogeneous[3]; + v->coord[3] = 1.0f/v->coord[3]; + v->coord[0] *= v->coord[3]; + v->coord[1] *= v->coord[3]; + v->coord[2] *= v->coord[3]; } - sw_project_ndc_to_screen(v->screen, v->homogeneous); + sw_project_ndc_to_screen(v->coord); int min[2] = { 0, 0 }; int max[2] = { RLSW.colorBuffer->width, RLSW.colorBuffer->height }; - if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST) + if (RLSW.userState & SW_STATE_SCISSOR_TEST) { min[0] = sw_clamp_int(RLSW.scMin[0], 0, RLSW.colorBuffer->width); min[1] = sw_clamp_int(RLSW.scMin[1], 0, RLSW.colorBuffer->height); @@ -3687,8 +3731,8 @@ static bool sw_point_clip_and_project(sw_vertex_t *v) max[1] = sw_clamp_int(RLSW.scMax[1], 0, RLSW.colorBuffer->height); } - bool insideX = (v->screen[0] - RLSW.pointRadius < max[0]) && (v->screen[0] + RLSW.pointRadius > min[0]); - bool insideY = (v->screen[1] - RLSW.pointRadius < max[1]) && (v->screen[1] + RLSW.pointRadius > min[1]); + bool insideX = (v->coord[0] - RLSW.pointRadius < max[0]) && (v->coord[0] + RLSW.pointRadius > min[0]); + bool insideY = (v->coord[1] - RLSW.pointRadius < max[1]) && (v->coord[1] + RLSW.pointRadius > min[1]); return (insideX && insideY); } @@ -3697,7 +3741,7 @@ static void sw_point_render(uint32_t state, sw_vertex_t *v) { if (!sw_point_clip_and_project(v)) return; state &= SW_RASTER_POINT_STATE_MASK; - SW_RASTER_POINT_FUNCS[state](v); + SW_RASTER_POINT_TABLE[state](v); } //------------------------------------------------------------------------------------------- @@ -3705,13 +3749,13 @@ static void sw_point_render(uint32_t state, sw_vertex_t *v) //------------------------------------------------------------------------------------------- static inline void sw_poly_point_render(uint32_t state) { - for (int i = 0; i < RLSW.vertexCounter; i++) sw_point_render(state, &RLSW.vertexBuffer[i]); + for (int i = 0; i < RLSW.primitive.vertexCount; i++) sw_point_render(state, &RLSW.primitive.buffer[i]); } static inline void sw_poly_line_render(uint32_t state) { - const sw_vertex_t *vertices = RLSW.vertexBuffer; - int cm1 = RLSW.vertexCounter - 1; + const sw_vertex_t *vertices = RLSW.primitive.buffer; + int cm1 = RLSW.primitive.vertexCount - 1; for (int i = 0; i < cm1; i++) { @@ -3727,8 +3771,8 @@ static inline void sw_poly_fill_render(uint32_t state) { switch (RLSW.drawMode) { - case SW_POINTS: sw_point_render(state, &RLSW.vertexBuffer[0]); break; - case SW_LINES: sw_line_render(state, RLSW.vertexBuffer); break; + case SW_POINTS: sw_point_render(state, &RLSW.primitive.buffer[0]); break; + case SW_LINES: sw_line_render(state, RLSW.primitive.buffer); break; case SW_TRIANGLES: sw_triangle_render(state); break; case SW_QUADS: sw_quad_render(state); break; default: break; @@ -3738,7 +3782,57 @@ static inline void sw_poly_fill_render(uint32_t state) // Immediate rendering logic //------------------------------------------------------------------------------------------- -static void sw_immediate_push_vertex(const float position[4], const float color[4], const float texcoord[2]) +static void sw_immediate_begin(SWdraw mode) +{ + // NOTE: Any checks to ensure command recording can start + // must be performed before calling this function. + + // Recalculate the MVP if this is needed + if (RLSW.isDirtyMVP) + { + sw_matrix_mul_rst(RLSW.matMVP, + RLSW.stackModelview[RLSW.stackModelviewCounter - 1], + RLSW.stackProjection[RLSW.stackProjectionCounter - 1]); + + RLSW.isDirtyMVP = false; + } + + // Disable pipeline states that are incompatible with the global state + uint32_t state = RLSW.userState; + if (!sw_is_texture_complete(RLSW.depthBuffer)) state &= ~SW_STATE_DEPTH_TEST; + if (!sw_is_texture_complete(RLSW.boundTexture)) state &= ~SW_STATE_TEXTURE_2D; + else if (sw_pixel_is_depth_format(RLSW.boundTexture->format)) state &= ~SW_STATE_TEXTURE_2D; + + // Initialize required values + RLSW.primitive.hasColorAlpha = false; + RLSW.primitive.vertexCount = 0; + RLSW.rasterState = state; + RLSW.drawMode = mode; +} + +static bool sw_immediate_is_active(void) +{ + return (RLSW.drawMode != SW_DRAW_INVALID); +} + +static void sw_immediate_set_color(const float color[4]) +{ + RLSW.primitive.color[0] = color[0]; + RLSW.primitive.color[1] = color[1]; + RLSW.primitive.color[2] = color[2]; + RLSW.primitive.color[3] = color[3]; + + RLSW.primitive.hasColorAlpha |= (color[3] < 1.0f); +} + +static void sw_immediate_set_texcoord(const float texcoord[2]) +{ + const float *m = RLSW.stackTexture[RLSW.stackTextureCounter - 1]; + RLSW.primitive.texcoord[0] = m[0]*texcoord[0] + m[4]*texcoord[1] + m[12]; + RLSW.primitive.texcoord[1] = m[1]*texcoord[0] + m[5]*texcoord[1] + m[13]; +} + +static void sw_immediate_push_vertex(const float position[4]) { // Check if the draw mode is valid if (!sw_is_draw_mode_valid(RLSW.drawMode)) @@ -3748,29 +3842,32 @@ static void sw_immediate_push_vertex(const float position[4], const float color[ } // Copy the attributes in the current vertex - sw_vertex_t *vertex = &RLSW.vertexBuffer[RLSW.vertexCounter++]; - for (int i = 0; i < 4; i++) - { - vertex->position[i] = position[i]; - if (i < 2) vertex->texcoord[i] = texcoord[i]; - vertex->color[i] = color[i]; - } + sw_vertex_t *vertex = &RLSW.primitive.buffer[RLSW.primitive.vertexCount++]; + for (int i = 0; i < 4; i++) vertex->position[i] = position[i]; + for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.primitive.color[i]; + for (int i = 0; i < 2; i++) vertex->texcoord[i] = RLSW.primitive.texcoord[i]; - // Calculate homogeneous coordinates + // Calculate clip coordinates const float *m = RLSW.matMVP, *v = vertex->position; - vertex->homogeneous[0] = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3]; - vertex->homogeneous[1] = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3]; - vertex->homogeneous[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3]; - vertex->homogeneous[3] = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3]; + vertex->coord[0] = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3]; + vertex->coord[1] = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3]; + vertex->coord[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3]; + vertex->coord[3] = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3]; // Immediate rendering of the primitive if the required number is reached - if (RLSW.vertexCounter == SW_PRIMITIVE_VERTEX_COUNT[RLSW.drawMode]) + if (RLSW.primitive.vertexCount == SW_PRIMITIVE_VERTEX_COUNT[RLSW.drawMode]) { - // Restricts the pipeline state to the minimum required - uint32_t state = RLSW.stateFlags; - if (!sw_is_texture_complete(RLSW.depthBuffer)) state &= ~SW_STATE_DEPTH_TEST; - if (!sw_is_texture_complete(RLSW.boundTexture)) state &= ~SW_STATE_TEXTURE_2D; - if ((RLSW.srcFactor == SW_ONE) && (RLSW.dstFactor == SW_ZERO)) state &= ~SW_STATE_BLEND; + uint32_t state = RLSW.rasterState; + + // Reduces blend mode costs when it's possible + if (state & SW_STATE_BLEND) + { + if (RLSW.blendFlags & SW_BLEND_FLAG_NOOP) state &= ~SW_STATE_BLEND; + else if ((RLSW.blendFlags & SW_BLEND_FLAG_NEEDS_ALPHA) && (!RLSW.primitive.hasColorAlpha)) + { + if (!(state & SW_STATE_TEXTURE_2D) || (RLSW.boundTexture->alpha == SW_PIXEL_ALPHA_NONE)) state &= ~SW_STATE_BLEND; + } + } switch (RLSW.polyMode) { @@ -3780,10 +3877,15 @@ static void sw_immediate_push_vertex(const float position[4], const float color[ default: break; } - RLSW.vertexCounter = 0; + RLSW.primitive.hasColorAlpha = false; + RLSW.primitive.vertexCount = 0; } } +static void sw_immediate_end(void) +{ + RLSW.drawMode = SW_DRAW_INVALID; +} //------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------- @@ -3834,24 +3936,26 @@ bool swInit(int w, int h) RLSW.stackTextureCounter = 1; RLSW.isDirtyMVP = false; - RLSW.current.texcoord[0] = 0.0f; - RLSW.current.texcoord[1] = 0.0f; + RLSW.primitive.texcoord[0] = 0.0f; + RLSW.primitive.texcoord[1] = 0.0f; - RLSW.current.color[0] = 1.0f; - RLSW.current.color[1] = 1.0f; - RLSW.current.color[2] = 1.0f; - RLSW.current.color[3] = 1.0f; + RLSW.primitive.color[0] = 1.0f; + RLSW.primitive.color[1] = 1.0f; + RLSW.primitive.color[2] = 1.0f; + RLSW.primitive.color[3] = 1.0f; RLSW.srcFactor = SW_SRC_ALPHA; RLSW.dstFactor = SW_ONE_MINUS_SRC_ALPHA; - - RLSW.srcFactorFunc = sw_factor_src_alpha; - RLSW.dstFactorFunc = sw_factor_one_minus_src_alpha; + RLSW.blendFunc = sw_blend_SRC_ALPHA_ONE_MINUS_SRC_ALPHA; RLSW.drawMode = SW_DRAW_INVALID; RLSW.polyMode = SW_FILL; RLSW.cullFace = SW_BACK; +#if SW_USE_COLOR_LUT + for (int i = 0; i < 256; i++) SW_LUT_UINT8_TO_FLOAT[i] = (float)i*SW_INV_255; +#endif + SW_LOG("INFO: RLSW: Software renderer initialized successfully\n"); #if defined(SW_HAS_FMA_AVX) && defined(SW_HAS_FMA_AVX2) SW_LOG("INFO: RLSW: Using SIMD instructions: FMA AVX\n"); @@ -3964,11 +4068,11 @@ void swEnable(SWstate state) { switch (state) { - case SW_SCISSOR_TEST: RLSW.stateFlags |= SW_STATE_SCISSOR_TEST; break; - case SW_TEXTURE_2D: RLSW.stateFlags |= SW_STATE_TEXTURE_2D; break; - case SW_DEPTH_TEST: RLSW.stateFlags |= SW_STATE_DEPTH_TEST; break; - case SW_CULL_FACE: RLSW.stateFlags |= SW_STATE_CULL_FACE; break; - case SW_BLEND: RLSW.stateFlags |= SW_STATE_BLEND; break; + case SW_SCISSOR_TEST: RLSW.userState |= SW_STATE_SCISSOR_TEST; break; + case SW_TEXTURE_2D: RLSW.userState |= SW_STATE_TEXTURE_2D; break; + case SW_DEPTH_TEST: RLSW.userState |= SW_STATE_DEPTH_TEST; break; + case SW_CULL_FACE: RLSW.userState |= SW_STATE_CULL_FACE; break; + case SW_BLEND: RLSW.userState |= SW_STATE_BLEND; break; default: RLSW.errCode = SW_INVALID_ENUM; break; } } @@ -3977,11 +4081,11 @@ void swDisable(SWstate state) { switch (state) { - case SW_SCISSOR_TEST: RLSW.stateFlags &= ~SW_STATE_SCISSOR_TEST; break; - case SW_TEXTURE_2D: RLSW.stateFlags &= ~SW_STATE_TEXTURE_2D; break; - case SW_DEPTH_TEST: RLSW.stateFlags &= ~SW_STATE_DEPTH_TEST; break; - case SW_CULL_FACE: RLSW.stateFlags &= ~SW_STATE_CULL_FACE; break; - case SW_BLEND: RLSW.stateFlags &= ~SW_STATE_BLEND; break; + case SW_SCISSOR_TEST: RLSW.userState &= ~SW_STATE_SCISSOR_TEST; break; + case SW_TEXTURE_2D: RLSW.userState &= ~SW_STATE_TEXTURE_2D; break; + case SW_DEPTH_TEST: RLSW.userState &= ~SW_STATE_DEPTH_TEST; break; + case SW_CULL_FACE: RLSW.userState &= ~SW_STATE_CULL_FACE; break; + case SW_BLEND: RLSW.userState &= ~SW_STATE_BLEND; break; default: RLSW.errCode = SW_INVALID_ENUM; break; } } @@ -4015,15 +4119,15 @@ void swGetFloatv(SWget name, float *v) } break; case SW_CURRENT_COLOR: { - v[0] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[0]; - v[1] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[1]; - v[2] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[2]; - v[3] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].color[3]; + v[0] = RLSW.primitive.buffer[RLSW.primitive.vertexCount - 1].color[0]; + v[1] = RLSW.primitive.buffer[RLSW.primitive.vertexCount - 1].color[1]; + v[2] = RLSW.primitive.buffer[RLSW.primitive.vertexCount - 1].color[2]; + v[3] = RLSW.primitive.buffer[RLSW.primitive.vertexCount - 1].color[3]; } break; case SW_CURRENT_TEXTURE_COORDS: { - v[0] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].texcoord[0]; - v[1] = RLSW.vertexBuffer[RLSW.vertexCounter - 1].texcoord[1]; + v[0] = RLSW.primitive.buffer[RLSW.primitive.vertexCount - 1].texcoord[0]; + v[1] = RLSW.primitive.buffer[RLSW.primitive.vertexCount - 1].texcoord[1]; } break; case SW_POINT_SIZE: { @@ -4131,60 +4235,27 @@ void swClear(uint32_t bitmask) if ((bitmask & (SW_COLOR_BUFFER_BIT)) && (RLSW.colorBuffer != NULL) && (RLSW.colorBuffer->pixels != NULL)) { - int size = RLSW.colorBuffer->width*RLSW.colorBuffer->height; sw_framebuffer_fill_color(RLSW.colorBuffer, RLSW.clearColor); } if ((bitmask & (SW_DEPTH_BUFFER_BIT)) && (RLSW.depthBuffer != NULL) && (RLSW.depthBuffer->pixels != NULL)) { - int size = RLSW.depthBuffer->width*RLSW.depthBuffer->height; sw_framebuffer_fill_depth(RLSW.depthBuffer, RLSW.clearDepth); } } void swBlendFunc(SWfactor sfactor, SWfactor dfactor) { - if (!sw_is_blend_src_factor_valid(sfactor) || - !sw_is_blend_dst_factor_valid(dfactor)) - { - RLSW.errCode = SW_INVALID_ENUM; - return; - } + int sIndex = sw_blend_factor_index(sfactor); + if (sIndex < 0) { RLSW.errCode = SW_INVALID_ENUM; return; } + + int dIndex = sw_blend_factor_index(dfactor); + if (dIndex < 0) { RLSW.errCode = SW_INVALID_ENUM; return; } RLSW.srcFactor = sfactor; RLSW.dstFactor = dfactor; - - switch (sfactor) - { - case SW_ZERO: RLSW.srcFactorFunc = sw_factor_zero; break; - case SW_ONE: RLSW.srcFactorFunc = sw_factor_one; break; - case SW_SRC_COLOR: RLSW.srcFactorFunc = sw_factor_src_color; break; - case SW_ONE_MINUS_SRC_COLOR: RLSW.srcFactorFunc = sw_factor_one_minus_src_color; break; - case SW_SRC_ALPHA: RLSW.srcFactorFunc = sw_factor_src_alpha; break; - case SW_ONE_MINUS_SRC_ALPHA: RLSW.srcFactorFunc = sw_factor_one_minus_src_alpha; break; - case SW_DST_ALPHA: RLSW.srcFactorFunc = sw_factor_dst_alpha; break; - case SW_ONE_MINUS_DST_ALPHA: RLSW.srcFactorFunc = sw_factor_one_minus_dst_alpha; break; - case SW_DST_COLOR: RLSW.srcFactorFunc = sw_factor_dst_color; break; - case SW_ONE_MINUS_DST_COLOR: RLSW.srcFactorFunc = sw_factor_one_minus_dst_color; break; - case SW_SRC_ALPHA_SATURATE: RLSW.srcFactorFunc = sw_factor_src_alpha_saturate; break; - default: break; - } - - switch (dfactor) - { - case SW_ZERO: RLSW.dstFactorFunc = sw_factor_zero; break; - case SW_ONE: RLSW.dstFactorFunc = sw_factor_one; break; - case SW_SRC_COLOR: RLSW.dstFactorFunc = sw_factor_src_color; break; - case SW_ONE_MINUS_SRC_COLOR: RLSW.dstFactorFunc = sw_factor_one_minus_src_color; break; - case SW_SRC_ALPHA: RLSW.dstFactorFunc = sw_factor_src_alpha; break; - case SW_ONE_MINUS_SRC_ALPHA: RLSW.dstFactorFunc = sw_factor_one_minus_src_alpha; break; - case SW_DST_ALPHA: RLSW.dstFactorFunc = sw_factor_dst_alpha; break; - case SW_ONE_MINUS_DST_ALPHA: RLSW.dstFactorFunc = sw_factor_one_minus_dst_alpha; break; - case SW_DST_COLOR: RLSW.dstFactorFunc = sw_factor_dst_color; break; - case SW_ONE_MINUS_DST_COLOR: RLSW.dstFactorFunc = sw_factor_one_minus_dst_color; break; - case SW_SRC_ALPHA_SATURATE: break; - default: break; - } + RLSW.blendFlags = sw_blend_compute_flags(sfactor, dfactor); + RLSW.blendFunc = SW_BLEND_TABLE[sIndex][dIndex]; } void swPolygonMode(SWpoly mode) @@ -4502,77 +4573,79 @@ void swBegin(SWdraw mode) return; } - // Recalculate the MVP if this is needed - if (RLSW.isDirtyMVP) + // Ensures that a recording has not already started (spec) + if (sw_immediate_is_active()) { - sw_matrix_mul_rst(RLSW.matMVP, - RLSW.stackModelview[RLSW.stackModelviewCounter - 1], - RLSW.stackProjection[RLSW.stackProjectionCounter - 1]); - - RLSW.isDirtyMVP = false; + RLSW.errCode = SW_INVALID_OPERATION; + return; } - // Initialize required values - RLSW.vertexCounter = 0; - RLSW.drawMode = mode; + sw_immediate_begin(mode); } void swEnd(void) { - RLSW.drawMode = SW_DRAW_INVALID; + // Ensures that a recording has already started (spec) + if (!sw_immediate_is_active()) + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + + sw_immediate_end(); } void swVertex2i(int x, int y) { const float v[4] = { (float)x, (float)y, 0.0f, 1.0f }; - sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord); + sw_immediate_push_vertex(v); } void swVertex2f(float x, float y) { const float v[4] = { x, y, 0.0f, 1.0f }; - sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord); + sw_immediate_push_vertex(v); } void swVertex2fv(const float *v) { const float v4[4] = { v[0], v[1], 0.0f, 1.0f }; - sw_immediate_push_vertex(v4, RLSW.current.color, RLSW.current.texcoord); + sw_immediate_push_vertex(v4); } void swVertex3i(int x, int y, int z) { const float v[4] = { (float)x, (float)y, (float)z, 1.0f }; - sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord); + sw_immediate_push_vertex(v); } void swVertex3f(float x, float y, float z) { const float v[4] = { x, y, z, 1.0f }; - sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord); + sw_immediate_push_vertex(v); } void swVertex3fv(const float *v) { const float v4[4] = { v[0], v[1], v[2], 1.0f }; - sw_immediate_push_vertex(v4, RLSW.current.color, RLSW.current.texcoord); + sw_immediate_push_vertex(v4); } void swVertex4i(int x, int y, int z, int w) { const float v[4] = { (float)x, (float)y, (float)z, (float)w }; - sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord); + sw_immediate_push_vertex(v); } void swVertex4f(float x, float y, float z, float w) { const float v[4] = { x, y, z, w }; - sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord); + sw_immediate_push_vertex(v); } void swVertex4fv(const float *v) { - sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord); + sw_immediate_push_vertex(v); } void swColor3ub(uint8_t r, uint8_t g, uint8_t b) @@ -4583,7 +4656,7 @@ void swColor3ub(uint8_t r, uint8_t g, uint8_t b) cv[2] = (float)b*SW_INV_255; cv[3] = 1.0f; - swColor4fv(cv); + sw_immediate_set_color(cv); } void swColor3ubv(const uint8_t *v) @@ -4594,7 +4667,7 @@ void swColor3ubv(const uint8_t *v) cv[2] = (float)v[2]*SW_INV_255; cv[3] = 1.0f; - swColor4fv(cv); + sw_immediate_set_color(cv); } void swColor3f(float r, float g, float b) @@ -4605,7 +4678,7 @@ void swColor3f(float r, float g, float b) cv[2] = b; cv[3] = 1.0f; - swColor4fv(cv); + sw_immediate_set_color(cv); } void swColor3fv(const float *v) @@ -4616,7 +4689,7 @@ void swColor3fv(const float *v) cv[2] = v[2]; cv[3] = 1.0f; - swColor4fv(cv); + sw_immediate_set_color(cv); } void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a) @@ -4627,7 +4700,7 @@ void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a) cv[2] = (float)b*SW_INV_255; cv[3] = (float)a*SW_INV_255; - swColor4fv(cv); + sw_immediate_set_color(cv); } void swColor4ubv(const uint8_t *v) @@ -4638,7 +4711,7 @@ void swColor4ubv(const uint8_t *v) cv[2] = (float)v[2]*SW_INV_255; cv[3] = (float)v[3]*SW_INV_255; - swColor4fv(cv); + sw_immediate_set_color(cv); } void swColor4f(float r, float g, float b, float a) @@ -4649,32 +4722,33 @@ void swColor4f(float r, float g, float b, float a) cv[2] = b; cv[3] = a; - swColor4fv(cv); + sw_immediate_set_color(cv); } void swColor4fv(const float *v) { - for (int i = 0; i < 4; i++) RLSW.current.color[i] = v[i]; + sw_immediate_set_color(v); } void swTexCoord2f(float u, float v) { - const float *m = RLSW.stackTexture[RLSW.stackTextureCounter - 1]; - - RLSW.current.texcoord[0] = m[0]*u + m[4]*v + m[12]; - RLSW.current.texcoord[1] = m[1]*u + m[5]*v + m[13]; + const float texcoord[2] = { u, v }; + sw_immediate_set_texcoord(texcoord); } void swTexCoord2fv(const float *v) { - const float *m = RLSW.stackTexture[RLSW.stackTextureCounter - 1]; - - RLSW.current.texcoord[0] = m[0]*v[0] + m[4]*v[1] + m[12]; - RLSW.current.texcoord[1] = m[1]*v[0] + m[5]*v[1] + m[13]; + sw_immediate_set_texcoord(v); } void swBindArray(SWarray type, void *buffer) { + if (sw_immediate_is_active()) + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + switch (type) { case SW_VERTEX_ARRAY: RLSW.array.positions = (float *)buffer; break; @@ -4686,76 +4760,46 @@ void swBindArray(SWarray type, void *buffer) void swDrawArrays(SWdraw mode, int offset, int count) { - if ((!sw_is_ready_to_render()) || (RLSW.array.positions == NULL)) + if ((sw_immediate_is_active()) || (!sw_is_ready_to_render()) || (RLSW.array.positions == NULL)) { RLSW.errCode = SW_INVALID_OPERATION; return; } - swBegin(mode); + sw_immediate_begin(mode); { - const float *texMatrix = RLSW.stackTexture[RLSW.stackTextureCounter - 1]; - const float *defaultTexcoord = RLSW.current.texcoord; - const float *defaultColor = RLSW.current.color; - const float *positions = RLSW.array.positions; const float *texcoords = RLSW.array.texcoords; const uint8_t *colors = RLSW.array.colors; int end = offset + count; - for (int i = offset; i < end; i++) { - float u, v; - if (texcoords) - { - int idx = 2*i; - u = texcoords[idx]; - v = texcoords[idx + 1]; - } - else - { - u = defaultTexcoord[0]; - v = defaultTexcoord[1]; - } - - float texcoord[2]; - texcoord[0] = texMatrix[0]*u + texMatrix[4]*v + texMatrix[12]; - texcoord[1] = texMatrix[1]*u + texMatrix[5]*v + texMatrix[13]; - - float color[4] = { - defaultColor[0], - defaultColor[1], - defaultColor[2], - defaultColor[3] - }; + if (texcoords) sw_immediate_set_texcoord(&texcoords[2*i]); if (colors) { - int idx = 4*i; - color[0] *= (float)colors[idx]*SW_INV_255; - color[1] *= (float)colors[idx + 1]*SW_INV_255; - color[2] *= (float)colors[idx + 2]*SW_INV_255; - color[3] *= (float)colors[idx + 3]*SW_INV_255; + const uint8_t *c = &colors[4*i]; + float color[4] = { + (float)c[0]*SW_INV_255, + (float)c[1]*SW_INV_255, + (float)c[2]*SW_INV_255, + (float)c[3]*SW_INV_255, + }; + sw_immediate_set_color(color); } - int idx = 3*i; - float position[4] = { - positions[idx], - positions[idx + 1], - positions[idx + 2], - 1.0f - }; - - sw_immediate_push_vertex(position, color, texcoord); + const float *p = &positions[3*i]; + float position[4] = { p[0], p[1], p[2], 1.0f }; + sw_immediate_push_vertex(position); } } - swEnd(); + sw_immediate_end(); } void swDrawElements(SWdraw mode, int count, int type, const void *indices) { - if ((!sw_is_ready_to_render()) || (RLSW.array.positions == NULL)) + if ((sw_immediate_is_active()) || (!sw_is_ready_to_render()) || (RLSW.array.positions == NULL)) { RLSW.errCode = SW_INVALID_OPERATION; return; @@ -4767,82 +4811,56 @@ void swDrawElements(SWdraw mode, int count, int type, const void *indices) return; } - const uint8_t *indicesUb = NULL; - const uint16_t *indicesUs = NULL; - const uint32_t *indicesUi = NULL; - - switch (type) + if ((type != SW_UNSIGNED_BYTE) && (type != SW_UNSIGNED_SHORT) && (type != SW_UNSIGNED_INT)) { - case SW_UNSIGNED_BYTE: indicesUb = (const uint8_t *)indices; break; - case SW_UNSIGNED_SHORT: indicesUs = (const uint16_t *)indices; break; - case SW_UNSIGNED_INT: indicesUi = (const uint32_t *)indices; break; - default: RLSW.errCode = SW_INVALID_ENUM; return; + RLSW.errCode = SW_INVALID_ENUM; + return; } - swBegin(mode); + sw_immediate_begin(mode); { - const float *texMatrix = RLSW.stackTexture[RLSW.stackTextureCounter - 1]; - const float *defaultTexcoord = RLSW.current.texcoord; - const float *defaultColor = RLSW.current.color; - const float *positions = RLSW.array.positions; const float *texcoords = RLSW.array.texcoords; const uint8_t *colors = RLSW.array.colors; + const uint8_t *indicesUb = (type == SW_UNSIGNED_BYTE)? indices : NULL; + const uint16_t *indicesUs = (type == SW_UNSIGNED_SHORT)? indices : NULL; + const uint32_t *indicesUi = (type == SW_UNSIGNED_INT)? indices : NULL; + for (int i = 0; i < count; i++) { - int index = indicesUb? indicesUb[i] : - (indicesUs? indicesUs[i] : indicesUi[i]); + uint32_t index = indicesUb? (uint32_t)indicesUb[i] : (indicesUs? (uint32_t)indicesUs[i] : (uint32_t)indicesUi[i]); - float u, v; - if (texcoords) - { - int idx = 2*index; - u = texcoords[idx]; - v = texcoords[idx + 1]; - } - else - { - u = defaultTexcoord[0]; - v = defaultTexcoord[1]; - } - - float texcoord[2]; - texcoord[0] = texMatrix[0]*u + texMatrix[4]*v + texMatrix[12]; - texcoord[1] = texMatrix[1]*u + texMatrix[5]*v + texMatrix[13]; - - float color[4] = { - defaultColor[0], - defaultColor[1], - defaultColor[2], - defaultColor[3] - }; + if (texcoords) sw_immediate_set_texcoord(&texcoords[2*index]); if (colors) { - int idx = 4*index; - color[0] *= (float)colors[idx]*SW_INV_255; - color[1] *= (float)colors[idx + 1]*SW_INV_255; - color[2] *= (float)colors[idx + 2]*SW_INV_255; - color[3] *= (float)colors[idx + 3]*SW_INV_255; + const uint8_t *c = &colors[4*index]; + float color[4] = { + (float)c[0]*SW_INV_255, + (float)c[1]*SW_INV_255, + (float)c[2]*SW_INV_255, + (float)c[3]*SW_INV_255, + }; + sw_immediate_set_color(color); } - int idx = 3*index; - float position[4] = { - positions[idx], - positions[idx + 1], - positions[idx + 2], - 1.0f - }; - - sw_immediate_push_vertex(position, color, texcoord); + const float *p = &positions[3*index]; + float position[4] = { p[0], p[1], p[2], 1.0f }; + sw_immediate_push_vertex(position); } } - swEnd(); + sw_immediate_end(); } void swGenTextures(int count, sw_handle_t *textures) { + if (sw_immediate_is_active()) + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + if (!count || !textures) return; for (int i = 0; i < count; i++) @@ -4855,6 +4873,12 @@ void swGenTextures(int count, sw_handle_t *textures) void swDeleteTextures(int count, sw_handle_t *textures) { + if (sw_immediate_is_active()) + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + if (!count || !textures) return; for (int i = 0; i < count; i++) @@ -4866,7 +4890,7 @@ void swDeleteTextures(int count, sw_handle_t *textures) if (tex == RLSW.depthBuffer) RLSW.depthBuffer = NULL; sw_texture_free(tex); - *tex = (sw_texture_t){ 0 }; + *tex = (sw_texture_t) { 0 }; sw_pool_free(&RLSW.texturePool, textures[i]); } @@ -4874,14 +4898,35 @@ void swDeleteTextures(int count, sw_handle_t *textures) void swBindTexture(sw_handle_t id) { - if (id == SW_HANDLE_NULL) { RLSW.boundTexture = NULL; return; } - if (!sw_is_texture_valid(id)) { RLSW.errCode = SW_INVALID_VALUE; return; } + if (sw_immediate_is_active()) + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + + if (id == SW_HANDLE_NULL) + { + RLSW.boundTexture = NULL; + return; + } + + if (!sw_is_texture_valid(id)) + { + RLSW.errCode = SW_INVALID_VALUE; + return; + } RLSW.boundTexture = sw_pool_get(&RLSW.texturePool, id); } void swTexStorage2D(int width, int height, SWinternalformat format) { + if (sw_immediate_is_active()) + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + if (RLSW.boundTexture == NULL) return; int pixelFormat = SW_PIXELFORMAT_UNKNOWN; @@ -4912,6 +4957,12 @@ void swTexStorage2D(int width, int height, SWinternalformat format) void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data) { + if (sw_immediate_is_active()) + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + if (RLSW.boundTexture == NULL) return; int pixelFormat = sw_pixel_get_format(format, type); @@ -4922,6 +4973,12 @@ void swTexImage2D(int width, int height, SWformat format, SWtype type, const voi void swTexSubImage2D(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) { + if (sw_immediate_is_active()) + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + if (!sw_is_texture_complete(RLSW.boundTexture) || (!pixels) || (width <= 0) || (height <= 0)) { RLSW.errCode = SW_INVALID_VALUE; @@ -4934,20 +4991,28 @@ void swTexSubImage2D(GLint x, GLint y, GLsizei width, GLsizei height, GLenum for return; } - sw_pixelformat_t pFormat = sw_pixel_get_format(format, type); - if ((pFormat <= 0) || (pFormat >= SW_PIXELFORMAT_COUNT)) + sw_pixel_write_color_f writeColor = sw_pixel_get_write_color_func(RLSW.boundTexture->format); + if (writeColor == NULL) // probably a depth format + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + + sw_pixelformat_t srcPixelFormat = sw_pixel_get_format(format, type); + sw_pixel_read_color_f readColor = sw_pixel_get_read_color_func(srcPixelFormat); + if (readColor == NULL) { RLSW.errCode = SW_INVALID_ENUM; return; } - const int srcPixelSize = SW_PIXELFORMAT_SIZE[pFormat]; + const int srcPixelSize = SW_PIXELFORMAT_SIZE[srcPixelFormat]; const int dstPixelSize = SW_PIXELFORMAT_SIZE[RLSW.boundTexture->format]; const uint8_t *srcBytes = (const uint8_t *)pixels; uint8_t *dstBytes = (uint8_t *)RLSW.boundTexture->pixels; - if (pFormat == RLSW.boundTexture->format) + if (srcPixelFormat == RLSW.boundTexture->format) { const int rowSize = width*dstPixelSize; const int dstStride = RLSW.boundTexture->width*dstPixelSize; @@ -4965,6 +5030,8 @@ void swTexSubImage2D(GLint x, GLint y, GLsizei width, GLsizei height, GLenum for return; } + bool alphaFound = false; + for (int j = 0; j < height; ++j) { for (int i = 0; i < width; ++i) @@ -4973,14 +5040,24 @@ void swTexSubImage2D(GLint x, GLint y, GLsizei width, GLsizei height, GLenum for const int srcPixelOffset = ((j*width) + i)*srcPixelSize; const int dstPixelOffset = (((y + j)*RLSW.boundTexture->width) + (x + i))*dstPixelSize; - sw_pixel_get_color(color, srcBytes, srcPixelOffset, pFormat); - sw_pixel_set_color(dstBytes, color, dstPixelOffset, RLSW.boundTexture->format); + readColor(color, srcBytes, srcPixelOffset); + alphaFound |= (color[3] < 1.0f); + + writeColor(dstBytes, color, dstPixelOffset); } } + + RLSW.boundTexture->alpha = alphaFound? SW_PIXELFORMAT_ALPHA[srcPixelFormat] : SW_PIXEL_ALPHA_NONE; } void swTexParameteri(int param, int value) { + if (sw_immediate_is_active()) + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + if (RLSW.boundTexture == NULL) return; switch (param) @@ -5011,6 +5088,12 @@ void swTexParameteri(int param, int value) void swGenFramebuffers(int count, uint32_t *framebuffers) { + if (sw_immediate_is_active()) + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + if (!count || !framebuffers) return; for (int i = 0; i < count; i++) @@ -5023,6 +5106,12 @@ void swGenFramebuffers(int count, uint32_t *framebuffers) void swDeleteFramebuffers(int count, uint32_t *framebuffers) { + if (sw_immediate_is_active()) + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + if (!count || !framebuffers) return; for (int i = 0; i < count; i++) @@ -5043,6 +5132,12 @@ void swDeleteFramebuffers(int count, uint32_t *framebuffers) void swBindFramebuffer(uint32_t id) { + if (sw_immediate_is_active()) + { + RLSW.errCode = SW_INVALID_OPERATION; + return; + } + if (id == SW_HANDLE_NULL) { RLSW.boundFramebufferId = SW_HANDLE_NULL; @@ -5065,7 +5160,7 @@ void swBindFramebuffer(uint32_t id) void swFramebufferTexture2D(SWattachment attach, uint32_t texture) { - if (RLSW.boundFramebufferId == SW_HANDLE_NULL) + if ((sw_immediate_is_active()) || (RLSW.boundFramebufferId == SW_HANDLE_NULL)) { RLSW.errCode = SW_INVALID_OPERATION; // not really standard but hey return; @@ -5161,152 +5256,202 @@ void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWattachget #define SW_RASTER_TRIANGLE_SPAN SW_CONCATX(sw_raster_triangle_span_, RLSW_TEMPLATE_RASTER_TRIANGLE) #define SW_RASTER_TRIANGLE SW_CONCATX(sw_raster_triangle_, RLSW_TEMPLATE_RASTER_TRIANGLE) +#ifdef SW_ENABLE_TEXTURE + #define SW_GET_GRAD sw_get_vertex_grad_CTH + #define SW_ADD_GRAD sw_add_vertex_grad_CTH + #define SW_ADD_GRAD_SCALED sw_add_vertex_grad_scaled_CTH +#else + #define SW_GET_GRAD sw_get_vertex_grad_CH + #define SW_ADD_GRAD sw_add_vertex_grad_CH + #define SW_ADD_GRAD_SCALED sw_add_vertex_grad_scaled_CH +#endif + static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t *end, float dUdy, float dVdy) { - // Gets the start and end coordinates - int xStart = (int)start->screen[0]; - int xEnd = (int)end->screen[0]; - - // Avoid empty lines + // Gets the start/end coordinates and skip empty lines + int xStart = (int)start->coord[0]; + int xEnd = (int)end->coord[0]; if (xStart == xEnd) return; - // Compute the subpixel distance to traverse before the first pixel - float xSubstep = 1.0f - sw_fract(start->screen[0]); - // Compute the inverse horizontal distance along the X axis - float dxRcp = 1.0f/(end->screen[0] - start->screen[0]); + float dxRcp = 1.0f/(end->coord[0] - start->coord[0]); // Compute the interpolation steps along the X axis -#ifdef SW_ENABLE_DEPTH_TEST - float dZdx = (end->homogeneous[2] - start->homogeneous[2])*dxRcp; -#endif - float dWdx = (end->homogeneous[3] - start->homogeneous[3])*dxRcp; + float dWdx = (end->coord[3] - start->coord[3])*dxRcp; float dCdx[4] = { (end->color[0] - start->color[0])*dxRcp, (end->color[1] - start->color[1])*dxRcp, (end->color[2] - start->color[2])*dxRcp, (end->color[3] - start->color[3])*dxRcp }; +#ifdef SW_ENABLE_DEPTH_TEST + float dZdx = (end->coord[2] - start->coord[2])*dxRcp; +#endif #ifdef SW_ENABLE_TEXTURE float dUdx = (end->texcoord[0] - start->texcoord[0])*dxRcp; float dVdx = (end->texcoord[1] - start->texcoord[1])*dxRcp; #endif + // Compute the subpixel distance to traverse before the first pixel + float xSubstep = 1.0f - sw_fract(start->coord[0]); + // Initializing the interpolation starting values -#ifdef SW_ENABLE_DEPTH_TEST - float z = start->homogeneous[2] + dZdx*xSubstep; -#endif - float w = start->homogeneous[3] + dWdx*xSubstep; + float w = start->coord[3] + dWdx*xSubstep; float color[4] = { start->color[0] + dCdx[0]*xSubstep, start->color[1] + dCdx[1]*xSubstep, start->color[2] + dCdx[2]*xSubstep, start->color[3] + dCdx[3]*xSubstep }; +#ifdef SW_ENABLE_DEPTH_TEST + float z = start->coord[2] + dZdx*xSubstep; +#endif #ifdef SW_ENABLE_TEXTURE float u = start->texcoord[0] + dUdx*xSubstep; float v = start->texcoord[1] + dVdx*xSubstep; #endif // Pre-calculate the starting pointers for the framebuffer row - int y = (int)start->screen[1]; + int y = (int)start->coord[1]; int baseOffset = y*RLSW.colorBuffer->width + xStart; uint8_t *cPtr = (uint8_t *)(RLSW.colorBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE; #ifdef SW_ENABLE_DEPTH_TEST uint8_t *dPtr = (uint8_t *)(RLSW.depthBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE; #endif - // Scanline rasterization - for (int x = xStart; x < xEnd; x++) +#define SW_AFFINE_BLOCK 16 + + int x = xStart; + while (x < xEnd) { - float wRcp = 1.0f/w; + // Clamp last block to remaining pixels + int blockEnd = x + SW_AFFINE_BLOCK; + if (blockEnd > xEnd) blockEnd = xEnd; + float blockLenF = (float)(blockEnd - x); + float blockLenRcp = 1.0f/blockLenF; + + // Only 2 '1/w' here; none inside the pixel loop + float wRcpA = 1.0f/w; + float wB = w + dWdx*blockLenF; + float wRcpB = 1.0f/wB; + + // Perspective-correct color at both block endpoints, then affine gradient float srcColor[4] = { - color[0]*wRcp, - color[1]*wRcp, - color[2]*wRcp, - color[3]*wRcp + color[0]*wRcpA, + color[1]*wRcpA, + color[2]*wRcpA, + color[3]*wRcpA + }; + float dSrcColordx[4] = { + ((color[0] + dCdx[0]*blockLenF)*wRcpB - srcColor[0])*blockLenRcp, + ((color[1] + dCdx[1]*blockLenF)*wRcpB - srcColor[1])*blockLenRcp, + ((color[2] + dCdx[2]*blockLenF)*wRcpB - srcColor[2])*blockLenRcp, + ((color[3] + dCdx[3]*blockLenF)*wRcpB - srcColor[3])*blockLenRcp }; - #ifdef SW_ENABLE_DEPTH_TEST + #ifdef SW_ENABLE_TEXTURE + // Perspective-correct UVs at both endpoints, then affine gradient + float uAffine = u*wRcpA; + float vAffine = v*wRcpA; + float dUaffine = ((u + dUdx*blockLenF)*wRcpB - uAffine)*blockLenRcp; + float dVaffine = ((v + dVdx*blockLenF)*wRcpB - vAffine)*blockLenRcp; + #endif + + // Inner span pixel loop + for (; x < blockEnd; x++) { - /* TODO: Implement different depth funcs? */ - float depth = SW_FRAMEBUFFER_DEPTH_GET(dPtr, 0); - if (z > depth) goto discard; + #ifdef SW_ENABLE_DEPTH_TEST + { + float depth = SW_FRAMEBUFFER_DEPTH_GET(dPtr, 0); + if (z > depth) goto discard; + SW_FRAMEBUFFER_DEPTH_SET(dPtr, z, 0); + } + #endif - /* TODO: Implement depth mask */ - SW_FRAMEBUFFER_DEPTH_SET(dPtr, z, 0); + #ifdef SW_ENABLE_TEXTURE + { + float texColor[4]; + sw_texture_sample(texColor, RLSW.boundTexture, uAffine, vAffine, dUdx, dUdy, dVdx, dVdy); + float finalColor[4] = { + srcColor[0]*texColor[0], + srcColor[1]*texColor[1], + srcColor[2]*texColor[2], + srcColor[3]*texColor[3] + }; + #ifdef SW_ENABLE_BLEND + { + float dstColor[4]; + SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); + RLSW.blendFunc(dstColor, finalColor); + SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); + } + #else + SW_FRAMEBUFFER_COLOR_SET(cPtr, finalColor, 0); + #endif + } + #else + { + #ifdef SW_ENABLE_BLEND + { + float dstColor[4]; + SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); + RLSW.blendFunc(dstColor, srcColor); + SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); + } + #else + SW_FRAMEBUFFER_COLOR_SET(cPtr, srcColor, 0); + #endif + } + #endif + + discard: + srcColor[0] += dSrcColordx[0]; + srcColor[1] += dSrcColordx[1]; + srcColor[2] += dSrcColordx[2]; + srcColor[3] += dSrcColordx[3]; + cPtr += SW_FRAMEBUFFER_COLOR_SIZE; + + #ifdef SW_ENABLE_DEPTH_TEST + { + z += dZdx; + dPtr += SW_FRAMEBUFFER_DEPTH_SIZE; + } + #endif + + #ifdef SW_ENABLE_TEXTURE + { + uAffine += dUaffine; + vAffine += dVaffine; + } + #endif } - #endif + // Advance perspective-space accumulators by the full block width + w = wB; + color[0] += dCdx[0]*blockLenF; + color[1] += dCdx[1]*blockLenF; + color[2] += dCdx[2]*blockLenF; + color[3] += dCdx[3]*blockLenF; #ifdef SW_ENABLE_TEXTURE - { - float texColor[4]; - float s = u*wRcp; - float t = v*wRcp; - sw_texture_sample(texColor, RLSW.boundTexture, s, t, dUdx, dUdy, dVdx, dVdy); - srcColor[0] *= texColor[0]; - srcColor[1] *= texColor[1]; - srcColor[2] *= texColor[2]; - srcColor[3] *= texColor[3]; - } - #endif - - #ifdef SW_ENABLE_BLEND - { - float dstColor[4]; - SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); - sw_blend_colors(dstColor, srcColor); - SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); - } - #else - { - SW_FRAMEBUFFER_COLOR_SET(cPtr, srcColor, 0); - } - #endif - - // Increment the interpolation parameter, UVs, and pointers - discard: - #ifdef SW_ENABLE_DEPTH_TEST - { - z += dZdx; - } - #endif - - w += dWdx; - - color[0] += dCdx[0]; - color[1] += dCdx[1]; - color[2] += dCdx[2]; - color[3] += dCdx[3]; - - #ifdef SW_ENABLE_TEXTURE - { - u += dUdx; - v += dVdx; - } - #endif - - cPtr += SW_FRAMEBUFFER_COLOR_SIZE; - - #ifdef SW_ENABLE_DEPTH_TEST - { - dPtr += SW_FRAMEBUFFER_DEPTH_SIZE; - } + u += dUdx*blockLenF; + v += dVdx*blockLenF; #endif } + +#undef SW_AFFINE_BLOCK } static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, const sw_vertex_t *v2) { // Swap vertices by increasing Y - if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } - if (v1->screen[1] > v2->screen[1]) { const sw_vertex_t *tmp = v1; v1 = v2; v2 = tmp; } - if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } + if (v0->coord[1] > v1->coord[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } + if (v1->coord[1] > v2->coord[1]) { const sw_vertex_t *tmp = v1; v1 = v2; v2 = tmp; } + if (v0->coord[1] > v1->coord[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } // Extracting coordinates from the sorted vertices - float x0 = v0->screen[0], y0 = v0->screen[1]; - float x1 = v1->screen[0], y1 = v1->screen[1]; - float x2 = v2->screen[0], y2 = v2->screen[1]; + float x0 = v0->coord[0], y0 = v0->coord[1]; + float x1 = v1->coord[0], y1 = v1->coord[1]; + float x2 = v2->coord[0], y2 = v2->coord[1]; // Compute height differences float h02 = y2 - y0; @@ -5315,75 +5460,64 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con if (h02 < 1e-6f) return; - // Precompute the inverse values without additional checks + // Inverse edge dy for per-edge dV/dy (scanline interpolation) float h02Rcp = 1.0f/h02; float h01Rcp = (h01 > 1e-6f)? 1.0f/h01 : 0.0f; float h12Rcp = (h12 > 1e-6f)? 1.0f/h12 : 0.0f; - // Pre-calculation of slopes - float dXdy02 = (x2 - x0)*h02Rcp; - float dXdy01 = (x1 - x0)*h01Rcp; - float dXdy12 = (x2 - x1)*h12Rcp; + // Compute gradients for each side of the triangle + sw_vertex_t dVXdy02, dVXdy01, dVXdy12; + SW_GET_GRAD(&dVXdy02, v0, v2, h02Rcp); + SW_GET_GRAD(&dVXdy01, v0, v1, h01Rcp); + SW_GET_GRAD(&dVXdy12, v1, v2, h12Rcp); // Y subpixel correction float y0Substep = 1.0f - sw_fract(y0); float y1Substep = 1.0f - sw_fract(y1); + // Get a copy of vertices for interpolation and apply substep correction + sw_vertex_t lVert = *v0, rVert = *v0; + SW_ADD_GRAD_SCALED(&lVert, &dVXdy02, y0Substep); + SW_ADD_GRAD_SCALED(&rVert, &dVXdy01, y0Substep); + // Y bounds (vertical clipping) int yTop = (int)y0; int yMid = (int)y1; int yBot = (int)y2; - // Compute gradients for each side of the triangle - sw_vertex_t dVXdy02, dVXdy01, dVXdy12; - sw_get_vertex_grad_PTCH(&dVXdy02, v0, v2, h02Rcp); - sw_get_vertex_grad_PTCH(&dVXdy01, v0, v1, h01Rcp); - sw_get_vertex_grad_PTCH(&dVXdy12, v1, v2, h12Rcp); - - // Get a copy of vertices for interpolation and apply substep correction - sw_vertex_t vLeft = *v0, vRight = *v0; - sw_add_vertex_grad_scaled_PTCH(&vLeft, &dVXdy02, y0Substep); - sw_add_vertex_grad_scaled_PTCH(&vRight, &dVXdy01, y0Substep); - - vLeft.screen[0] += dXdy02*y0Substep; - vRight.screen[0] += dXdy01*y0Substep; - // Scanline for the upper part of the triangle for (int y = yTop; y < yMid; y++) { - vLeft.screen[1] = vRight.screen[1] = y; - - if (vLeft.screen[0] < vRight.screen[0]) SW_RASTER_TRIANGLE_SPAN(&vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); - else SW_RASTER_TRIANGLE_SPAN(&vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); - - sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02); - vLeft.screen[0] += dXdy02; - - sw_add_vertex_grad_PTCH(&vRight, &dVXdy01); - vRight.screen[0] += dXdy01; + lVert.coord[1] = rVert.coord[1] = y; + bool longSideIsLeft = (lVert.coord[0] < rVert.coord[0]); + const sw_vertex_t *a = longSideIsLeft? &lVert : &rVert; + const sw_vertex_t *b = longSideIsLeft? &rVert : &lVert; + SW_RASTER_TRIANGLE_SPAN(a, b, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); + SW_ADD_GRAD(&lVert, &dVXdy02); + SW_ADD_GRAD(&rVert, &dVXdy01); } // Get a copy of next right for interpolation and apply substep correction - vRight = *v1; - sw_add_vertex_grad_scaled_PTCH(&vRight, &dVXdy12, y1Substep); - vRight.screen[0] += dXdy12*y1Substep; + rVert = *v1; + SW_ADD_GRAD_SCALED(&rVert, &dVXdy12, y1Substep); // Scanline for the lower part of the triangle for (int y = yMid; y < yBot; y++) { - vLeft.screen[1] = vRight.screen[1] = y; - - if (vLeft.screen[0] < vRight.screen[0]) SW_RASTER_TRIANGLE_SPAN(&vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); - else SW_RASTER_TRIANGLE_SPAN(&vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); - - sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02); - vLeft.screen[0] += dXdy02; - - sw_add_vertex_grad_PTCH(&vRight, &dVXdy12); - vRight.screen[0] += dXdy12; + lVert.coord[1] = rVert.coord[1] = y; + bool longSideIsLeft = (lVert.coord[0] < rVert.coord[0]); + const sw_vertex_t *a = longSideIsLeft? &lVert : &rVert; + const sw_vertex_t *b = longSideIsLeft? &rVert : &lVert; + SW_RASTER_TRIANGLE_SPAN(a, b, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); + SW_ADD_GRAD(&lVert, &dVXdy02); + SW_ADD_GRAD(&rVert, &dVXdy12); } } +#undef SW_GET_GRAD +#undef SW_ADD_GRAD +#undef SW_ADD_GRAD_SCALED + #endif // RLSW_TEMPLATE_RASTER_TRIANGLE //------------------------------------------------------------------------------------------- @@ -5399,9 +5533,8 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con #define SW_RASTER_QUAD SW_CONCATX(sw_raster_quad_, RLSW_TEMPLATE_RASTER_QUAD) -// REVIEW: Could a perfectly aligned quad, where one of the four points has a different depth, -// still appear perfectly aligned from a certain point of view? -// Because in that case, it's still needed to perform perspective division for textures and colors... +// NOTE: This function should only render affine axis-aligned quads +// No perspective divide is applied after interpolation static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, const sw_vertex_t *c, const sw_vertex_t *d) @@ -5412,18 +5545,18 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, const sw_vertex_t *tl = verts[0], *tr = verts[0], *br = verts[0], *bl = verts[0]; for (int i = 1; i < 4; i++) { - float sum = verts[i]->screen[0] + verts[i]->screen[1]; - float diff = verts[i]->screen[0] - verts[i]->screen[1]; - if (sum < tl->screen[0] + tl->screen[1]) tl = verts[i]; - if (diff > tr->screen[0] - tr->screen[1]) tr = verts[i]; - if (sum > br->screen[0] + br->screen[1]) br = verts[i]; - if (diff < bl->screen[0] - bl->screen[1]) bl = verts[i]; + float sum = verts[i]->coord[0] + verts[i]->coord[1]; + float diff = verts[i]->coord[0] - verts[i]->coord[1]; + if (sum < tl->coord[0] + tl->coord[1]) tl = verts[i]; + if (diff > tr->coord[0] - tr->coord[1]) tr = verts[i]; + if (sum > br->coord[0] + br->coord[1]) br = verts[i]; + if (diff < bl->coord[0] - bl->coord[1]) bl = verts[i]; } - int xMin = (int)tl->screen[0]; - int yMin = (int)tl->screen[1]; - int xMax = (int)br->screen[0]; - int yMax = (int)br->screen[1]; + int xMin = (int)tl->coord[0]; + int yMin = (int)tl->coord[1]; + int xMax = (int)br->coord[0]; + int yMax = (int)br->coord[1]; float w = (float)(xMax - xMin); float h = (float)(yMax - yMin); @@ -5433,8 +5566,8 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, float hRcp = 1.0f/h; // Subpixel corrections - float xSubstep = 1.0f - sw_fract(tl->screen[0]); - float ySubstep = 1.0f - sw_fract(tl->screen[1]); + float xSubstep = 1.0f - sw_fract(tl->coord[0]); + float ySubstep = 1.0f - sw_fract(tl->coord[1]); // Gradients along X (tl->tr) and Y (tl->bl) float dCdx[4] = { @@ -5451,9 +5584,9 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, }; #ifdef SW_ENABLE_DEPTH_TEST - float dZdx = (tr->homogeneous[2] - tl->homogeneous[2])*wRcp; - float dZdy = (bl->homogeneous[2] - tl->homogeneous[2])*hRcp; - float zRow = tl->homogeneous[2] + dZdx*xSubstep + dZdy*ySubstep; + float dZdx = (tr->coord[2] - tl->coord[2])*wRcp; + float dZdy = (bl->coord[2] - tl->coord[2])*hRcp; + float zRow = tl->coord[2] + dZdx*xSubstep + dZdy*ySubstep; #endif #ifdef SW_ENABLE_TEXTURE @@ -5519,7 +5652,7 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, { float dstColor[4]; SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); - sw_blend_colors(dstColor, srcColor); + RLSW.blendFunc(dstColor, srcColor); SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); } #else @@ -5589,10 +5722,10 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1) { // Convert from pixel-center convention (n+0.5) to pixel-origin convention (n) - float x0 = v0->screen[0] - 0.5f; - float y0 = v0->screen[1] - 0.5f; - float x1 = v1->screen[0] - 0.5f; - float y1 = v1->screen[1] - 0.5f; + float x0 = v0->coord[0] - 0.5f; + float y0 = v0->coord[1] - 0.5f; + float x1 = v1->coord[0] - 0.5f; + float y1 = v1->coord[1] - 0.5f; float dx = x1 - x0; float dy = y1 - y0; @@ -5617,7 +5750,7 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1) float yInc = dy/steps; float stepRcp = 1.0f/steps; #ifdef SW_ENABLE_DEPTH_TEST - float zInc = (v1->homogeneous[2] - v0->homogeneous[2])*stepRcp; + float zInc = (v1->coord[2] - v0->coord[2])*stepRcp; #endif float rInc = (v1->color[0] - v0->color[0])*stepRcp; float gInc = (v1->color[1] - v0->color[1])*stepRcp; @@ -5628,7 +5761,7 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1) float x = x0 + xInc*substep; float y = y0 + yInc*substep; #ifdef SW_ENABLE_DEPTH_TEST - float z = v0->homogeneous[2] + zInc*substep; + float z = v0->coord[2] + zInc*substep; #endif float r = v0->color[0] + rInc*substep; float g = v0->color[1] + gInc*substep; @@ -5672,7 +5805,7 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1) { float dstColor[4]; SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); - sw_blend_colors(dstColor, srcColor); + RLSW.blendFunc(dstColor, srcColor); SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); } #else @@ -5696,19 +5829,19 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1) } } -static void SW_RASTER_LINE_THICK(const sw_vertex_t *v1, const sw_vertex_t *v2) +static void SW_RASTER_LINE_THICK(const sw_vertex_t *v0, const sw_vertex_t *v1) { - sw_vertex_t tv1, tv2; + sw_vertex_t tv0, tv1; - int x1 = (int)v1->screen[0]; - int y1 = (int)v1->screen[1]; - int x2 = (int)v2->screen[0]; - int y2 = (int)v2->screen[1]; + int x0 = (int)v0->coord[0]; + int y0 = (int)v0->coord[1]; + int x1 = (int)v1->coord[0]; + int y1 = (int)v1->coord[1]; - int dx = x2 - x1; - int dy = y2 - y1; + int dx = x1 - x0; + int dy = y1 - y0; - SW_RASTER_LINE(v1, v2); + SW_RASTER_LINE(v0, v1); if ((dx != 0) && (abs(dy/dx) < 1)) { @@ -5716,14 +5849,14 @@ static void SW_RASTER_LINE_THICK(const sw_vertex_t *v1, const sw_vertex_t *v2) wy >>= 1; for (int i = 1; i <= wy; i++) { - tv1 = *v1, tv2 = *v2; - tv1.screen[1] -= i; - tv2.screen[1] -= i; - SW_RASTER_LINE(&tv1, &tv2); - tv1 = *v1, tv2 = *v2; - tv1.screen[1] += i; - tv2.screen[1] += i; - SW_RASTER_LINE(&tv1, &tv2); + tv0 = *v0, tv1 = *v1; + tv0.coord[1] -= i; + tv1.coord[1] -= i; + SW_RASTER_LINE(&tv0, &tv1); + tv0 = *v0, tv1 = *v1; + tv0.coord[1] += i; + tv1.coord[1] += i; + SW_RASTER_LINE(&tv0, &tv1); } } else if (dy != 0) @@ -5732,14 +5865,14 @@ static void SW_RASTER_LINE_THICK(const sw_vertex_t *v1, const sw_vertex_t *v2) wx >>= 1; for (int i = 1; i <= wx; i++) { - tv1 = *v1, tv2 = *v2; - tv1.screen[0] -= i; - tv2.screen[0] -= i; - SW_RASTER_LINE(&tv1, &tv2); - tv1 = *v1, tv2 = *v2; - tv1.screen[0] += i; - tv2.screen[0] += i; - SW_RASTER_LINE(&tv1, &tv2); + tv0 = *v0, tv1 = *v1; + tv0.coord[0] -= i; + tv1.coord[0] -= i; + SW_RASTER_LINE(&tv0, &tv1); + tv0 = *v0, tv1 = *v1; + tv0.coord[0] += i; + tv1.coord[0] += i; + SW_RASTER_LINE(&tv0, &tv1); } } } @@ -5782,7 +5915,7 @@ static void SW_RASTER_POINT_PIXEL(int x, int y, float z, const float color[4]) { float dstColor[4]; SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); - sw_blend_colors(dstColor, color); + RLSW.blendFunc(dstColor, color); SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); } #else @@ -5794,9 +5927,9 @@ static void SW_RASTER_POINT_PIXEL(int x, int y, float z, const float color[4]) static void SW_RASTER_POINT(const sw_vertex_t *v) { - int cx = v->screen[0]; - int cy = v->screen[1]; - float cz = v->homogeneous[2]; + int cx = v->coord[0]; + int cy = v->coord[1]; + float cz = v->coord[2]; int radius = RLSW.pointRadius; const float *color = v->color; From 8783e66e21cd640ea496a65c79ca6e5f78eed60e Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 19 Mar 2026 23:42:20 +0100 Subject: [PATCH 40/41] Update rlsw.h --- src/external/rlsw.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index b243f576f..e4b481a0b 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -4059,9 +4059,9 @@ void swBlitPixels(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, in // Get framefuffer pixel data pointer and size void *swGetColorBuffer(int *width, int *height) { - if (width != NULL) *width = RLSW.framebuffer.color->width; - if (height != NULL) *height = RLSW.framebuffer.color->height; - return RLSW.framebuffer.color->pixels; + if (width != NULL) *width = RLSW.framebuffer.color.width; + if (height != NULL) *height = RLSW.framebuffer.color.height; + return RLSW.framebuffer.color.pixels; } void swEnable(SWstate state) From 8a685877eb321fe0eaeabab7b8ec69d2f8a0064d Mon Sep 17 00:00:00 2001 From: Le Juez Victor <90587919+Bigfoot71@users.noreply.github.com> Date: Fri, 20 Mar 2026 12:07:50 +0100 Subject: [PATCH 41/41] [rlsw] Remove position attribute from `sw_vertex_t` (#5677) * review `sw_vertex_t` * fix comment * fix pop matrix --- src/external/rlsw.h | 402 ++++++++++++++++++++++---------------------- 1 file changed, 198 insertions(+), 204 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index e4b481a0b..8472b03e9 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -953,10 +953,9 @@ typedef void (*sw_raster_point_f)(const sw_vertex_t*); typedef float sw_matrix_t[4*4]; typedef struct sw_vertex { - float position[4]; // Position coordinates + float position[4]; // Clip space (x,y,z,w) -> NDC (after /w) -> screen space (x,y,z,1/w) float color[4]; // Color value (RGBA) float texcoord[2]; // Texture coordinates - float coord[4]; // Clip space (x,y,z,w) -> NDC (after /w) -> screen space (x,y,z,1/w) } sw_vertex_t; typedef struct { @@ -1221,7 +1220,7 @@ static inline float sw_luminance(const float *color) return color[0]*0.299f + color[1]*0.587f + color[2]*0.114f; } -static inline void sw_lerp_vertex_PCTH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float t) +static inline void sw_lerp_vertex_PCT(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float t) { const float tInv = 1.0f - t; @@ -1240,16 +1239,16 @@ static inline void sw_lerp_vertex_PCTH(sw_vertex_t *SW_RESTRICT out, const sw_ve // Texture coordinate interpolation (2 components) out->texcoord[0] = a->texcoord[0]*tInv + b->texcoord[0]*t; out->texcoord[1] = a->texcoord[1]*tInv + b->texcoord[1]*t; - - // Pipeline coordinate interpolation (4 components) - out->coord[0] = a->coord[0]*tInv + b->coord[0]*t; - out->coord[1] = a->coord[1]*tInv + b->coord[1]*t; - out->coord[2] = a->coord[2]*tInv + b->coord[2]*t; - out->coord[3] = a->coord[3]*tInv + b->coord[3]*t; } -static inline void sw_get_vertex_grad_CTH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale) +static inline void sw_get_vertex_grad_PCT(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale) { + // Calculate gradients for Position + out->position[0] = (b->position[0] - a->position[0])*scale; + out->position[1] = (b->position[1] - a->position[1])*scale; + out->position[2] = (b->position[2] - a->position[2])*scale; + out->position[3] = (b->position[3] - a->position[3])*scale; + // Calculate gradients for Color out->color[0] = (b->color[0] - a->color[0])*scale; out->color[1] = (b->color[1] - a->color[1])*scale; @@ -1259,16 +1258,16 @@ static inline void sw_get_vertex_grad_CTH(sw_vertex_t *SW_RESTRICT out, const sw // Calculate gradients for Texture coordinates out->texcoord[0] = (b->texcoord[0] - a->texcoord[0])*scale; out->texcoord[1] = (b->texcoord[1] - a->texcoord[1])*scale; - - // Calculate gradients for Pipeline coordinates - out->coord[0] = (b->coord[0] - a->coord[0])*scale; - out->coord[1] = (b->coord[1] - a->coord[1])*scale; - out->coord[2] = (b->coord[2] - a->coord[2])*scale; - out->coord[3] = (b->coord[3] - a->coord[3])*scale; } -static inline void sw_add_vertex_grad_CTH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients) +static inline void sw_add_vertex_grad_PCT(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients) { + // Add gradients to Position + out->position[0] += gradients->position[0]; + out->position[1] += gradients->position[1]; + out->position[2] += gradients->position[2]; + out->position[3] += gradients->position[3]; + // Add gradients to Color out->color[0] += gradients->color[0]; out->color[1] += gradients->color[1]; @@ -1278,16 +1277,16 @@ static inline void sw_add_vertex_grad_CTH(sw_vertex_t *SW_RESTRICT out, const sw // Add gradients to Texture coordinates out->texcoord[0] += gradients->texcoord[0]; out->texcoord[1] += gradients->texcoord[1]; - - // Add gradients to Pipeline coordinates - out->coord[0] += gradients->coord[0]; - out->coord[1] += gradients->coord[1]; - out->coord[2] += gradients->coord[2]; - out->coord[3] += gradients->coord[3]; } -static inline void sw_add_vertex_grad_scaled_CTH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients, float scale) +static inline void sw_add_vertex_grad_scaled_PCT(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients, float scale) { + // Add gradients to Position + out->position[0] += gradients->position[0]*scale; + out->position[1] += gradients->position[1]*scale; + out->position[2] += gradients->position[2]*scale; + out->position[3] += gradients->position[3]*scale; + // Add gradients to Color out->color[0] += gradients->color[0]*scale; out->color[1] += gradients->color[1]*scale; @@ -1297,57 +1296,51 @@ static inline void sw_add_vertex_grad_scaled_CTH(sw_vertex_t *SW_RESTRICT out, c // Add gradients to Texture coordinates out->texcoord[0] += gradients->texcoord[0]*scale; out->texcoord[1] += gradients->texcoord[1]*scale; - - // Add gradients to Pipeline coordinates - out->coord[0] += gradients->coord[0]*scale; - out->coord[1] += gradients->coord[1]*scale; - out->coord[2] += gradients->coord[2]*scale; - out->coord[3] += gradients->coord[3]*scale; } -static inline void sw_get_vertex_grad_CH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale) +static inline void sw_get_vertex_grad_PC(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale) { + // Calculate gradients for Position + out->position[0] = (b->position[0] - a->position[0])*scale; + out->position[1] = (b->position[1] - a->position[1])*scale; + out->position[2] = (b->position[2] - a->position[2])*scale; + out->position[3] = (b->position[3] - a->position[3])*scale; + // Calculate gradients for Color out->color[0] = (b->color[0] - a->color[0])*scale; out->color[1] = (b->color[1] - a->color[1])*scale; out->color[2] = (b->color[2] - a->color[2])*scale; out->color[3] = (b->color[3] - a->color[3])*scale; - - // Calculate gradients for Pipeline coordinates - out->coord[0] = (b->coord[0] - a->coord[0])*scale; - out->coord[1] = (b->coord[1] - a->coord[1])*scale; - out->coord[2] = (b->coord[2] - a->coord[2])*scale; - out->coord[3] = (b->coord[3] - a->coord[3])*scale; } -static inline void sw_add_vertex_grad_CH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients) +static inline void sw_add_vertex_grad_PC(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients) { + // Add gradients to Position + out->position[0] += gradients->position[0]; + out->position[1] += gradients->position[1]; + out->position[2] += gradients->position[2]; + out->position[3] += gradients->position[3]; + // Add gradients to Color out->color[0] += gradients->color[0]; out->color[1] += gradients->color[1]; out->color[2] += gradients->color[2]; out->color[3] += gradients->color[3]; - - // Add gradients to Pipeline coordinates - out->coord[0] += gradients->coord[0]; - out->coord[1] += gradients->coord[1]; - out->coord[2] += gradients->coord[2]; - out->coord[3] += gradients->coord[3]; } -static inline void sw_add_vertex_grad_scaled_CH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients, float scale) +static inline void sw_add_vertex_grad_scaled_PC(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients, float scale) { + // Add gradients to Position + out->position[0] += gradients->position[0]*scale; + out->position[1] += gradients->position[1]*scale; + out->position[2] += gradients->position[2]*scale; + out->position[3] += gradients->position[3]*scale; + // Add gradients to Color out->color[0] += gradients->color[0]*scale; out->color[1] += gradients->color[1]*scale; out->color[2] += gradients->color[2]*scale; out->color[3] += gradients->color[3]*scale; - - // Add gradients to Pipeline coordinates - out->coord[0] += gradients->coord[0]*scale; - out->coord[1] += gradients->coord[1]*scale; - out->coord[2] += gradients->coord[2]*scale; - out->coord[3] += gradients->coord[3]*scale; } // Half conversion functions @@ -2871,17 +2864,17 @@ static int sw_clip_##name( int n) \ { \ const sw_vertex_t *prev = &input[n - 1]; \ - int prevInside = FUNC_IS_INSIDE(prev->coord); \ + int prevInside = FUNC_IS_INSIDE(prev->position); \ int outputCount = 0; \ \ for (int i = 0; i < n; i++) { \ const sw_vertex_t *curr = &input[i]; \ - int currInside = FUNC_IS_INSIDE(curr->coord); \ + int currInside = FUNC_IS_INSIDE(curr->position); \ \ /* If transition between interior/exterior, calculate intersection point */ \ if (prevInside != currInside) { \ - float t = FUNC_COMPUTE_T(prev->coord, curr->coord); \ - sw_lerp_vertex_PCTH(&output[outputCount++], prev, curr, t); \ + float t = FUNC_COMPUTE_T(prev->position, curr->position); \ + sw_lerp_vertex_PCT(&output[outputCount++], prev, curr, t); \ } \ \ /* If current vertex inside, add it */ \ @@ -3320,9 +3313,9 @@ static inline bool sw_triangle_face_culling(void) // even with negative w values // Preload clip coordinates into local variables - const float *h0 = RLSW.primitive.buffer[0].coord; - const float *h1 = RLSW.primitive.buffer[1].coord; - const float *h2 = RLSW.primitive.buffer[2].coord; + const float *p0 = RLSW.primitive.buffer[0].position; + const float *p1 = RLSW.primitive.buffer[1].position; + const float *p2 = RLSW.primitive.buffer[2].position; // Compute a value proportional to the signed area in the projected 2D plane, // calculated directly using clip coordinates BEFORE division by w @@ -3331,28 +3324,28 @@ static inline bool sw_triangle_face_culling(void) // space and its relationship to the projected 2D winding order, even with // negative w values // The determinant formula used here is: - // h0.x*(h1.y*h2.w - h2.y*h1.w) + - // h1.x*(h2.y*h0.w - h0.y*h2.w) + - // h2.x*(h0.y*h1.w - h1.y*h0.w) + // p0.x*(p1.y*p2.w - p2.y*p1.w) + + // p1.x*(p2.y*p0.w - p0.y*p2.w) + + // p2.x*(p0.y*p1.w - p1.y*p0.w) - const float hSgnArea = - h0[0]*(h1[1]*h2[3] - h2[1]*h1[3]) + - h1[0]*(h2[1]*h0[3] - h0[1]*h2[3]) + - h2[0]*(h0[1]*h1[3] - h1[1]*h0[3]); + const float sgnArea = + p0[0]*(p1[1]*p2[3] - p2[1]*p1[3]) + + p1[0]*(p2[1]*p0[3] - p0[1]*p2[3]) + + p2[0]*(p0[1]*p1[3] - p1[1]*p0[3]); // Discard the triangle if its winding order (determined by the sign // of the homogeneous area/determinant) matches the culled direction - // A positive hSgnArea typically corresponds to a counter-clockwise + // A positive sgnArea typically corresponds to a counter-clockwise // winding in the projected space when all w > 0 // This test is robust for points with w > 0 or w < 0, correctly // capturing the change in orientation when crossing the w=0 plane // The culling logic remains the same based on the signed area/determinant - // A value of 0 for hSgnArea means the points are collinear in (x, y, w) + // A value of 0 for sgnArea means the points are collinear in (x, y, w) // space, which corresponds to a degenerate triangle projection // Such triangles are typically not culled by this test (0 < 0 is false, 0 > 0 is false) // and should be handled by the clipper if necessary - return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0) : (hSgnArea > 0); // Cull if winding is "clockwise" : "counter-clockwise" + return (RLSW.cullFace == SW_FRONT)? (sgnArea < 0) : (sgnArea > 0); // Cull if winding is "clockwise" : "counter-clockwise" } static void sw_triangle_clip_and_project(void) @@ -3369,13 +3362,13 @@ static void sw_triangle_clip_and_project(void) // Calculation of the reciprocal of W for normalization // as well as perspective-correct attributes - const float wRcp = 1.0f/v->coord[3]; - v->coord[3] = wRcp; + const float wRcp = 1.0f/v->position[3]; // Division of XYZ coordinates by weight - v->coord[0] *= wRcp; - v->coord[1] *= wRcp; - v->coord[2] *= wRcp; + v->position[0] *= wRcp; + v->position[1] *= wRcp; + v->position[2] *= wRcp; + v->position[3] = wRcp; // Division of texture coordinates (perspective-correct) v->texcoord[0] *= wRcp; @@ -3388,7 +3381,7 @@ static void sw_triangle_clip_and_project(void) v->color[3] *= wRcp; // Transformation to screen space - sw_project_ndc_to_screen(v->coord); + sw_project_ndc_to_screen(v->position); } } } @@ -3430,12 +3423,12 @@ static inline bool sw_quad_face_culling(void) // winding test on this first triangle // Preload clip coordinates into local variables - const float *h0 = RLSW.primitive.buffer[0].coord; - const float *h1 = RLSW.primitive.buffer[1].coord; - const float *h2 = RLSW.primitive.buffer[2].coord; + const float *p0 = RLSW.primitive.buffer[0].position; + const float *p1 = RLSW.primitive.buffer[1].position; + const float *p2 = RLSW.primitive.buffer[2].position; // NOTE: h3 is not needed for this test - // const float *h3 = RLSW.primitive.buffer[3].coord; + // const float *h3 = RLSW.primitive.buffer[3].position; // Compute a value proportional to the signed area of the triangle P0 P1 P2 // in the projected 2D plane, calculated directly using clip coordinates @@ -3445,29 +3438,29 @@ static inline bool sw_quad_face_culling(void) // in clip space and its relationship to the projected 2D winding order, // even with negative w values // The determinant formula used here is: - // h0.x*(h1.y*h2.w - h2.y*h1.w) + - // h1.x*(h2.y*h0.w - h0.y*h2.w) + - // h2.x*(h0.y*h1.w - h1.y*h0.w) + // p0.x*(p1.y*p2.w - p2.y*p1.w) + + // p1.x*(p2.y*p0.w - p0.y*p2.w) + + // p2.x*(p0.y*p1.w - p1.y*p0.w) - const float hSgnArea = - h0[0]*(h1[1]*h2[3] - h2[1]*h1[3]) + - h1[0]*(h2[1]*h0[3] - h0[1]*h2[3]) + - h2[0]*(h0[1]*h1[3] - h1[1]*h0[3]); + const float sgnArea = + p0[0]*(p1[1]*p2[3] - p2[1]*p1[3]) + + p1[0]*(p2[1]*p0[3] - p0[1]*p2[3]) + + p2[0]*(p0[1]*p1[3] - p1[1]*p0[3]); // Perform face culling based on the winding order determined by the sign // of the homogeneous area/determinant of triangle P0 P1 P2 // This test is robust for points with w > 0 or w < 0 within the triangle, // correctly capturing the change in orientation when crossing the w=0 plane - // A positive hSgnArea typically corresponds to a counter-clockwise + // A positive sgnArea typically corresponds to a counter-clockwise // winding in the projected space when all w > 0 - // A value of 0 for hSgnArea means P0, P1, P2 are collinear in (x, y, w) + // A value of 0 for sgnArea means P0, P1, P2 are collinear in (x, y, w) // space, which corresponds to a degenerate triangle projection // Such quads might also be degenerate or non-planar. They are typically // not culled by this test (0 < 0 is false, 0 > 0 is false) // and should be handled by the clipper if necessary - return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0.0f) : (hSgnArea > 0.0f); // Cull if winding is "clockwise" : "counter-clockwise" + return (RLSW.cullFace == SW_FRONT)? (sgnArea < 0.0f) : (sgnArea > 0.0f); // Cull if winding is "clockwise" : "counter-clockwise" } static void sw_quad_clip_and_project(void) @@ -3484,13 +3477,13 @@ static void sw_quad_clip_and_project(void) // Calculation of the reciprocal of W for normalization // as well as perspective-correct attributes - const float wRcp = 1.0f/v->coord[3]; - v->coord[3] = wRcp; + const float wRcp = 1.0f/v->position[3]; // Division of XYZ coordinates by weight - v->coord[0] *= wRcp; - v->coord[1] *= wRcp; - v->coord[2] *= wRcp; + v->position[0] *= wRcp; + v->position[1] *= wRcp; + v->position[2] *= wRcp; + v->position[3] = wRcp; // Division of texture coordinates (perspective-correct) v->texcoord[0] *= wRcp; @@ -3503,7 +3496,7 @@ static void sw_quad_clip_and_project(void) v->color[3] *= wRcp; // Transformation to screen space - sw_project_ndc_to_screen(v->coord); + sw_project_ndc_to_screen(v->position); } } } @@ -3515,17 +3508,17 @@ static bool sw_quad_is_axis_aligned(void) // so it's required for all vertices to have homogeneous w = 1.0 for (int i = 0; i < 4; i++) { - if (RLSW.primitive.buffer[i].coord[3] != 1.0f) return false; + if (RLSW.primitive.buffer[i].position[3] != 1.0f) return false; } // Epsilon tolerance in screen space (pixels) const float epsilon = 0.5f; // Fetch screen-space positions for the four quad vertices - const float *p0 = RLSW.primitive.buffer[0].coord; - const float *p1 = RLSW.primitive.buffer[1].coord; - const float *p2 = RLSW.primitive.buffer[2].coord; - const float *p3 = RLSW.primitive.buffer[3].coord; + const float *p0 = RLSW.primitive.buffer[0].position; + const float *p1 = RLSW.primitive.buffer[1].position; + const float *p2 = RLSW.primitive.buffer[2].position; + const float *p3 = RLSW.primitive.buffer[3].position; // Compute edge vectors between consecutive vertices // These define the four sides of the quad in screen space @@ -3614,25 +3607,25 @@ static bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1) for (int i = 0; i < 4; i++) { - dH[i] = v1->coord[i] - v0->coord[i]; + dH[i] = v1->position[i] - v0->position[i]; dC[i] = v1->color[i] - v0->color[i]; } // Clipping Liang-Barsky - if (!sw_line_clip_coord(v0->coord[3] - v0->coord[0], -dH[3] + dH[0], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->coord[3] + v0->coord[0], -dH[3] - dH[0], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->coord[3] - v0->coord[1], -dH[3] + dH[1], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->coord[3] + v0->coord[1], -dH[3] - dH[1], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->coord[3] - v0->coord[2], -dH[3] + dH[2], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->coord[3] + v0->coord[2], -dH[3] - dH[2], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->position[3] - v0->position[0], -dH[3] + dH[0], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->position[3] + v0->position[0], -dH[3] - dH[0], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->position[3] - v0->position[1], -dH[3] + dH[1], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->position[3] + v0->position[1], -dH[3] - dH[1], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->position[3] - v0->position[2], -dH[3] + dH[2], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->position[3] + v0->position[2], -dH[3] - dH[2], &t0, &t1)) return false; // Clipping Scissor if (RLSW.userState & SW_STATE_SCISSOR_TEST) { - if (!sw_line_clip_coord(v0->coord[0] - RLSW.scClipMin[0]*v0->coord[3], RLSW.scClipMin[0]*dH[3] - dH[0], &t0, &t1)) return false; - if (!sw_line_clip_coord(RLSW.scClipMax[0]*v0->coord[3] - v0->coord[0], dH[0] - RLSW.scClipMax[0]*dH[3], &t0, &t1)) return false; - if (!sw_line_clip_coord(v0->coord[1] - RLSW.scClipMin[1]*v0->coord[3], RLSW.scClipMin[1]*dH[3] - dH[1], &t0, &t1)) return false; - if (!sw_line_clip_coord(RLSW.scClipMax[1]*v0->coord[3] - v0->coord[1], dH[1] - RLSW.scClipMax[1]*dH[3], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->position[0] - RLSW.scClipMin[0]*v0->position[3], RLSW.scClipMin[0]*dH[3] - dH[0], &t0, &t1)) return false; + if (!sw_line_clip_coord(RLSW.scClipMax[0]*v0->position[3] - v0->position[0], dH[0] - RLSW.scClipMax[0]*dH[3], &t0, &t1)) return false; + if (!sw_line_clip_coord(v0->position[1] - RLSW.scClipMin[1]*v0->position[3], RLSW.scClipMin[1]*dH[3] - dH[1], &t0, &t1)) return false; + if (!sw_line_clip_coord(RLSW.scClipMax[1]*v0->position[3] - v0->position[1], dH[1] - RLSW.scClipMax[1]*dH[3], &t0, &t1)) return false; } // Interpolation of new coordinates @@ -3640,7 +3633,7 @@ static bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1) { for (int i = 0; i < 4; i++) { - v1->coord[i] = v0->coord[i] + t1*dH[i]; + v1->position[i] = v0->position[i] + t1*dH[i]; v1->color[i] = v0->color[i] + t1*dC[i]; } } @@ -3649,7 +3642,7 @@ static bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1) { for (int i = 0; i < 4; i++) { - v0->coord[i] += t0*dH[i]; + v0->position[i] += t0*dH[i]; v0->color[i] += t0*dC[i]; } } @@ -3662,24 +3655,24 @@ static bool sw_line_clip_and_project(sw_vertex_t *v0, sw_vertex_t *v1) if (!sw_line_clip(v0, v1)) return false; // Convert clip coordinates to NDC - v0->coord[3] = 1.0f/v0->coord[3]; - v1->coord[3] = 1.0f/v1->coord[3]; + v0->position[3] = 1.0f/v0->position[3]; + v1->position[3] = 1.0f/v1->position[3]; for (int i = 0; i < 3; i++) { - v0->coord[i] *= v0->coord[3]; - v1->coord[i] *= v1->coord[3]; + v0->position[i] *= v0->position[3]; + v1->position[i] *= v1->position[3]; } // Convert NDC coordinates to screen space - sw_project_ndc_to_screen(v0->coord); - sw_project_ndc_to_screen(v1->coord); + sw_project_ndc_to_screen(v0->position); + sw_project_ndc_to_screen(v1->position); // NDC +1.0 projects to exactly (width + 0.5f), which truncates out of bounds // The clamp is at most 0.5px on a boundary endpoint, it's visually imperceptible - v0->coord[0] = sw_clamp(v0->coord[0], 0.0f, (float)(RLSW.colorBuffer->width - 1) + 0.5f); - v0->coord[1] = sw_clamp(v0->coord[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f); - v1->coord[0] = sw_clamp(v1->coord[0], 0.0f, (float)(RLSW.colorBuffer->width - 1) + 0.5f); - v1->coord[1] = sw_clamp(v1->coord[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f); + v0->position[0] = sw_clamp(v0->position[0], 0.0f, (float)(RLSW.colorBuffer->width - 1) + 0.5f); + v0->position[1] = sw_clamp(v0->position[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f); + v1->position[0] = sw_clamp(v1->position[0], 0.0f, (float)(RLSW.colorBuffer->width - 1) + 0.5f); + v1->position[1] = sw_clamp(v1->position[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f); return true; } @@ -3705,20 +3698,20 @@ static void sw_line_render(uint32_t state, sw_vertex_t *vertices) //------------------------------------------------------------------------------------------- static bool sw_point_clip_and_project(sw_vertex_t *v) { - if (v->coord[3] != 1.0f) + if (v->position[3] != 1.0f) { for (int_fast8_t i = 0; i < 3; i++) { - if ((v->coord[i] < -v->coord[3]) || (v->coord[i] > v->coord[3])) return false; + if ((v->position[i] < -v->position[3]) || (v->position[i] > v->position[3])) return false; } - v->coord[3] = 1.0f/v->coord[3]; - v->coord[0] *= v->coord[3]; - v->coord[1] *= v->coord[3]; - v->coord[2] *= v->coord[3]; + v->position[3] = 1.0f/v->position[3]; + v->position[0] *= v->position[3]; + v->position[1] *= v->position[3]; + v->position[2] *= v->position[3]; } - sw_project_ndc_to_screen(v->coord); + sw_project_ndc_to_screen(v->position); int min[2] = { 0, 0 }; int max[2] = { RLSW.colorBuffer->width, RLSW.colorBuffer->height }; @@ -3731,8 +3724,8 @@ static bool sw_point_clip_and_project(sw_vertex_t *v) max[1] = sw_clamp_int(RLSW.scMax[1], 0, RLSW.colorBuffer->height); } - bool insideX = (v->coord[0] - RLSW.pointRadius < max[0]) && (v->coord[0] + RLSW.pointRadius > min[0]); - bool insideY = (v->coord[1] - RLSW.pointRadius < max[1]) && (v->coord[1] + RLSW.pointRadius > min[1]); + bool insideX = (v->position[0] - RLSW.pointRadius < max[0]) && (v->position[0] + RLSW.pointRadius > min[0]); + bool insideY = (v->position[1] - RLSW.pointRadius < max[1]) && (v->position[1] + RLSW.pointRadius > min[1]); return (insideX && insideY); } @@ -3841,18 +3834,19 @@ static void sw_immediate_push_vertex(const float position[4]) return; } - // Copy the attributes in the current vertex + // Gets the current vertex sw_vertex_t *vertex = &RLSW.primitive.buffer[RLSW.primitive.vertexCount++]; - for (int i = 0; i < 4; i++) vertex->position[i] = position[i]; - for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.primitive.color[i]; - for (int i = 0; i < 2; i++) vertex->texcoord[i] = RLSW.primitive.texcoord[i]; // Calculate clip coordinates - const float *m = RLSW.matMVP, *v = vertex->position; - vertex->coord[0] = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3]; - vertex->coord[1] = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3]; - vertex->coord[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3]; - vertex->coord[3] = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3]; + const float *m = RLSW.matMVP; + vertex->position[0] = m[0]*position[0] + m[4]*position[1] + m[8]*position[2] + m[12]*position[3]; + vertex->position[1] = m[1]*position[0] + m[5]*position[1] + m[9]*position[2] + m[13]*position[3]; + vertex->position[2] = m[2]*position[0] + m[6]*position[1] + m[10]*position[2] + m[14]*position[3]; + vertex->position[3] = m[3]*position[0] + m[7]*position[1] + m[11]*position[2] + m[15]*position[3]; + + // Copy the attributes in the current vertex + for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.primitive.color[i]; + for (int i = 0; i < 2; i++) vertex->texcoord[i] = RLSW.primitive.texcoord[i]; // Immediate rendering of the primitive if the required number is reached if (RLSW.primitive.vertexCount == SW_PRIMITIVE_VERTEX_COUNT[RLSW.drawMode]) @@ -4377,7 +4371,7 @@ void swPopMatrix(void) return; } - RLSW.currentMatrix = &RLSW.stackProjection[--RLSW.stackProjectionCounter]; + RLSW.currentMatrix = &RLSW.stackProjection[(--RLSW.stackProjectionCounter) - 1]; RLSW.isDirtyMVP = true; //< The MVP is considered to have been changed } break; case SW_MODELVIEW: @@ -4388,7 +4382,7 @@ void swPopMatrix(void) return; } - RLSW.currentMatrix = &RLSW.stackModelview[--RLSW.stackModelviewCounter]; + RLSW.currentMatrix = &RLSW.stackModelview[(--RLSW.stackModelviewCounter) - 1]; RLSW.isDirtyMVP = true; //< The MVP is considered to have been changed } break; case SW_TEXTURE: @@ -4399,7 +4393,7 @@ void swPopMatrix(void) return; } - RLSW.currentMatrix = &RLSW.stackTexture[--RLSW.stackTextureCounter]; + RLSW.currentMatrix = &RLSW.stackTexture[(--RLSW.stackTextureCounter) - 1]; } break; default: break; } @@ -5257,27 +5251,27 @@ void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWattachget #define SW_RASTER_TRIANGLE SW_CONCATX(sw_raster_triangle_, RLSW_TEMPLATE_RASTER_TRIANGLE) #ifdef SW_ENABLE_TEXTURE - #define SW_GET_GRAD sw_get_vertex_grad_CTH - #define SW_ADD_GRAD sw_add_vertex_grad_CTH - #define SW_ADD_GRAD_SCALED sw_add_vertex_grad_scaled_CTH + #define SW_GET_GRAD sw_get_vertex_grad_PCT + #define SW_ADD_GRAD sw_add_vertex_grad_PCT + #define SW_ADD_GRAD_SCALED sw_add_vertex_grad_scaled_PCT #else - #define SW_GET_GRAD sw_get_vertex_grad_CH - #define SW_ADD_GRAD sw_add_vertex_grad_CH - #define SW_ADD_GRAD_SCALED sw_add_vertex_grad_scaled_CH + #define SW_GET_GRAD sw_get_vertex_grad_PC + #define SW_ADD_GRAD sw_add_vertex_grad_PC + #define SW_ADD_GRAD_SCALED sw_add_vertex_grad_scaled_PC #endif static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t *end, float dUdy, float dVdy) { // Gets the start/end coordinates and skip empty lines - int xStart = (int)start->coord[0]; - int xEnd = (int)end->coord[0]; + int xStart = (int)start->position[0]; + int xEnd = (int)end->position[0]; if (xStart == xEnd) return; // Compute the inverse horizontal distance along the X axis - float dxRcp = 1.0f/(end->coord[0] - start->coord[0]); + float dxRcp = 1.0f/(end->position[0] - start->position[0]); // Compute the interpolation steps along the X axis - float dWdx = (end->coord[3] - start->coord[3])*dxRcp; + float dWdx = (end->position[3] - start->position[3])*dxRcp; float dCdx[4] = { (end->color[0] - start->color[0])*dxRcp, (end->color[1] - start->color[1])*dxRcp, @@ -5285,7 +5279,7 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t (end->color[3] - start->color[3])*dxRcp }; #ifdef SW_ENABLE_DEPTH_TEST - float dZdx = (end->coord[2] - start->coord[2])*dxRcp; + float dZdx = (end->position[2] - start->position[2])*dxRcp; #endif #ifdef SW_ENABLE_TEXTURE float dUdx = (end->texcoord[0] - start->texcoord[0])*dxRcp; @@ -5293,10 +5287,10 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t #endif // Compute the subpixel distance to traverse before the first pixel - float xSubstep = 1.0f - sw_fract(start->coord[0]); + float xSubstep = 1.0f - sw_fract(start->position[0]); // Initializing the interpolation starting values - float w = start->coord[3] + dWdx*xSubstep; + float w = start->position[3] + dWdx*xSubstep; float color[4] = { start->color[0] + dCdx[0]*xSubstep, start->color[1] + dCdx[1]*xSubstep, @@ -5304,7 +5298,7 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t start->color[3] + dCdx[3]*xSubstep }; #ifdef SW_ENABLE_DEPTH_TEST - float z = start->coord[2] + dZdx*xSubstep; + float z = start->position[2] + dZdx*xSubstep; #endif #ifdef SW_ENABLE_TEXTURE float u = start->texcoord[0] + dUdx*xSubstep; @@ -5312,7 +5306,7 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t #endif // Pre-calculate the starting pointers for the framebuffer row - int y = (int)start->coord[1]; + int y = (int)start->position[1]; int baseOffset = y*RLSW.colorBuffer->width + xStart; uint8_t *cPtr = (uint8_t *)(RLSW.colorBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE; #ifdef SW_ENABLE_DEPTH_TEST @@ -5444,14 +5438,14 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, const sw_vertex_t *v2) { // Swap vertices by increasing Y - if (v0->coord[1] > v1->coord[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } - if (v1->coord[1] > v2->coord[1]) { const sw_vertex_t *tmp = v1; v1 = v2; v2 = tmp; } - if (v0->coord[1] > v1->coord[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } + if (v0->position[1] > v1->position[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } + if (v1->position[1] > v2->position[1]) { const sw_vertex_t *tmp = v1; v1 = v2; v2 = tmp; } + if (v0->position[1] > v1->position[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } // Extracting coordinates from the sorted vertices - float x0 = v0->coord[0], y0 = v0->coord[1]; - float x1 = v1->coord[0], y1 = v1->coord[1]; - float x2 = v2->coord[0], y2 = v2->coord[1]; + float x0 = v0->position[0], y0 = v0->position[1]; + float x1 = v1->position[0], y1 = v1->position[1]; + float x2 = v2->position[0], y2 = v2->position[1]; // Compute height differences float h02 = y2 - y0; @@ -5488,8 +5482,8 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con // Scanline for the upper part of the triangle for (int y = yTop; y < yMid; y++) { - lVert.coord[1] = rVert.coord[1] = y; - bool longSideIsLeft = (lVert.coord[0] < rVert.coord[0]); + lVert.position[1] = rVert.position[1] = y; + bool longSideIsLeft = (lVert.position[0] < rVert.position[0]); const sw_vertex_t *a = longSideIsLeft? &lVert : &rVert; const sw_vertex_t *b = longSideIsLeft? &rVert : &lVert; SW_RASTER_TRIANGLE_SPAN(a, b, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); @@ -5504,8 +5498,8 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con // Scanline for the lower part of the triangle for (int y = yMid; y < yBot; y++) { - lVert.coord[1] = rVert.coord[1] = y; - bool longSideIsLeft = (lVert.coord[0] < rVert.coord[0]); + lVert.position[1] = rVert.position[1] = y; + bool longSideIsLeft = (lVert.position[0] < rVert.position[0]); const sw_vertex_t *a = longSideIsLeft? &lVert : &rVert; const sw_vertex_t *b = longSideIsLeft? &rVert : &lVert; SW_RASTER_TRIANGLE_SPAN(a, b, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); @@ -5545,18 +5539,18 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, const sw_vertex_t *tl = verts[0], *tr = verts[0], *br = verts[0], *bl = verts[0]; for (int i = 1; i < 4; i++) { - float sum = verts[i]->coord[0] + verts[i]->coord[1]; - float diff = verts[i]->coord[0] - verts[i]->coord[1]; - if (sum < tl->coord[0] + tl->coord[1]) tl = verts[i]; - if (diff > tr->coord[0] - tr->coord[1]) tr = verts[i]; - if (sum > br->coord[0] + br->coord[1]) br = verts[i]; - if (diff < bl->coord[0] - bl->coord[1]) bl = verts[i]; + float sum = verts[i]->position[0] + verts[i]->position[1]; + float diff = verts[i]->position[0] - verts[i]->position[1]; + if (sum < tl->position[0] + tl->position[1]) tl = verts[i]; + if (diff > tr->position[0] - tr->position[1]) tr = verts[i]; + if (sum > br->position[0] + br->position[1]) br = verts[i]; + if (diff < bl->position[0] - bl->position[1]) bl = verts[i]; } - int xMin = (int)tl->coord[0]; - int yMin = (int)tl->coord[1]; - int xMax = (int)br->coord[0]; - int yMax = (int)br->coord[1]; + int xMin = (int)tl->position[0]; + int yMin = (int)tl->position[1]; + int xMax = (int)br->position[0]; + int yMax = (int)br->position[1]; float w = (float)(xMax - xMin); float h = (float)(yMax - yMin); @@ -5566,8 +5560,8 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, float hRcp = 1.0f/h; // Subpixel corrections - float xSubstep = 1.0f - sw_fract(tl->coord[0]); - float ySubstep = 1.0f - sw_fract(tl->coord[1]); + float xSubstep = 1.0f - sw_fract(tl->position[0]); + float ySubstep = 1.0f - sw_fract(tl->position[1]); // Gradients along X (tl->tr) and Y (tl->bl) float dCdx[4] = { @@ -5584,9 +5578,9 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, }; #ifdef SW_ENABLE_DEPTH_TEST - float dZdx = (tr->coord[2] - tl->coord[2])*wRcp; - float dZdy = (bl->coord[2] - tl->coord[2])*hRcp; - float zRow = tl->coord[2] + dZdx*xSubstep + dZdy*ySubstep; + float dZdx = (tr->position[2] - tl->position[2])*wRcp; + float dZdy = (bl->position[2] - tl->position[2])*hRcp; + float zRow = tl->position[2] + dZdx*xSubstep + dZdy*ySubstep; #endif #ifdef SW_ENABLE_TEXTURE @@ -5722,10 +5716,10 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1) { // Convert from pixel-center convention (n+0.5) to pixel-origin convention (n) - float x0 = v0->coord[0] - 0.5f; - float y0 = v0->coord[1] - 0.5f; - float x1 = v1->coord[0] - 0.5f; - float y1 = v1->coord[1] - 0.5f; + float x0 = v0->position[0] - 0.5f; + float y0 = v0->position[1] - 0.5f; + float x1 = v1->position[0] - 0.5f; + float y1 = v1->position[1] - 0.5f; float dx = x1 - x0; float dy = y1 - y0; @@ -5750,7 +5744,7 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1) float yInc = dy/steps; float stepRcp = 1.0f/steps; #ifdef SW_ENABLE_DEPTH_TEST - float zInc = (v1->coord[2] - v0->coord[2])*stepRcp; + float zInc = (v1->position[2] - v0->position[2])*stepRcp; #endif float rInc = (v1->color[0] - v0->color[0])*stepRcp; float gInc = (v1->color[1] - v0->color[1])*stepRcp; @@ -5761,7 +5755,7 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1) float x = x0 + xInc*substep; float y = y0 + yInc*substep; #ifdef SW_ENABLE_DEPTH_TEST - float z = v0->coord[2] + zInc*substep; + float z = v0->position[2] + zInc*substep; #endif float r = v0->color[0] + rInc*substep; float g = v0->color[1] + gInc*substep; @@ -5833,10 +5827,10 @@ static void SW_RASTER_LINE_THICK(const sw_vertex_t *v0, const sw_vertex_t *v1) { sw_vertex_t tv0, tv1; - int x0 = (int)v0->coord[0]; - int y0 = (int)v0->coord[1]; - int x1 = (int)v1->coord[0]; - int y1 = (int)v1->coord[1]; + int x0 = (int)v0->position[0]; + int y0 = (int)v0->position[1]; + int x1 = (int)v1->position[0]; + int y1 = (int)v1->position[1]; int dx = x1 - x0; int dy = y1 - y0; @@ -5850,12 +5844,12 @@ static void SW_RASTER_LINE_THICK(const sw_vertex_t *v0, const sw_vertex_t *v1) for (int i = 1; i <= wy; i++) { tv0 = *v0, tv1 = *v1; - tv0.coord[1] -= i; - tv1.coord[1] -= i; + tv0.position[1] -= i; + tv1.position[1] -= i; SW_RASTER_LINE(&tv0, &tv1); tv0 = *v0, tv1 = *v1; - tv0.coord[1] += i; - tv1.coord[1] += i; + tv0.position[1] += i; + tv1.position[1] += i; SW_RASTER_LINE(&tv0, &tv1); } } @@ -5866,12 +5860,12 @@ static void SW_RASTER_LINE_THICK(const sw_vertex_t *v0, const sw_vertex_t *v1) for (int i = 1; i <= wx; i++) { tv0 = *v0, tv1 = *v1; - tv0.coord[0] -= i; - tv1.coord[0] -= i; + tv0.position[0] -= i; + tv1.position[0] -= i; SW_RASTER_LINE(&tv0, &tv1); tv0 = *v0, tv1 = *v1; - tv0.coord[0] += i; - tv1.coord[0] += i; + tv0.position[0] += i; + tv1.position[0] += i; SW_RASTER_LINE(&tv0, &tv1); } } @@ -5927,9 +5921,9 @@ static void SW_RASTER_POINT_PIXEL(int x, int y, float z, const float color[4]) static void SW_RASTER_POINT(const sw_vertex_t *v) { - int cx = v->coord[0]; - int cy = v->coord[1]; - float cz = v->coord[2]; + int cx = v->position[0]; + int cy = v->position[1]; + float cz = v->position[2]; int radius = RLSW.pointRadius; const float *color = v->color;