jkuhlmann / cgltf

:diamond_shape_with_a_dot_inside: Single-file glTF 2.0 loader and writer written in C99
MIT License
1.44k stars 136 forks source link

The reference information regarding the use of cgltf_load_buffer_base64 is unclear #194

Open b1skit opened 1 year ago

b1skit commented 1 year ago

The "Reference" section at the head of cgltf.h states:

 * `cgltf_result cgltf_load_buffer_base64(const cgltf_options* options,
 * cgltf_size size, const char* base64, void** out_data)` decodes
 * base64-encoded data content. Used internally by `cgltf_load_buffers()`.
 * This is useful when decoding data URIs in images.

This information is incomplete, and doesn't fully explain the usage of this function. Calling this function requires computation of some parameter values that are not immediately obvious to the user.

Google's filament parseDataUri function demonstrates successful usage of this function to load base64 texture data embedded in a URI:

 // Parses a data URI and returns a blob that gets malloc'd in cgltf, which the caller must free.  
// (implementation snarfed from meshoptimizer)  
static const uint8_t* parseDataUri(const char* uri, std::string* mimeType, size_t* psize) {  
    if (strncmp(uri, "data:", 5) != 0) {  
        return nullptr;  
    }  
    const char* comma = strchr(uri, ',');  
    if (comma && comma - uri >= 7 && strncmp(comma - 7, ";base64", 7) == 0) {
        const char* base64 = comma + 1;
        const size_t base64Size = strlen(base64);
        size_t size = base64Size - base64Size / 4;
        if (base64Size >= 2) {
            size -= base64[base64Size - 2] == '=';
            size -= base64[base64Size - 1] == '=';
        }
        void* data = 0;
        cgltf_options options = {};
        cgltf_result result = cgltf_load_buffer_base64(&options, size, base64, &data);
        if (result != cgltf_result_success) {
            return nullptr;
        }
        *mimeType = std::string(uri + 5, comma - 7);
        *psize = size;
        return (const uint8_t*) data;
    }
    return nullptr;
}

For reference, their implementation of parseDataUri can be found here (line 285): https://github.com/google/filament/blob/676694e4589dca55c1cdbbb669cf3dba0e2b576f/libs/gltfio/src/ResourceLoader.cpp

Notice how calling cgltf_load_buffer_base64 requires

This operations may be straightforward to users with knowledge of base64 encoding, but for others (such as myself) it's difficult to use.

As a solution, I'd recommend a combination of the following:

I'd offer to do this myself, but unfortunately I'm not familiar with base64 and only figured out how to use this feature by cribbing from the filament example above.