diff --git a/libs/filamentapp/CMakeLists.txt b/libs/filamentapp/CMakeLists.txt index 2e0e95b7da..4a8a6c4caf 100644 --- a/libs/filamentapp/CMakeLists.txt +++ b/libs/filamentapp/CMakeLists.txt @@ -47,6 +47,7 @@ set(LIBS geometry getopt image + imageio imgui ktxreader math diff --git a/libs/filamentapp/include/filamentapp/IBL.h b/libs/filamentapp/include/filamentapp/IBL.h index 6468f331e5..e151f9c484 100644 --- a/libs/filamentapp/include/filamentapp/IBL.h +++ b/libs/filamentapp/include/filamentapp/IBL.h @@ -22,6 +22,7 @@ #include #include +#include namespace filament { class Engine; diff --git a/libs/filamentapp/src/IBL.cpp b/libs/filamentapp/src/IBL.cpp index d2d546e153..7d4b97b0c1 100644 --- a/libs/filamentapp/src/IBL.cpp +++ b/libs/filamentapp/src/IBL.cpp @@ -25,6 +25,8 @@ #include +#include + #include #include @@ -37,6 +39,8 @@ #include +#include + using namespace filament; using namespace filament::math; using namespace ktxreader; @@ -60,26 +64,51 @@ bool IBL::loadFromEquirect(Path const& path) { return false; } - int w, h; - stbi_info(path.getAbsolutePath().c_str(), &w, &h, nullptr); - if (w != h * 2) { - std::cerr << "not an equirectangular image!" << std::endl; + int w = 0, h = 0; + int n = 0; + size_t size = 0; + void* data = nullptr; + void* user = nullptr; + Texture::PixelBufferDescriptor::Callback destroyer{}; + + if (path.getExtension() == "exr") { + std::ifstream in_stream(path.getAbsolutePath().c_str(), std::ios::binary); + image::LinearImage* image = new image::LinearImage( + image::ImageDecoder::decode(in_stream, path.getAbsolutePath().c_str())); + w = image->getWidth(); + h = image->getHeight(); + n = image->getChannels(); + size = w * h * n * sizeof(float); + data = image->getPixelRef(); + user = image; + destroyer = [](void*, size_t, void* user) { + delete reinterpret_cast(user); + }; + } else { + stbi_info(path.getAbsolutePath().c_str(), &w, &h, nullptr); + // load image as float + size = w * h * sizeof(float3); + data = (float3*)stbi_loadf(path.getAbsolutePath().c_str(), &w, &h, &n, 3); + destroyer = [](void* data, size_t, void*) { + stbi_image_free(data); + }; + } + + if (data == nullptr || n != 3) { + std::cerr << "Could not decode image " << std::endl; + destroyer(data, size, user); return false; } - // load image as float - int n; - const size_t size = w * h * sizeof(float3); - float3* const data = (float3*)stbi_loadf(path.getAbsolutePath().c_str(), &w, &h, &n, 3); - if (data == nullptr || n != 3) { - std::cerr << "Could not decode image " << std::endl; + if (w != h * 2) { + std::cerr << "not an equirectangular image!" << std::endl; + destroyer(data, size, user); return false; } // now load texture Texture::PixelBufferDescriptor buffer( - data, size,Texture::Format::RGB, Texture::Type::FLOAT, - [](void* buffer, size_t size, void* user) { stbi_image_free(buffer); }); + data, size,Texture::Format::RGB, Texture::Type::FLOAT, destroyer, user); Texture* const equirect = Texture::Builder() .width((uint32_t)w) @@ -102,7 +131,7 @@ bool IBL::loadFromEquirect(Path const& path) { mTexture = specularFilter(mSkyboxTexture); - mFogTexture = irradianceFilter({ .generateMipmap=false }, mSkyboxTexture); + mFogTexture = irradianceFilter({ .generateMipmap = false }, mSkyboxTexture); mFogTexture->generateMipmaps(mEngine); mIndirectLight = IndirectLight::Builder() diff --git a/samples/gltf_viewer.cpp b/samples/gltf_viewer.cpp index ee5e136226..77aee4743f 100644 --- a/samples/gltf_viewer.cpp +++ b/samples/gltf_viewer.cpp @@ -515,7 +515,9 @@ static void onClick(App& app, View* view, ImVec2 pos) { static utils::Path getPathForIBLAsset(std::string_view string) { auto isIBL = [] (utils::Path file) -> bool { - return file.getExtension() == "ktx" || file.getExtension() == "hdr"; + return file.getExtension() == "ktx" || file.getExtension() == "hdr" || + file.getExtension() == "exr"; + }; utils::Path filename{ string };