diff --git a/src/backstage/image.cpp b/src/backstage/image.cpp index ebb0a19..b15925a 100644 --- a/src/backstage/image.cpp +++ b/src/backstage/image.cpp @@ -77,6 +77,63 @@ Image::Image(std::string filename, bool is_hdr) : m_is_hdr(is_hdr) { } } +Image::Image(uint8_t* blob, size_t size, bool is_hdr) { + m_is_hdr = is_hdr; + uint8_t* image = nullptr; + size_t image_size = 0; + + // Try stbi first, assuming the image is not EXR + stbi_set_flip_vertically_on_load(true); + if (is_hdr) + image = (uint8_t*)stbi_loadf_from_memory(blob, size, &m_width, &m_height, &m_channels, 4); + else + image = stbi_load_from_memory(blob, size, &m_width, &m_height, &m_channels, 4); + m_channels = 4; + image_size = (is_hdr ? sizeof(float) : sizeof(uint8_t)) * m_width * m_height * m_channels; + + // If the blob failed to load with stbi, try tinyexr + if (image == nullptr) { + const char* err = nullptr; + float* image_float; + int ret = LoadEXRFromMemory(&image_float, &m_width, &m_height, blob, size, &err); + if (ret != TINYEXR_SUCCESS) { + ERR("Unable to load image blob"); + if (err) { + ERR(err); + FreeEXRErrorMessage(err); + } + return; + } + + // Flip y axis + tbb::parallel_for(tbb::blocked_range(0, m_height/2), [&](const auto& r) { + for (uint32_t row = r.begin(); row != r.end(); row++) { + tbb::parallel_for(tbb::blocked_range(0, m_width * m_channels), [&](const auto& rr) { + for (uint32_t el = rr.begin(); el != rr.end(); el++) { + uint32_t id_a = row * m_width * m_channels + el; + uint32_t id_b = (m_height - row - 1) * m_width * m_channels + el; + std::swap(image_float[id_a], image_float[id_b]); + } + }); + } + }); + + m_is_hdr = true; + image = (uint8_t*)image_float; + image_size = sizeof(float) * m_width * m_height * m_channels; + } + + + if (image == nullptr) { + ERR("Unable to load image blob"); + return; + } + + m_image = (uint8_t*)std::malloc(image_size); + std::memcpy(m_image, image, image_size); + std::free(image); +} + Image::Image(stage_vec3f color) { m_image = (uint8_t*)std::malloc(sizeof(uint8_t) * 4); m_image[0] = color.x * 255; diff --git a/src/backstage/image.h b/src/backstage/image.h index 0d5d38b..b77bae8 100644 --- a/src/backstage/image.h +++ b/src/backstage/image.h @@ -11,6 +11,7 @@ struct Image { public: Image(std::string filename, bool is_hdr = false); + Image(uint8_t* blob, size_t size, bool is_hdr = false); Image(stage_vec3f color); Image(Image& other) = delete; Image(Image&& other); @@ -40,7 +41,6 @@ struct Image { int32_t m_channels; bool m_is_hdr { false }; - }; } diff --git a/src/backstage/scene.cpp b/src/backstage/scene.cpp index 24c915d..420310c 100644 --- a/src/backstage/scene.cpp +++ b/src/backstage/scene.cpp @@ -995,23 +995,15 @@ void FBXScene::loadFBX(std::string scene) { // Load textures if (fbx_material->pbr.base_color.texture_enabled) { - std::string filename(fbx_material->pbr.base_color.texture->absolute_filename.data); - Image texture(filename); - if (texture.isValid()) { - m_textures.push_back(std::move(texture)); + if (loadFBXTexture(fbx_material->pbr.base_color.texture)) { material.base_color_texid = m_textures.size() - 1; } - LOG("Read texture image '" + filename + "'"); } if (fbx_material->pbr.opacity.texture_enabled) { - std::string filename(fbx_material->pbr.opacity.texture->absolute_filename.data); - Image texture(filename); - if (texture.isValid()) { - m_textures.push_back(std::move(texture)); + if (loadFBXTexture(fbx_material->pbr.opacity.texture)) { material.geometry_opacity_texid = m_textures.size() - 1; } - LOG("Read opacity image '" + filename + "'"); } m_materials.push_back(material); @@ -1050,17 +1042,14 @@ void FBXScene::loadFBX(std::string scene) { ufbx_vec3 position = ufbx_get_vertex_vec3(&fbx_mesh->vertex_position, index); ufbx_vec3 normal = ufbx_get_vertex_vec3(&fbx_mesh->vertex_normal, index); - ufbx_vec2 uv = fbx_mesh->vertex_uv.exists ? ufbx_get_vertex_vec2(&fbx_mesh->vertex_uv, index) : ufbx_vec2{0, 0}; + ufbx_vec2 uv = fbx_mesh->vertex_uv.exists ? ufbx_get_vertex_vec2(&fbx_mesh->vertex_uv, index) : ufbx_vec2({0, 0}); AligendVertex vertex; - // vertex.position = make_vec3(&position.x); vertex.position.x = position.x; vertex.position.y = position.y; vertex.position.z = position.z; - // vertex.normal = make_vec3(&normal.x); vertex.normal.x = normal.x; vertex.normal.y = normal.y; vertex.normal.z = normal.z; - // vertex.uv = make_vec2(&uv.x); vertex.uv.x = uv.x; vertex.uv.y = uv.y; @@ -1110,5 +1099,28 @@ void FBXScene::loadFBX(std::string scene) { ufbx_free_scene(fbx_scene); } + +bool +FBXScene::loadFBXTexture(ufbx_texture *texture) +{ + std::unique_ptr image; + if (texture->content.size > 0) + { + image = std::make_unique((uint8_t*)texture->content.data, texture->content.size); + if (image->isValid()) LOG("Read texture image blob"); + } + else + { + std::filesystem::path filepath = getAbsolutePath(texture->relative_filename.data); + image = std::make_unique(filepath.string()); + if (image->isValid()) LOG("Read texture image '" + filename + "'"); + } + if (image->isValid()) + { + m_textures.push_back(std::move(*image)); + return true; + } + return false; +} } } \ No newline at end of file diff --git a/src/backstage/scene.h b/src/backstage/scene.h index 0ed8a4f..3a139ec 100644 --- a/src/backstage/scene.h +++ b/src/backstage/scene.h @@ -37,6 +37,8 @@ namespace pbrt { struct Spectrum; } +struct ufbx_texture; + namespace stage { namespace backstage { @@ -144,6 +146,7 @@ struct FBXScene : public Scene { private: void loadFBX(std::string scene); + bool loadFBXTexture(ufbx_texture* texture); }; std::unique_ptr createScene(std::string scene);