From a309ecedc28b0139b1e3fb1b4ea216cfd08fe160 Mon Sep 17 00:00:00 2001 From: msmith-codes Date: Sun, 21 Dec 2025 15:18:25 -0500 Subject: [PATCH] Possibly fixed the swizzling bug --- examples/textures/generate_test_dds.py | 125 ++++++++++++++++++ .../textures/resources/test_rgba_mipmaps.dds | Bin 0 -> 349652 bytes examples/textures/textures_test_dds_mipmaps.c | 66 +++++++++ src/external/rl_gputex.h | 2 +- 4 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 examples/textures/generate_test_dds.py create mode 100644 examples/textures/resources/test_rgba_mipmaps.dds create mode 100644 examples/textures/textures_test_dds_mipmaps.c diff --git a/examples/textures/generate_test_dds.py b/examples/textures/generate_test_dds.py new file mode 100644 index 000000000..426b3c679 --- /dev/null +++ b/examples/textures/generate_test_dds.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 +"""Generate a test DDS file with mipmaps to verify swizzling fix""" + +import struct +import os + +def write_dword(f, value): + """Write a 32-bit unsigned integer (little-endian)""" + f.write(struct.pack(' 1 or mip_h > 1: + mip_w = max(1, mip_w // 2) + mip_h = max(1, mip_h // 2) + mipmap_count += 1 + + print(f"Generating DDS: {width}x{height} with {mipmap_count} mipmaps") + + with open(filename, 'wb') as f: + # Write DDS magic number + f.write(b'DDS ') + + # Write DDS header (124 bytes) + write_dword(f, 124) # dwSize + write_dword(f, 0x1 | 0x2 | 0x4 | 0x1000 | 0x20000) # dwFlags (CAPS, HEIGHT, WIDTH, PIXELFORMAT, MIPMAPCOUNT) + write_dword(f, height) # dwHeight + write_dword(f, width) # dwWidth + write_dword(f, width * 4) # dwPitchOrLinearSize + write_dword(f, 0) # dwDepth + write_dword(f, mipmap_count) # dwMipMapCount + + # Reserved1[11] + for _ in range(11): + write_dword(f, 0) + + # DDS_PIXELFORMAT (32 bytes) + write_dword(f, 32) # dwSize + write_dword(f, 0x41) # dwFlags (RGBA) + write_dword(f, 0) # dwFourCC + write_dword(f, 32) # dwRGBBitCount + write_dword(f, 0x00FF0000) # dwRBitMask (R at byte 2) + write_dword(f, 0x0000FF00) # dwGBitMask (G at byte 1) + write_dword(f, 0x000000FF) # dwBBitMask (B at byte 0) + write_dword(f, 0xFF000000) # dwABitMask (A at byte 3) + + # dwCaps + write_dword(f, 0x1000 | 0x8 | 0x400000) # TEXTURE | COMPLEX | MIPMAP + write_dword(f, 0) # dwCaps2 + write_dword(f, 0) # dwCaps3 + write_dword(f, 0) # dwCaps4 + write_dword(f, 0) # dwReserved2 + + # Write image data with mipmaps + mip_w, mip_h = width, height + mip_data = generate_bgra_image(width, height) + + for mip in range(mipmap_count): + print(f" Mipmap {mip}: {mip_w}x{mip_h} ({len(mip_data)} bytes)") + f.write(mip_data) + + if mip < mipmap_count - 1: + mip_data = generate_mipmap(mip_data, mip_w, mip_h) + mip_w = max(1, mip_w // 2) + mip_h = max(1, mip_h // 2) + + print(f"✓ Created {filename}") + +if __name__ == "__main__": + # Create resources directory if it doesn't exist + os.makedirs("resources", exist_ok=True) + + # Generate test DDS file + write_dds_file("resources/test_rgba_mipmaps.dds", 256, 256) + + print("\nTest file created!") + print("Left half should be RED, right half should be BLUE") + print("If the fix is working, all mipmap levels will show correct colors") diff --git a/examples/textures/resources/test_rgba_mipmaps.dds b/examples/textures/resources/test_rgba_mipmaps.dds new file mode 100644 index 0000000000000000000000000000000000000000..6543189818103583995010c2ecaff819d94a4080 GIT binary patch literal 349652 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 literal 0 HcmV?d00001 diff --git a/examples/textures/textures_test_dds_mipmaps.c b/examples/textures/textures_test_dds_mipmaps.c new file mode 100644 index 000000000..63a00db2e --- /dev/null +++ b/examples/textures/textures_test_dds_mipmaps.c @@ -0,0 +1,66 @@ +/******************************************************************************************* +* +* raylib [textures] example - Test DDS loading with mipmaps +* +********************************************************************************************/ + +#include "raylib.h" + +int main(void) +{ + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [textures] - DDS mipmaps test"); + + // Load DDS texture with mipmaps (create one with a distinct color pattern) + Texture2D texture = LoadTexture("resources/test_rgba_mipmaps.dds"); + + if (texture.id == 0) + { + TraceLog(LOG_ERROR, "Failed to load DDS texture"); + } + else + { + TraceLog(LOG_INFO, "DDS texture loaded: %dx%d, mipmaps: %d", + texture.width, texture.height, texture.mipmaps); + } + + SetTargetFPS(60); + + while (!WindowShouldClose()) + { + BeginDrawing(); + ClearBackground(RAYWHITE); + + // Draw texture at different scales to see mipmap levels + DrawTexturePro(texture, + (Rectangle){0, 0, texture.width, texture.height}, + (Rectangle){50, 50, 256, 256}, + (Vector2){0, 0}, 0.0f, WHITE); + + DrawTexturePro(texture, + (Rectangle){0, 0, texture.width, texture.height}, + (Rectangle){350, 50, 128, 128}, + (Vector2){0, 0}, 0.0f, WHITE); + + DrawTexturePro(texture, + (Rectangle){0, 0, texture.width, texture.height}, + (Rectangle){520, 50, 64, 64}, + (Vector2){0, 0}, 0.0f, WHITE); + + DrawText("256x256", 50, 320, 20, DARKGRAY); + DrawText("128x128", 350, 190, 20, DARKGRAY); + DrawText("64x64", 520, 125, 20, DARKGRAY); + + DrawText("If colors look wrong (blue/red swapped), mipmaps have swizzling bug", + 10, 400, 10, RED); + + EndDrawing(); + } + + UnloadTexture(texture); + CloseWindow(); + + return 0; +} \ No newline at end of file diff --git a/src/external/rl_gputex.h b/src/external/rl_gputex.h index 29500f3cf..84ab33eba 100644 --- a/src/external/rl_gputex.h +++ b/src/external/rl_gputex.h @@ -362,7 +362,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ // NOTE: Data comes as A8R8G8B8, it must be reordered R8G8B8A8 (view next comment) // DirecX understand ARGB as a 32bit DWORD but the actual memory byte alignment is BGRA // So, we must realign B8G8R8A8 to R8G8B8A8 - for (int i = 0; i < image_pixel_size*4; i += 4) + for (int i = 0; i < data_size; i += 4) { blue = ((unsigned char *)image_data)[i]; ((unsigned char *)image_data)[i] = ((unsigned char *)image_data)[i + 2];