/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "IBL.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace filament; using namespace image; using namespace math; using namespace utils; static constexpr float IBL_INTENSITY = 30000.0f; IBL::IBL(Engine& engine) : mEngine(engine) { } IBL::~IBL() { mEngine.destroy(mIndirectLight); mEngine.destroy(mTexture); mEngine.destroy(mSkybox); mEngine.destroy(mSkyboxTexture); } bool IBL::loadFromKtx(const std::string& prefix) { Path iblPath(prefix + "_ibl.ktx"); Path skyPath(prefix + "_skybox.ktx"); if (!iblPath.exists() || !skyPath.exists()) { return false; } auto createKtx = [] (Path path) { using namespace std; ifstream file(path.getPath(), ios::binary); vector contents((istreambuf_iterator(file)), {}); return new image::KtxBundle(contents.data(), contents.size()); }; KtxBundle* iblKtx = createKtx(iblPath); KtxBundle* skyKtx = createKtx(skyPath); mSkyboxTexture = KtxUtility::createTexture(&mEngine, skyKtx, false, true); mTexture = KtxUtility::createTexture(&mEngine, iblKtx, false, true); std::istringstream shstring(iblKtx->getMetadata("sh")); for (float3& band : mBands) { shstring >> band.x >> band.y >> band.z; } mIndirectLight = IndirectLight::Builder() .reflections(mTexture) .irradiance(3, mBands) .intensity(IBL_INTENSITY) .build(mEngine); mSkybox = Skybox::Builder().environment(mSkyboxTexture).showSun(true).build(mEngine); return true; } bool IBL::loadFromDirectory(const utils::Path& path) { // First check if KTX files are available. if (loadFromKtx(Path::concat(path, path.getName()))) { return true; } // Read spherical harmonics Path sh(Path::concat(path, "sh.txt")); if (sh.exists()) { std::ifstream shReader(sh); shReader >> std::skipws; std::string line; for (float3& band : mBands) { std::getline(shReader, line); int n = sscanf(line.c_str(), "(%f,%f,%f)", &band.r, &band.g, &band.b); // NOLINT(cert-err34-c) if (n != 3) return false; } } else { return false; } // Read mip-mapped cubemap const std::string prefix = "m"; if (!loadCubemapLevel(&mTexture, path, 0, prefix + "0_")) return false; size_t numLevels = mTexture->getLevels(); for (size_t i = 1; i(buffer.buffer); for (size_t j = 0; j < 6; j++) { offsets[j] = faceSize * j; std::string faceName = levelPrefix + faceSuffix[j] + ".rgbm"; Path facePath(Path::concat(path, faceName)); if (!facePath.exists()) { std::cerr << "The face " << faceName << " does not exist" << std::endl; success = false; break; } int w, h, n; unsigned char* data = stbi_load(facePath.getAbsolutePath().c_str(), &w, &h, &n, 4); if (w != h || w != size) { std::cerr << "Face " << faceName << "has a wrong size " << w << " x " << h << ", instead of " << size << " x " << size << std::endl; success = false; break; } if (data == nullptr || n != 4) { std::cerr << "Could not decode face " << faceName << std::endl; success = false; break; } memcpy(p + offsets[j], data, size_t(w * h * 4)); stbi_image_free(data); } if (!success) return false; (*texture)->setImage(mEngine, level, std::move(buffer), offsets); return true; }