Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rmodels] Loading GLB/GLTF fails to parse or render when running on a Big Endian system #4647

Open
nbe1233 opened this issue Dec 28, 2024 · 7 comments
Labels
enhancement This is an improvement of some feature external This issue depends on external lib

Comments

@nbe1233
Copy link

nbe1233 commented Dec 28, 2024

Please, before submitting a new issue verify and check:

  • [ x] I tested it on latest raylib version from master branch
  • [ x] I checked there is no similar issue already reported
  • [ x] I checked the documentation on the wiki
  • [ x] My code has no errors or misuse of raylib

Issue description

glb files fails to load as cgltf.h uses endian-specific code.
gltf files are successfully parsed, but mesh vertices, normals, and indices are incorrectly loaded by rmodels.c

Environment

I've been working on a homebrew PS3 port using the PSL1GHT SDK, using RSXGL which implements Opengl 3.1 core.

Code Example

Here cgltf.h copys bytes from glb data, which is stored as little-endian, but since the system is big-endian it stores GlbMagic as big-endian while interpreting glb bytes as a big-endian number, causing a mismatch.

//cgltf.h
static const uint32_t GlbMagic = 0x46546C67;
...
cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_size size, cgltf_data** out_data)
{
...
        uint32_t tmp;
        // Magic
        memcpy(&tmp, data, 4);
        if (tmp != GlbMagic) {...}
...
}

After fixing cgltf.h with a bunch of __builtin_bswap32(), I could now load glb which behaved the same as gltf files, that is to say still broken. I found that in order for the model to be rendered correctly, I had to swap the bytes of Mesh positions, normals, and indices. I believe the errors comes from the LOAD_ATTRIBUTE_CAST macro function in LoadGLTF.

static Model LoadGLTF(const char *fileName)
{
...
//rmodels.c line 5234
    #define LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, dstType) \
    { \
        int n = 0; \
        srcType *buffer = (srcType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(srcType) + accesor->offset/sizeof(srcType); \
        for (unsigned int k = 0; k < accesor->count; k++) \
        {\
            for (int l = 0; l < numComp; l++) \
            {\
                dstPtr[numComp*k + l] = (dstType)buffer[n + l];\
            }\
            n += (int)(accesor->stride/sizeof(srcType));\
        }\
    }
...
}

I've managed to get glb/gltf files to render correctly by passing __builtin_bswap32(), perhaps using le32toh() would be better, though my toolchain lack said function.

@raysan5 raysan5 added enhancement This is an improvement of some feature external This issue depends on external lib labels Dec 29, 2024
@raysan5
Copy link
Owner

raysan5 commented Dec 29, 2024

@nbe1233 raylib was not designed considering Big Endian systems so it could fail in multiple points in that regards... Still, lately some changes by @Peter0x44 where merged to add some BE support.

The reported issue also involves an external library, it should probably reported to https://github.com/jkuhlmann/cgltf

What additional changes are needed to support BE on raylib for gltf loading?

@Peter0x44
Copy link
Contributor

I didn't make any changes for that, but parts of the gltf loading code look rather suspicious, and probably assume LE byte order. Everything in a glb is LE.

@Peter0x44
Copy link
Contributor

image
there was a previous discussion about a ps3 port in discord here
I'm not sure if that is simply a BE quirk or the ps3 itself has something to do with it.

Testing powerpc linux with qemu might also help, but I am yet to set that up.

@Memorix101
Copy link

Memorix101 commented Dec 29, 2024

Currently, we look into Wii/GameCube on the raylib Discord together, which is BE too. Does the PS3 give you the same results, similar to that, when you load a GLTF/GLB file?
image
Video: https://github.com/user-attachments/assets/7308d660-5246-499c-b7c4-f8bd0aab5a70

How it should look like:
image

@nbe1233
Copy link
Author

nbe1233 commented Dec 29, 2024

Yeah I had the same issue. I solved it by replacing LOAD_ATTRIBUTE_CAST() in rmodels.c with this


    #define LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, dstType) \
    { \
        int n = 0; \
        srcType *buffer = (srcType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(srcType) + accesor->offset/sizeof(srcType); \
        char *dst_type_str = #dstType; \
        bool is_dst_float = false;\
        bool is_dst_ushort = false;\
        if (strcmp(dst_type_str, "float") == 0 ) {is_dst_float = true;} \
        if (strcmp(dst_type_str, "unsigned short") == 0 ) {is_dst_ushort = true;} \
        for (unsigned int k = 0; k < accesor->count; k++) \
        {\
            for (int l = 0; l < numComp; l++) \
            {\
                dstPtr[numComp*k + l] = (dstType)buffer[n + l];\
                if (is_dst_float)\
                {\
                    union { uint32_t u; float f ;} x ;\
                    x.f = dstPtr[numComp*k + l];\
                    x.u = __builtin_bswap32(x.u);\
                    dstPtr[numComp*k + l] = x.f;\
                }\
                if (is_dst_ushort)\
                {\
                    dstPtr[numComp*k + l] = __builtin_bswap16(dstPtr[numComp*k + l]);\
                }\
            }\
            n += (int)(accesor->stride/sizeof(srcType));\
        }\
    }

@nbe1233
Copy link
Author

nbe1233 commented Dec 29, 2024

These are the commits I used to get gltf rendering working
4efa33c
e254c1e

@raysan5
Copy link
Owner

raysan5 commented Jan 1, 2025

Supporting BE could require many changes to raylib and also external libraries... Have you tried with multiple texture formats or other file-formats?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement This is an improvement of some feature external This issue depends on external lib
Projects
None yet
Development

No branches or pull requests

4 participants