Load texture from glb

Add loading image from glb file.
This commit is contained in:
Piotr Krygier
2026-03-20 14:22:17 +01:00
parent 4c706982f1
commit ceb9e365de
9 changed files with 59 additions and 85 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

+24 -2
View File
@@ -21,6 +21,7 @@
#include "utilities/errors_common.h" #include "utilities/errors_common.h"
#include "utilities/file_utils.h" #include "utilities/file_utils.h"
#include "vulkan_buffers.h" #include "vulkan_buffers.h"
#include "vulkan_image.h"
rse_err_t mesh_create(struct graphics_context_t* context, rse_err_t mesh_create(struct graphics_context_t* context,
struct vertex_t* vertices, struct vertex_t* vertices,
@@ -49,7 +50,7 @@ rse_err_t mesh_create(struct graphics_context_t* context,
return status; return status;
} }
rse_err_t mesh_create_from_file(struct graphics_context_t* context, const char* file_name, rse_id_t* mesh_id) rse_err_t mesh_create_from_file(struct graphics_context_t* context, const char* file_name, rse_id_t* mesh_id, rse_id_t* texture_id)
{ {
struct vertex_t* vertices = NULL; struct vertex_t* vertices = NULL;
uint16_t* indices = NULL; uint16_t* indices = NULL;
@@ -63,7 +64,10 @@ rse_err_t mesh_create_from_file(struct graphics_context_t* context, const char*
size_t* position_data_offset = NULL; size_t* position_data_offset = NULL;
size_t* color_data_offset = NULL; size_t* color_data_offset = NULL;
size_t* texture_coord_data_offset = NULL; size_t* texture_coord_data_offset = NULL;
size_t* indices_data_offset = 0U; size_t* indices_data_offset = NULL;
size_t* texture_data_offset = NULL;
int* texture_data_size = NULL;
unsigned char *texture_pixel_buffer = NULL;
size_t data_count = 0U; size_t data_count = 0U;
size_t data_index = 0U; size_t data_index = 0U;
size_t tmp_offset = 0U; size_t tmp_offset = 0U;
@@ -94,6 +98,15 @@ rse_err_t mesh_create_from_file(struct graphics_context_t* context, const char*
rse_malloc(indices, (sizeof(uint16_t) * indices_count)); rse_malloc(indices, (sizeof(uint16_t) * indices_count));
} }
if (primitive->material != NULL) {
if (primitive->material->has_pbr_metallic_roughness) {
rse_malloc(texture_data_offset, sizeof(size_t));
rse_malloc(texture_data_size, sizeof(int));
*texture_data_offset = primitive->material->pbr_metallic_roughness.base_color_texture.texture->image->buffer_view->offset;
*texture_data_size = primitive->material->pbr_metallic_roughness.base_color_texture.texture->image->buffer_view->size;
}
}
for (attribute_index = 0; attribute_index < primitive->attributes_count; ++attribute_index) { for (attribute_index = 0; attribute_index < primitive->attributes_count; ++attribute_index) {
attribute = &primitive->attributes[attribute_index]; attribute = &primitive->attributes[attribute_index];
@@ -157,6 +170,12 @@ rse_err_t mesh_create_from_file(struct graphics_context_t* context, const char*
} }
} }
if (texture_data_offset != NULL) {
rse_malloc(texture_pixel_buffer, *texture_data_size);
rse_memcpy(texture_pixel_buffer, (bin + *texture_data_offset), *texture_data_size);
STATUS_CHECK(texture_load_from_buffer(context, texture_pixel_buffer, *texture_data_size, texture_id));
}
rse_memcpy(indices, (bin + *indices_data_offset), (sizeof(uint16_t) * indices_count)); rse_memcpy(indices, (bin + *indices_data_offset), (sizeof(uint16_t) * indices_count));
STATUS_CHECK(mesh_create(context, vertices, indices, data_count, indices_count, mesh_id)); STATUS_CHECK(mesh_create(context, vertices, indices, data_count, indices_count, mesh_id));
@@ -167,6 +186,9 @@ exit:
rse_free(color_data_offset); rse_free(color_data_offset);
rse_free(texture_coord_data_offset); rse_free(texture_coord_data_offset);
rse_free(indices_data_offset); rse_free(indices_data_offset);
rse_free(texture_data_size);
rse_free(texture_data_offset);
rse_free(texture_pixel_buffer);
rse_free(vertices); rse_free(vertices);
rse_free(indices); rse_free(indices);
cgltf_free(data); cgltf_free(data);
+1 -1
View File
@@ -41,7 +41,7 @@ rse_err_t mesh_create(struct graphics_context_t* context, struct vertex_t* verti
rse_err_t mesh_create_instance(struct graphics_context_t* context, entity_t entity, rse_err_t mesh_create_instance(struct graphics_context_t* context, entity_t entity,
struct instance_data_t instance_data); struct instance_data_t instance_data);
rse_err_t mesh_create_from_file(struct graphics_context_t* context, const char* file_name, rse_id_t* mesh_id); rse_err_t mesh_create_from_file(struct graphics_context_t* context, const char* file_name, rse_id_t* mesh_id, rse_id_t* texture_id);
/** /**
* @brief Get the vertex count for mesh with mesh_id ID * @brief Get the vertex count for mesh with mesh_id ID
* *
+1 -1
View File
@@ -29,7 +29,7 @@ rse_err_t shader_create_module(struct graphics_context_t* context,
const char* shader_path, const char* shader_path,
const VkShaderStageFlagBits shader_stage) const VkShaderStageFlagBits shader_stage)
{ {
char* buffer; unsigned char* buffer;
size_t buffer_size; size_t buffer_size;
VkShaderModuleCreateInfo create_info = {0}; VkShaderModuleCreateInfo create_info = {0};
+1 -2
View File
@@ -134,7 +134,6 @@ rse_err_t rse_graphics_test_function(struct graphics_context_t* context)
STATUS_CHECK(texture_load_from_file(context, "../../test_image.jpg", &textures[0])); STATUS_CHECK(texture_load_from_file(context, "../../test_image.jpg", &textures[0]));
STATUS_CHECK(texture_load_from_file(context, "../../test_image_2.jpg", &textures[1])); STATUS_CHECK(texture_load_from_file(context, "../../test_image_2.jpg", &textures[1]));
STATUS_CHECK(texture_load_from_file(context, "../../Avocado_baseColor.png", &textures[2]));
// STATUS_CHECK(fonts_init()); // STATUS_CHECK(fonts_init());
// STATUS_CHECK(fonts_load_from_file(context, "../../NotoSansMono-Regular.ttf", &font_id)); // STATUS_CHECK(fonts_load_from_file(context, "../../NotoSansMono-Regular.ttf", &font_id));
@@ -183,7 +182,7 @@ rse_err_t rse_graphics_test_function(struct graphics_context_t* context)
exit(1); exit(1);
} }
mesh_create_from_file(context, "../../Avocado.glb", &avocado_id); mesh_create_from_file(context, "../../Avocado.glb", &avocado_id, &textures[2]);
if (RSE_ERROR_NO_ERROR != if (RSE_ERROR_NO_ERROR !=
mesh_create_instance( mesh_create_instance(
context, context,
+29 -9
View File
@@ -16,6 +16,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"
#define IMAGE_TAKEN 1U #define IMAGE_TAKEN 1U
#define IMAGE_FREE 0U #define IMAGE_FREE 0U
@@ -515,20 +518,19 @@ rse_err_t load_texture_from_bitmat(struct graphics_context_t* context,
return status; return status;
} }
rse_err_t texture_load_from_file(struct graphics_context_t* context, const char* file_path, rse_id_t* texture_id) rse_err_t texture_load_from_buffer(struct graphics_context_t* context, const unsigned char* data_buffer, size_t buffer_size, rse_id_t* texture_id)
{ {
rse_err_t status = RSE_ERROR_NO_ERROR;
int width = 0; int width = 0;
int height = 0; int height = 0;
size_t buffer_size = 0U; int channels = 0;
unsigned char* pixel_buffer = NULL; unsigned char* pixel_buffer = NULL;
rse_err_t status = RSE_ERROR_NO_ERROR;
STATUS_CHECK(file_load_pixels(file_path, NULL, &buffer_size, &width, &height)); pixel_buffer = stbi_load_from_memory(data_buffer, (int)buffer_size, &width, &height, &channels, STBI_rgb_alpha);
rse_malloc(pixel_buffer, buffer_size); if (pixel_buffer == NULL) {
if (file_load_pixels(file_path, pixel_buffer, &buffer_size, &width, &height) != RSE_ERROR_NO_ERROR) { SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failed to load image");
status = RSE_ERROR_INTERNAL_ERROR;
goto mem_free; return RSE_ERROR_INTERNAL_ERROR;
} }
if (load_texture_from_bitmat(context, pixel_buffer, width, height, texture_id, VK_FORMAT_R8G8B8A8_SRGB) != RSE_ERROR_NO_ERROR) { if (load_texture_from_bitmat(context, pixel_buffer, width, height, texture_id, VK_FORMAT_R8G8B8A8_SRGB) != RSE_ERROR_NO_ERROR) {
@@ -538,8 +540,26 @@ rse_err_t texture_load_from_file(struct graphics_context_t* context, const char*
} }
mem_free: mem_free:
stbi_image_free(pixel_buffer);
rse_free(pixel_buffer); return status;
}
rse_err_t texture_load_from_file(struct graphics_context_t* context, const char* file_path, rse_id_t* texture_id)
{
size_t buffer_size = 0U;
unsigned char* data_buffer = NULL;
rse_err_t status = RSE_ERROR_NO_ERROR;
STATUS_CHECK(file_read_bytes(file_path, &buffer_size, NULL));
rse_malloc(data_buffer, buffer_size);
STATUS_CHECK(file_read_bytes(file_path, &buffer_size, data_buffer));
if (texture_load_from_buffer(context, data_buffer, buffer_size, texture_id) != RSE_ERROR_NO_ERROR) {
status = RSE_ERROR_INTERNAL_ERROR;
}
rse_free(data_buffer);
return status; return status;
} }
+1
View File
@@ -42,6 +42,7 @@ rse_err_t image_get_extent(struct graphics_context_t* context, VkExtent2D* exten
rse_err_t load_texture_from_bitmat(struct graphics_context_t* context, const unsigned char* pixel_buffer, int width, rse_err_t load_texture_from_bitmat(struct graphics_context_t* context, const unsigned char* pixel_buffer, int width,
int height, rse_id_t* texture_id, VkFormat color_format); int height, rse_id_t* texture_id, VkFormat color_format);
rse_err_t texture_load_from_buffer(struct graphics_context_t* context, const unsigned char* data_buffer, size_t buffer_size, rse_id_t* texture_id);
/** /**
* @brief Loads image from file, for later to be used as a texture * @brief Loads image from file, for later to be used as a texture
* *
+1 -3
View File
@@ -15,12 +15,10 @@
* @param bytes_count Returned bytes count * @param bytes_count Returned bytes count
* @param buffer Returned filled buffer * @param buffer Returned filled buffer
*/ */
rse_err_t file_read_bytes(const char* file_path, size_t* bytes_count, char* buffer); rse_err_t file_read_bytes(const char* file_path, size_t* bytes_count, unsigned char* buffer);
rse_err_t file_write(const char* file_name, size_t bytes_count, char* buffer); rse_err_t file_write(const char* file_name, size_t bytes_count, char* buffer);
rse_err_t file_load_pixels(const char* file_name, unsigned char* buffer, size_t* buffer_size, int* width, int* height);
rse_err_t file_append_full_path(char* file_path, size_t max_buffer_size); rse_err_t file_append_full_path(char* file_path, size_t max_buffer_size);
rse_err_t file_load_gltf(const char* file_name, cgltf_data** data); rse_err_t file_load_gltf(const char* file_name, cgltf_data** data);
+1 -67
View File
@@ -14,9 +14,6 @@
#include "commons.h" #include "commons.h"
#include "errors_common.h" #include "errors_common.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"
#ifdef __linux__ #ifdef __linux__
#include <limits.h> #include <limits.h>
#include <unistd.h> #include <unistd.h>
@@ -119,70 +116,7 @@ rse_err_t file_append_full_path(char* file_path, size_t max_buffer_size)
return ret; return ret;
} }
rse_err_t file_load_pixels(const char* file_name, unsigned char* buffer, size_t* buffer_size, int* width, int* height) rse_err_t file_read_bytes(const char* file_name, size_t* bytes_count, unsigned char* buffer)
{
int channels = 0;
stbi_uc* pixel_buffer = NULL;
size_t image_buffer_size = 0U;
rse_err_t ret = RSE_ERROR_NO_ERROR;
char real_path[MAX_PATH_LENGTH] = {0};
if (buffer_size == NULL) {
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Provided NULL buffer_size");
return RSE_ERROR_INVALID_PARAM;
}
if (width == NULL) {
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Provided NULL width");
return RSE_ERROR_INVALID_PARAM;
}
if (height == NULL) {
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Provided NULL height");
return RSE_ERROR_INVALID_PARAM;
}
strncpy(real_path, file_name, MAX_PATH_LENGTH);
if ((ret = file_append_full_path(real_path, MAX_PATH_LENGTH)) != RSE_ERROR_NO_ERROR) {
return ret;
}
pixel_buffer = stbi_load(real_path, width, height, &channels, STBI_rgb_alpha);
if (pixel_buffer == NULL) {
SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failed to load texture from file: %s", file_name);
return RSE_ERROR_INTERNAL_ERROR;
}
image_buffer_size = *width * *height * 4; // TODO: "4" is very hardcoded value. Change this
if ((buffer != NULL) && (image_buffer_size > *buffer_size)) {
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION,
"Provided buffer is to small to hold pixel data. %ld vs %ld",
*buffer_size,
image_buffer_size);
ret = RSE_ERROR_INTERNAL_ERROR;
goto image_free;
}
*buffer_size = image_buffer_size;
if (buffer != NULL) {
memset(buffer, 0, *buffer_size);
memcpy(buffer, pixel_buffer, *buffer_size);
}
image_free:
stbi_image_free(pixel_buffer);
return ret;
}
rse_err_t file_read_bytes(const char* file_name, size_t* bytes_count, char* buffer)
{ {
rse_err_t ret = RSE_ERROR_NO_ERROR; rse_err_t ret = RSE_ERROR_NO_ERROR;
FILE* file = NULL; FILE* file = NULL;